Gentoo Archives: gentoo-commits

From: Magnus Granberg <zorry@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/tinderbox-cluster:master commit in: /, patches/
Date: Mon, 22 Aug 2022 22:35:30
Message-Id: 1661207697.b635f1ab52fa63964ff9fc01f67638810c2fd2bf.zorry@gentoo
1 commit: b635f1ab52fa63964ff9fc01f67638810c2fd2bf
2 Author: Magnus Granberg <zorry <AT> gentoo <DOT> org>
3 AuthorDate: Mon Aug 22 22:34:57 2022 +0000
4 Commit: Magnus Granberg <zorry <AT> gentoo <DOT> org>
5 CommitDate: Mon Aug 22 22:34:57 2022 +0000
6 URL: https://gitweb.gentoo.org/proj/tinderbox-cluster.git/commit/?id=b635f1ab
7
8 Add buildbot gitlab patch
9
10 Signed-off-by: Magnus Granberg <zorry <AT> gentoo.org>
11
12 master.cfg | 21 +++--
13 patches/bb-gitlab.patch | 212 +++++++++++++++++++++++++++++++++++++++++++++
14 patches/secretstring.patch | 74 ----------------
15 3 files changed, 225 insertions(+), 82 deletions(-)
16
17 diff --git a/master.cfg b/master.cfg
18 index af50ec2..dbdee3f 100644
19 --- a/master.cfg
20 +++ b/master.cfg
21 @@ -12,11 +12,13 @@ worker_data = [
22 {'uuid' : 'updatedb_2', 'password' : '', 'type' : 'local', 'enable' : True, },
23 {'uuid' : 'updatedb_3', 'password' : '', 'type' : 'local', 'enable' : True, },
24 {'uuid' : 'updatedb_4', 'password' : '', 'type' : 'local', 'enable' : True, },
25 - {'uuid' : 'c89c2c1a-46e0-4ded-81dd-c51afeb7fcfa', 'password' : 'test', 'type' : 'log', 'enable' : True, },
26 - {'uuid' : 'a89c2c1a-46e0-4ded-81dd-c51afeb7fcfa', 'password' : 'test', 'type' : 'docker', 'enable' : True, },
27 - {'uuid' : 'a89c2c1a-46e0-4ded-81dd-c51afeb7fcfb', 'password' : 'test', 'type' : 'docker', 'enable' : True, },
28 - {'uuid' : 'a89c2c1a-46e0-4ded-81dd-c51afeb7fcfd', 'password' : 'test', 'type' : 'docker', 'enable' : True, },
29 - {'uuid' : 'c89c2c1a-46e0-4ded-81dd-c51afeb7fcfa', 'password' : 'test', 'type' : 'node', 'enable' : True, },
30 + {'uuid' : 'b89c2c1a-46e0-4ded-81dd-c51afeb7fcfa', 'password' : 'X', 'type' : 'log', 'enable' : True, },
31 + {'uuid' : 'b89c2c1a-46e0-4ded-81dd-c51afeb7fcfb', 'password' : 'X', 'type' : 'log', 'enable' : True, },
32 + {'uuid' : 'b89c2c1a-46e0-4ded-81dd-c51afeb7fcfc', 'password' : 'X', 'type' : 'log', 'enable' : True, },
33 + {'uuid' : 'a89c2c1a-46e0-4ded-81dd-c51afeb7fcfa', 'password' : 'X', 'type' : 'docker', 'enable' : True, },
34 + {'uuid' : 'a89c2c1a-46e0-4ded-81dd-c51afeb7fcfb', 'password' : 'X', 'type' : 'docker', 'enable' : True, },
35 + {'uuid' : 'a89c2c1a-46e0-4ded-81dd-c51afeb7fcfd', 'password' : 'X', 'type' : 'docker', 'enable' : True, },
36 + {'uuid' : 'c89c2c1a-46e0-4ded-81dd-c51afeb7fcfa', 'password' : 'X', 'type' : 'node', 'enable' : True, },
37 ]
38
39 # This is the dictionary that the buildmaster pays attention to. We also use
40 @@ -27,7 +29,8 @@ c['buildbotNetUsageData'] = None
41
42 ####### SECRETS
43
44 -c['secretsProviders'] = [secrets.SecretInAFile(dirname="/var/lib/buildmaster/gentoo-ci-cloud/secrets/")]
45 +c['secretsProviders'] = []
46 +c['secretsProviders'].append(secrets.SecretInAFile(dirname="/var/lib/buildmaster/gentoo-ci-cloud/secrets"))
47
48 ####### WORKERS
49
50 @@ -88,7 +91,7 @@ c['titleURL'] = "https://gentoo-ci.gentoo.org"
51 # the 'www' entry below, but with an externally-visible host name which the
52 # buildbot cannot figure out without some help.
53
54 -c['buildbotURL'] = "http://90.231.13.235:8010/"
55 +c['buildbotURL'] = "http://0.0.0.0:8010/"
56
57 # minimalistic config to activate new web UI
58 c['www'] = dict(
59 @@ -97,6 +100,8 @@ c['www'] = dict(
60 change_hook_dialects={
61 'gitlab' : {
62 'secret': util.Secret("WWWHookGitlabToken"),
63 + 'token': util.Secret("gitlabToken"),
64 + 'baseUrl': 'https://gitlab.gentoo.org',
65 },
66 },
67 )
68 @@ -116,4 +121,4 @@ c['www']['ui_default_config'] = {
69 # It's easy to start with sqlite, but it's recommended to switch to a dedicated
70 # database, such as PostgreSQL or MySQL, for use in production environments.
71 # http://docs.buildbot.net/current/manual/configuration/global.html#database-specification
72 -c['db_url'] = "postgresql://buildbot:fooo@192.168.1.9/buildbot"
73 +c['db_url'] = "postgresql://buildbot:X@192.0.0.0/buildbot"
74
75 diff --git a/patches/bb-gitlab.patch b/patches/bb-gitlab.patch
76 new file mode 100644
77 index 0000000..f57a2ac
78 --- /dev/null
79 +++ b/patches/bb-gitlab.patch
80 @@ -0,0 +1,212 @@
81 +--- a/buildbot/www/hooks/gitlab.py 2022-03-06 15:10:44.000000000 +0100
82 ++++ b/buildbot/www/hooks/gitlab.py 2022-08-07 22:22:16.570498909 +0200
83 +@@ -19,6 +19,8 @@ import re
84 +
85 + from dateutil.parser import parse as dateparse
86 +
87 ++import gitlab as python_gitlab
88 ++
89 + from twisted.internet.defer import inlineCallbacks
90 + from twisted.python import log
91 +
92 +@@ -26,6 +28,7 @@ from buildbot.process.properties import
93 + from buildbot.util import bytes2unicode
94 + from buildbot.www.hooks.base import BaseHookHandler
95 +
96 ++_HOSTED_BASE_URL = 'https://gitlab.com'
97 + _HEADER_EVENT = b'X-Gitlab-Event'
98 + _HEADER_GITLAB_TOKEN = b'X-Gitlab-Token'
99 +
100 +@@ -94,6 +97,35 @@ class GitLabHandler(BaseHookHandler):
101 +
102 + return changes
103 +
104 ++ #@inlineCallbacks
105 ++ def _configGitlabRest(self, token, baseURL=None):
106 ++ if baseURL is None:
107 ++ baseURL = _HOSTED_BASE_URL
108 ++ if baseURL.endswith('/'):
109 ++ baseURL = baseURL[:-1]
110 ++ return python_gitlab.Gitlab(url=baseURL, private_token=token)
111 ++
112 ++ #@inlineCallbacks
113 ++ def _getFiles(self, attrs):
114 ++ """
115 ++ get the files changes
116 ++ """
117 ++ files = []
118 ++ project = self.gl.projects.get(attrs['target']['id'])
119 ++ mr = project.mergerequests.get(attrs['iid'])
120 ++ changes = mr.changes()
121 ++ if isinstance(changes['changes'], list):
122 ++ for change in changes['changes']:
123 ++ print(change['old_path'])
124 ++ print(change['new_path'])
125 ++ print(change['new_file'])
126 ++ print(change['renamed_file'])
127 ++ print(change['deleted_file'])
128 ++ if change['old_path'] == change['new_path']:
129 ++ files.append(change['old_path'])
130 ++ print(f"Files: {files}")
131 ++ return files
132 ++
133 + def _process_merge_request_change(self, payload, event, codebase=None):
134 + """
135 + Consumes the merge_request JSON as a python object and turn it into a buildbot change.
136 +@@ -126,7 +158,7 @@ class GitLabHandler(BaseHookHandler):
137 +
138 + changes = [{
139 + 'author': f"{commit['author']['name']} <{commit['author']['email']}>",
140 +- 'files': [], # @todo use rest API
141 ++ 'files' : self._getFiles(attrs),
142 + 'comments': f"MR#{attrs['iid']}: {attrs['title']}\n\n{attrs['description']}",
143 + 'revision': commit['id'],
144 + 'when_timestamp': when_timestamp,
145 +@@ -151,6 +183,65 @@ class GitLabHandler(BaseHookHandler):
146 + changes[0]['codebase'] = codebase
147 + return changes
148 +
149 ++ def _process_note_addition_to_merge_request(self, payload, event, codebase=None):
150 ++ """
151 ++ Consumes a note event JSON as a python object and turn it into a buildbot change.
152 ++ :arguments:
153 ++ payload
154 ++ Python Object that represents the JSON sent by GitLab Service
155 ++ Hook.
156 ++ Comments in merge_requests are send as note events by the API
157 ++ """
158 ++ attrs = payload['object_attributes']
159 ++
160 ++ # handle only note events coming from merge_requests
161 ++ # this can be direct comments or comments added to a changeset of the MR
162 ++ #
163 ++ # editing a comment does NOT lead to an event at all
164 ++ if 'merge_request' not in payload:
165 ++ log.msg(f"Found note event (id {attrs['id']}) without corresponding MR - ignore")
166 ++ return []
167 ++
168 ++ # change handling is very similar to the method above, but
169 ++ commit = payload['merge_request']['last_commit']
170 ++ when_timestamp = dateparse(commit['timestamp'])
171 ++ # @todo provide and document a way to choose between http and ssh url
172 ++ repo_url = payload['merge_request']['target']['git_http_url']
173 ++ # project name from http headers is empty for me, so get it from
174 ++ # object_attributes/target/name
175 ++ mr = payload['merge_request']
176 ++ project = mr['target']['name']
177 ++
178 ++ log.msg(f"Found notes on MR#{mr['iid']}: {attrs['note']}")
179 ++ changes = [{
180 ++ 'author': f"{commit['author']['name']} <{commit['author']['email']}>",
181 ++ 'files': [], # not provided by rest API
182 ++ 'comments': f"MR#{mr['iid']}: {mr['title']}\n\n{mr['description']}",
183 ++ 'revision': commit['id'],
184 ++ 'when_timestamp': when_timestamp,
185 ++ 'branch': mr['target_branch'],
186 ++ 'repository': repo_url,
187 ++ 'project': project,
188 ++ 'category': event,
189 ++ 'revlink': mr['url'],
190 ++ 'properties': {
191 ++ 'source_branch': mr['source_branch'],
192 ++ 'source_project_id': mr['source_project_id'],
193 ++ 'source_repository': mr['source']['git_http_url'],
194 ++ 'source_git_ssh_url': mr['source']['git_ssh_url'],
195 ++ 'target_branch': mr['target_branch'],
196 ++ 'target_project_id': mr['target_project_id'],
197 ++ 'target_repository': mr['target']['git_http_url'],
198 ++ 'target_git_ssh_url': mr['target']['git_ssh_url'],
199 ++ 'event': event,
200 ++ 'comments': attrs['note'],
201 ++ },
202 ++ }]
203 ++ if codebase is not None:
204 ++ changes[0]['codebase'] = codebase
205 ++ return changes
206 ++
207 ++
208 + @inlineCallbacks
209 + def getChanges(self, request):
210 + """
211 +@@ -160,17 +251,21 @@ class GitLabHandler(BaseHookHandler):
212 + request
213 + the http request object
214 + """
215 ++ p = Properties()
216 ++ p.master = self.master
217 + expected_secret = isinstance(self.options, dict) and self.options.get('secret')
218 + if expected_secret:
219 + received_secret = request.getHeader(_HEADER_GITLAB_TOKEN)
220 + received_secret = bytes2unicode(received_secret)
221 +-
222 +- p = Properties()
223 +- p.master = self.master
224 + expected_secret_value = yield p.render(expected_secret)
225 +
226 + if received_secret != expected_secret_value:
227 + raise ValueError("Invalid secret")
228 ++
229 ++ baseUrl_value = isinstance(self.options, dict) and self.options.get('baseUrl')
230 ++ expected_token = isinstance(self.options, dict) and self.options.get('token')
231 ++ expected_token_value = yield p.render(expected_token)
232 ++
233 + try:
234 + content = request.content.read()
235 + payload = json.loads(bytes2unicode(content))
236 +@@ -189,7 +284,11 @@ class GitLabHandler(BaseHookHandler):
237 + repo_url = payload['repository']['url']
238 + changes = self._process_change(
239 + payload, user, repo, repo_url, event_type, codebase=codebase)
240 ++ elif event_type == 'note':
241 ++ changes = self._process_note_addition_to_merge_request(
242 ++ payload, event_type, codebase=codebase)
243 + elif event_type == 'merge_request':
244 ++ self.gl = self._configGitlabRest(expected_token_value, baseURL=baseUrl_value)
245 + changes = self._process_merge_request_change(
246 + payload, event_type, codebase=codebase)
247 + else:
248 +--- a/buildbot/reporters/gitlab.py 2022-03-06 15:10:44.000000000 +0100
249 ++++ b/buildbot/reporters/gitlab.py 2022-08-23 00:11:55.996195542 +0200
250 +@@ -95,7 +95,7 @@ class GitLabStatusPush(ReporterBase):
251 + :param branch: Branch name to create the status for.
252 + :param sha: Full sha to create the status for.
253 + :param state: one of the following 'pending', 'success', 'failed'
254 +- or 'cancelled'.
255 ++ or 'canceled'.
256 + :param target_url: Target url to associate with this status.
257 + :param description: Short description of the status.
258 + :param context: Context of the result
259 +@@ -155,10 +155,12 @@ class GitLabStatusPush(ReporterBase):
260 + SKIPPED: 'success',
261 + EXCEPTION: 'failed',
262 + RETRY: 'pending',
263 +- CANCELLED: 'cancelled'
264 ++ CANCELLED: 'canceled'
265 + }.get(build['results'], 'failed')
266 +- else:
267 ++ elif build.get('started_at'):
268 + state = 'running'
269 ++ else:
270 ++ state = 'pending'
271 +
272 + context = yield props.render(self.context)
273 +
274 +@@ -167,8 +169,8 @@ class GitLabStatusPush(ReporterBase):
275 + # FIXME: probably only want to report status for the last commit in the changeset
276 + for sourcestamp in sourcestamps:
277 + sha = sourcestamp['revision']
278 +- if 'source_project_id' in props:
279 +- proj_id = props['source_project_id']
280 ++ if 'target_project_id' in props:
281 ++ proj_id = props['target_project_id']
282 + else:
283 + proj_id = yield self.getProjectId(sourcestamp)
284 + if proj_id is None:
285 +@@ -189,6 +191,7 @@ class GitLabStatusPush(ReporterBase):
286 + description=description
287 + )
288 + if res.code not in (200, 201, 204):
289 ++ log.msg(res.code)
290 + message = yield res.json()
291 + message = message.get('message', 'unspecified error')
292 + log.msg(
293
294 diff --git a/patches/secretstring.patch b/patches/secretstring.patch
295 deleted file mode 100644
296 index 4e0833d..0000000
297 --- a/patches/secretstring.patch
298 +++ /dev/null
299 @@ -1,74 +0,0 @@
300 -diff --git a/master/buildbot/process/buildstep.py b/master/buildbot/process/buildstep.py
301 -index 7ac18b086..82ff7ce07 100644
302 ---- a/master/buildbot/process/buildstep.py
303 -+++ b/master/buildbot/process/buildstep.py
304 -@@ -850,6 +850,7 @@ class ShellMixin:
305 - 'sigtermTime',
306 - 'initialStdin',
307 - 'decodeRC',
308 -+ 'SecretString',
309 - ]
310 - renderables = _shellMixinArgs
311 -
312 -diff --git a/master/buildbot/process/remotecommand.py b/master/buildbot/process/remotecommand.py
313 -index 90ec4c44d..fb3099b28 100644
314 ---- a/master/buildbot/process/remotecommand.py
315 -+++ b/master/buildbot/process/remotecommand.py
316 -@@ -44,7 +44,7 @@ class RemoteCommand(base.RemoteCommandImpl):
317 -
318 - def __init__(self, remote_command, args, ignore_updates=False,
319 - collectStdout=False, collectStderr=False, decodeRC=None,
320 -- stdioLogName='stdio'):
321 -+ stdioLogName='stdio', SecretString=False):
322 - if decodeRC is None:
323 - decodeRC = {0: SUCCESS}
324 - self.logs = {}
325 -@@ -70,6 +70,7 @@ class RemoteCommand(base.RemoteCommandImpl):
326 - self.commandID = None
327 - self.deferred = None
328 - self.interrupted = False
329 -+ self.SecretString = SecretString
330 - # a lock to make sure that only one log-handling method runs at a time.
331 - # This is really only a problem with old-style steps, which do not
332 - # wait for the Deferred from one method before invoking the next.
333 -@@ -275,6 +276,8 @@ class RemoteCommand(base.RemoteCommandImpl):
334 - def cleanup(data):
335 - if self.step is None:
336 - return data
337 -+ if self.SecretString and isinstance(self.SecretString, list) and len(self.SecretString) == 2:
338 -+ data = data.replace(self.SecretString[0], '<' + self.SecretString[1] + '>')
339 - return self.step.build.properties.cleanupTextFromSecrets(data)
340 -
341 - if self.debug:
342 -@@ -358,7 +361,8 @@ class RemoteShellCommand(RemoteCommand):
343 - collectStdout=False, collectStderr=False,
344 - interruptSignal=None,
345 - initialStdin=None, decodeRC=None,
346 -- stdioLogName='stdio'):
347 -+ stdioLogName='stdio',
348 -+ SecretString=False):
349 - if logfiles is None:
350 - logfiles = {}
351 - if decodeRC is None:
352 -@@ -398,7 +402,8 @@ class RemoteShellCommand(RemoteCommand):
353 - super().__init__("shell", args, collectStdout=collectStdout,
354 - collectStderr=collectStderr,
355 - decodeRC=decodeRC,
356 -- stdioLogName=stdioLogName)
357 -+ stdioLogName=stdioLogName,
358 -+ SecretString=SecretString)
359 -
360 - def _start(self):
361 - if self.args['usePTY'] is None:
362 -diff --git a/master/buildbot/steps/shell.py b/master/buildbot/steps/shell.py
363 -index d21ca7b9b..cf56a2802 100644
364 ---- a/master/buildbot/steps/shell.py
365 -+++ b/master/buildbot/steps/shell.py
366 -@@ -183,6 +183,7 @@ class ShellCommand(buildstep.ShellMixin, buildstep.BuildStep):
367 - 'decodeRC',
368 - 'stdioLogName',
369 - 'workdir',
370 -+ 'SecretString',
371 - ] + buildstep.BuildStep.parms
372 -
373 - invalid_args = []