forked from fecgov/fec-cms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tasks.py
132 lines (105 loc) · 3.59 KB
/
tasks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import os
import json
import git
from invoke import run
from invoke import task
from slacker import Slacker
import cfenv
env = cfenv.AppEnv()
@task
def add_hooks():
run('ln -s ../../bin/post-merge .git/hooks/post-merge')
run('ln -s ../../bin/post-checkout .git/hooks/post-checkout')
@task
def remove_hooks():
run('rm .git/hooks/post-merge')
run('rm .git/hooks/post-checkout')
def _detect_prod(repo, branch):
"""Deploy to production if master is checked out and tagged."""
if branch != 'master':
return False
try:
# Equivalent to `git describe --tags --exact-match`
repo.git().describe('--tags', '--exact-match')
return True
except git.exc.GitCommandError:
return False
def _resolve_rule(repo, branch):
"""Get space associated with first matching rule."""
for space, rule in DEPLOY_RULES:
if rule(repo, branch):
return space
return None
def _detect_branch(repo):
try:
return repo.active_branch.name
except TypeError:
return None
def _detect_space(repo, branch=None, yes=False):
"""Detect space from active git branch.
:param str branch: Optional branch name override
:param bool yes: Skip confirmation
:returns: Space name if space is detected and confirmed, else `None`
"""
space = _resolve_rule(repo, branch)
if space is None:
print('No space detected')
return None
print('Detected space {space}'.format(**locals()))
if not yes:
run = input(
'Deploy to space {space} (enter "yes" to deploy)? > '.format(**locals())
)
if run.lower() not in ['y', 'yes']:
return None
return space
DEPLOY_RULES = (
('prod', _detect_prod),
('stage', lambda _, branch: branch.startswith('release')),
('dev', lambda _, branch: branch == 'develop'),
)
@task
def deploy(space=None, branch=None, yes=False):
"""Deploy app to Cloud Foundry. Log in using credentials stored in
`FEC_CF_USERNAME` and `FEC_CF_PASSWORD`; push to either `space` or the space
detected from the name and tags of the current branch. Note: Must pass `space`
or `branch` if repo is in detached HEAD mode, e.g. when running on Travis.
"""
# Detect space
repo = git.Repo('.')
branch = branch or _detect_branch(repo)
space = space or _detect_space(repo, branch, yes)
if space is None:
return
# Set api
api = 'https://api.cloud.gov'
run('cf api {0}'.format(api), echo=True)
# Log in if necessary
if os.getenv('FEC_CF_USERNAME') and os.getenv('FEC_CF_PASSWORD'):
run('cf auth "$FEC_CF_USERNAME" "$FEC_CF_PASSWORD"', echo=True)
# Target space
run('cf target -o fec -s {0}'.format(space), echo=True)
# Set deploy variables
with open('.cfmeta', 'w') as fp:
json.dump({'user': os.getenv('USER'), 'branch': branch}, fp)
# Deploy cms
deployed = run('cf app cms', echo=True, warn=True)
cmd = 'zero-downtime-push' if deployed.ok else 'push'
run('cf {0} cms -f manifest_{1}.yml'.format(cmd, space), echo=True)
@task
def notify():
try:
meta = json.load(open('.cfmeta'))
except OSError:
meta = {}
slack = Slacker(env.get_credential('FEC_SLACK_TOKEN'))
slack.chat.post_message(
env.get_credential('FEC_SLACK_CHANNEL', '#fec'),
'deploying branch {branch} of app {name} to space {space} by {user}'.format(
name=env.name,
space=env.space,
user=meta.get('user'),
branch=meta.get('branch'),
),
username=env.get_credential('FEC_SLACK_BOT', 'fec-bot'),
)