-
Notifications
You must be signed in to change notification settings - Fork 6
/
tc.py
executable file
·271 lines (220 loc) · 9.35 KB
/
tc.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# PYTHON_ARGCOMPLETE_OK
"""
tc.py <command> [<args>]
Where command is the type of build you with to invoke:
linux Neo4j Linux
power8 Neo4j Power8
windows Neo4j Windows
har HA Robustness
"""
# StdLib imports first
from __future__ import print_function
from argparse import ArgumentParser
import sys
try:
import urlparse
except ImportError:
# Renamed in Python3
from urllib import parse as urlparse
# Library imports
import requests as r
# Some constants #
# Want to request json from the server
_HEADERS = {'Accept': 'application/json',
'Content-Type': 'application/xml'}
_REQUESTBASE = """
<build personal="{personal}" branchName="{branch}">
<buildType id="{buildid}"/>
<comment><text>Triggered from CLI</text></comment>
<properties>
<property name="remote" value="{remote}"/>
<property name="branch" value="{branch}"/>{props}
</properties>
</build>
"""
_REQUESTPROPERTYBASE = '\n <property name="{name}" value="{value}"/>'
_NEO4JLINUX_ID = "JonasHaRequests_Neo4jCustom"
_NEO4JPOWER8_ID = "JonasRequests_Neo4jCustomPower8"
_HAR_ID = "JonasHaRequests_HarBranchArtifacts"
_WIN_ID = "JonasHaRequests_Neo4jCustomWindows"
_LINUX_JDKS = ['openjdk-8', 'openjdk-7',
'oracle-jdk-8', 'oracle-jdk-7',
'ibmjdk-8', 'ibmjdk-7']
# End constants #
# Top level parsers
# All builds share teamcity information
_PARSER = ArgumentParser(add_help=False)
_REQUIRED = _PARSER.add_argument_group('mandatory arguments')
_REQUIRED.add_argument('-u', '--user', metavar='USERNAME',
help='TeamCity username', required=True)
_REQUIRED.add_argument('-p', '--password',
help='TeamCity password', required=True)
_PARSER.add_argument('-r', '--remote', metavar='URL',
help='Public remote repo where branch exists',
default='origin')
_PARSER.add_argument('--teamcity', metavar='URL',
help='Url to TeamCity',
default='https://build.neohq.net')
_PERSONAL_PARSER = _PARSER.add_mutually_exclusive_group(required=False)
_PERSONAL_PARSER.add_argument('--personal', dest='personal',
action='store_true',
help='Start as personal build')
_PERSONAL_PARSER.add_argument('--no-personal', dest='personal',
action='store_false',
help='Do not start as personal build')
_PARSER.set_defaults(personal=False)
# All Neo4j builds share some obvious arguments
_NEO4JPARSERBASE = ArgumentParser(add_help=False)
_NEO4JPARSERBASE.add_argument('--maven-goals', metavar='GOALS',
help='Maven goal(s) to invoke',
default='clean verify')
_NEO4JPARSERBASE.add_argument('--maven-args', metavar='ARGS',
help='Additional Maven arguments',
default='-DrunITs -DskipBrowser')
_NEO4JREQUIRED = _NEO4JPARSERBASE.add_argument_group('mandatory arguments')
_NEO4JREQUIRED.add_argument('-b', '--branch',
help=('Branch of Neo4j to checkout.' +
' For a pr specify "refs/pull/<num>/head"'),
required=True)
# End top level parsers
def dict_as_properties(props):
"""
Format a dictionary as xml property tags:
<property name=NAME value=VALUE />
"""
xml = ""
for k, v in props.items():
xml += _REQUESTPROPERTYBASE.format(name=k, value=v)
return xml
def request_xml(buildid, personal, branch, remote, props=None):
"""
Format an XML build request
"""
if props is None:
props = ""
return _REQUESTBASE.format(buildid=buildid,
remote=remote,
branch=branch,
props=props,
personal=str(personal).lower())
def send_request(user, password, url, data):
"""
Start a build, defined in data
"""
resp = r.post(urlparse.urljoin(url, "httpAuth/app/rest/buildQueue"),
auth=(user, password),
headers=_HEADERS,
data=data)
if resp.ok:
print("Build started. View status at")
print(resp.json().get('webUrl'))
else:
print("Could not start build:")
print(resp.status_code)
try:
print(resp.json())
except:
print(resp.text)
exit(1)
def tc_mvn_args(original):
"""
Add some useful maven arguments in TC
"""
return "-DfailIfNoTests=false -Dmaven.test.failure.ignore=true -Dlicensing.skip --show-version " + original
def start_linux(user, password, url, personal, branch, remote,
mvngoals, mvnargs, jdk):
"""
Start a custom linux build
"""
props = dict_as_properties({'project-default-jdk': "%{}%".format(jdk),
'maven-goals': mvngoals,
'maven-args': mvnargs})
data = request_xml(_NEO4JLINUX_ID, personal, branch, remote, props)
send_request(user, password, url, data)
def start_power8(user, password, url, personal, branch, remote,
mvngoals, mvnargs, jdk):
"""
Start a custom linux build
"""
props = dict_as_properties({'project-default-jdk': "%{}%".format(jdk),
'maven-goals': mvngoals,
'maven-args': mvnargs})
data = request_xml(_NEO4JPOWER8_ID, personal, branch, remote, props)
send_request(user, password, url, data)
def start_windows(user, password, url, personal, branch, remote,
mvngoals, mvnargs):
"""
Start a custom windows build
"""
props = dict_as_properties({'maven-goals': mvngoals,
'maven-args': mvnargs})
data = request_xml(_WIN_ID, personal, branch, remote, props)
send_request(user, password, url, data)
def start_ha(user, password, url, personal, branch, remote, arguments):
"""
Start a custom ha robustness build
"""
props = dict_as_properties({'run-args': arguments})
data = request_xml(_HAR_ID, personal, branch, remote, props)
send_request(user, password, url, data)
class TC(object):
def __init__(self, cliargs):
parser = ArgumentParser(
description='Script for triggering builds on TeamCity',
usage=__doc__)
parser.add_argument('command', help='Type of build to invoke')
# Only care about the first argument
args = parser.parse_args(cliargs[:1])
# If no method with that name exists on this object
if not hasattr(self, args.command):
print('Unrecognized command:', args.command)
parser.print_help()
exit(1)
# Invoke the sub command method with rest of the args
getattr(self, args.command)(cliargs[1:])
def windows(self, subargs):
parser = ArgumentParser(description="Neo4j Windows",
parents=[_PARSER, _NEO4JPARSERBASE])
args = parser.parse_args(subargs)
start_windows(args.user, args.password, args.teamcity, args.personal,
args.branch, args.remote,
args.maven_goals,
tc_mvn_args(args.maven_args))
def linux(self, subargs):
parser = ArgumentParser(description="Neo4j Linux",
parents=[_PARSER, _NEO4JPARSERBASE])
parser.add_argument('--jdk', help='JDK to build with',
default=_LINUX_JDKS[0], choices=_LINUX_JDKS)
args = parser.parse_args(subargs)
start_linux(args.user, args.password, args.teamcity, args.personal,
args.branch, args.remote,
args.maven_goals,
tc_mvn_args(args.maven_args),
args.jdk)
def power8(self, subargs):
parser = ArgumentParser(description="Neo4j Power8",
parents=[_PARSER, _NEO4JPARSERBASE])
parser.add_argument('--jdk', help='JDK to build with',
default='ibmjdk-8', choices=_LINUX_JDKS)
args = parser.parse_args(subargs)
start_power8(args.user, args.password, args.teamcity, args.personal,
args.branch, args.remote,
args.maven_goals,
tc_mvn_args(args.maven_args),
args.jdk)
def har(self, subargs):
# Add to top group to keep a single group
_REQUIRED.add_argument('-b', '--branch', required=True,
help='Branch of Neo4j to checkout. Supports special "pr/1234" syntax')
parser = ArgumentParser(description="HA Robustness",
parents=[_PARSER])
parser.add_argument('--arguments',
help='Arguments to give to HA-robustness run script. Note that due to a bug, you MUST start this string with a SPACE',
default='-ha-cluster-size=3 -threads=10 -jvm-mode=separate -time=7200 -history -myknocks -lock_manager=forseti')
args = parser.parse_args(subargs)
start_ha(args.user, args.password, args.teamcity, args.personal,
args.branch, args.remote, args.arguments)
if __name__ == "__main__":
TC(sys.argv[1:])