Add back further changes from blender-devops
This commit is contained in:
parent
18e653fd2e
commit
0a1454d250
61 changed files with 7917 additions and 1 deletions
21
config/gitea/LICENSE
Normal file
21
config/gitea/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 LAB132
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
4
config/gitea/README.md
Normal file
4
config/gitea/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
### Buildbot Gitea Integration
|
||||
|
||||
Based on:
|
||||
https://github.com/lab132/buildbot-gitea
|
0
config/gitea/__init__.py
Normal file
0
config/gitea/__init__.py
Normal file
62
config/gitea/blender.py
Normal file
62
config/gitea/blender.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: 2018 LAB132
|
||||
# SPDX-FileCopyrightText: 2013-2024 Blender Authors
|
||||
# <pep8 compliant>
|
||||
|
||||
# Based on the gitlab reporter from buildbot
|
||||
|
||||
from twisted.python import log
|
||||
|
||||
import buildbot.plugins
|
||||
|
||||
import importlib
|
||||
import requests
|
||||
|
||||
import gitea.reporter
|
||||
|
||||
importlib.reload(gitea.reporter)
|
||||
|
||||
# Create status reporter service.
|
||||
gitea_url = "https://projects.blender.org"
|
||||
gitea_api_token = None
|
||||
gitea_status_service = None
|
||||
|
||||
|
||||
def setup_service(devops_env_id: str):
|
||||
import conf.worker
|
||||
|
||||
importlib.reload(conf.worker)
|
||||
worker_config = conf.worker.get_config(devops_env_id)
|
||||
gitea_api_token = worker_config.gitea_api_token(devops_env_id)
|
||||
|
||||
if gitea_api_token:
|
||||
log.msg("Found Gitea API token, enabling status push")
|
||||
return gitea.reporter.GiteaStatusService11(gitea_url, gitea_api_token, verbose=False)
|
||||
else:
|
||||
log.msg("No Gitea API token found, status push disabled")
|
||||
return None
|
||||
|
||||
|
||||
# Get revision for coordinator.
|
||||
@buildbot.plugins.util.renderer
|
||||
def get_patch_revision(props):
|
||||
if "revision" in props and props["revision"]:
|
||||
return {}
|
||||
if "pull_revision" in props and props["pull_revision"]:
|
||||
return {"revision": props["pull_revision"]}
|
||||
pull_id = props["patch_id"]
|
||||
url = f"{gitea_url}/api/v1/repos/blender/blender/pulls/{pull_id}"
|
||||
response = requests.get(url, headers={"accept": "application/json"})
|
||||
sha = response.json().get("head", {"sha": ""}).get("sha")
|
||||
return {"revision": sha}
|
||||
|
||||
|
||||
@buildbot.plugins.util.renderer
|
||||
def get_branch_revision(props):
|
||||
if "revision" in props and props["revision"]:
|
||||
return {}
|
||||
branch = props["override_branch_id"]
|
||||
url = f"{gitea_url}/api/v1/repos/blender/blender/git/commits/{branch}"
|
||||
response = requests.get(url, headers={"accept": "application/json"})
|
||||
sha = response.json().get("sha", "")
|
||||
return {"revision": sha}
|
279
config/gitea/reporter.py
Normal file
279
config/gitea/reporter.py
Normal file
|
@ -0,0 +1,279 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: 2018 LAB132
|
||||
# SPDX-FileCopyrightText: 2013-2024 Blender Authors
|
||||
# <pep8 compliant>
|
||||
|
||||
# Based on the gitlab reporter from buildbot
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.python import log
|
||||
|
||||
from buildbot.process.properties import Interpolate
|
||||
from buildbot.process.properties import Properties
|
||||
from buildbot.process.results import CANCELLED
|
||||
from buildbot.process.results import EXCEPTION
|
||||
from buildbot.process.results import FAILURE
|
||||
from buildbot.process.results import RETRY
|
||||
from buildbot.process.results import SKIPPED
|
||||
from buildbot.process.results import SUCCESS
|
||||
from buildbot.process.results import WARNINGS
|
||||
from buildbot.reporters import http
|
||||
from buildbot.util import httpclientservice
|
||||
from buildbot.reporters.generators.build import BuildStartEndStatusGenerator
|
||||
from buildbot.reporters.message import MessageFormatterRenderable
|
||||
|
||||
|
||||
import re
|
||||
|
||||
|
||||
# This name has a number in it to trick buildbot into reloading it on without
|
||||
# restart. Needs to be incremented every time this file is changed. Is there
|
||||
# a better solution?
|
||||
class GiteaStatusService11(http.ReporterBase):
|
||||
name = "GiteaStatusService11"
|
||||
ssh_url_match = re.compile(
|
||||
r"(ssh://)?[\w+\-\_]+@[\w\.\-\_]+:?(\d*/)?(?P<owner>[\w_\-\.]+)/(?P<repo_name>[\w_\-\.]+?)(\.git)?$"
|
||||
)
|
||||
|
||||
def checkConfig(
|
||||
self,
|
||||
baseURL,
|
||||
token,
|
||||
context=None,
|
||||
context_pr=None,
|
||||
verbose=False,
|
||||
debug=None,
|
||||
verify=None,
|
||||
generators=None,
|
||||
warningAsSuccess=False,
|
||||
**kwargs,
|
||||
):
|
||||
if generators is None:
|
||||
generators = self._create_default_generators()
|
||||
|
||||
super().checkConfig(generators=generators, **kwargs)
|
||||
httpclientservice.HTTPClientService.checkAvailable(self.__class__.__name__)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def reconfigService(
|
||||
self,
|
||||
baseURL,
|
||||
token,
|
||||
context=None,
|
||||
context_pr=None,
|
||||
verbose=False,
|
||||
debug=None,
|
||||
verify=None,
|
||||
generators=None,
|
||||
warningAsSuccess=False,
|
||||
**kwargs,
|
||||
):
|
||||
token = yield self.renderSecrets(token)
|
||||
self.debug = debug
|
||||
self.verify = verify
|
||||
self.verbose = verbose
|
||||
if generators is None:
|
||||
generators = self._create_default_generators()
|
||||
|
||||
yield super().reconfigService(generators=generators, **kwargs)
|
||||
|
||||
self.context = context or Interpolate("buildbot/%(prop:buildername)s")
|
||||
self.context_pr = context_pr or Interpolate("buildbot/pull_request/%(prop:buildername)s")
|
||||
if baseURL.endswith("/"):
|
||||
baseURL = baseURL[:-1]
|
||||
self.baseURL = baseURL
|
||||
self._http = yield httpclientservice.HTTPClientService.getService(
|
||||
self.master,
|
||||
baseURL,
|
||||
headers={"Authorization": "token {}".format(token)},
|
||||
debug=self.debug,
|
||||
verify=self.verify,
|
||||
)
|
||||
self.verbose = verbose
|
||||
self.project_ids = {}
|
||||
self.warningAsSuccess = warningAsSuccess
|
||||
|
||||
def _create_default_generators(self):
|
||||
start_formatter = MessageFormatterRenderable("Build started.")
|
||||
end_formatter = MessageFormatterRenderable("Build done.")
|
||||
|
||||
return [
|
||||
BuildStartEndStatusGenerator(
|
||||
start_formatter=start_formatter, end_formatter=end_formatter
|
||||
)
|
||||
]
|
||||
|
||||
def createStatus(
|
||||
self, project_owner, repo_name, sha, state, target_url=None, description=None, context=None
|
||||
):
|
||||
"""
|
||||
:param project_owner: username of the owning user or organization
|
||||
:param repo_name: name of the repository
|
||||
:param sha: Full sha to create the status for.
|
||||
:param state: one of the following 'pending', 'success', 'failed'
|
||||
or 'cancelled'.
|
||||
:param target_url: Target url to associate with this status.
|
||||
:param description: Short description of the status.
|
||||
:param context: Context of the result
|
||||
:return: A deferred with the result from GitLab.
|
||||
|
||||
"""
|
||||
payload = {"state": state}
|
||||
|
||||
if description is not None:
|
||||
payload["description"] = description
|
||||
|
||||
if target_url is not None:
|
||||
payload["target_url"] = target_url
|
||||
|
||||
if context is not None:
|
||||
payload["context"] = context
|
||||
|
||||
url = "/api/v1/repos/{owner}/{repository}/statuses/{sha}".format(
|
||||
owner=project_owner, repository=repo_name, sha=sha
|
||||
)
|
||||
log.msg(f"Sending status to {url}: {payload}")
|
||||
|
||||
return self._http.post(url, json=payload)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def sendMessage(self, reports):
|
||||
yield self._send_impl(reports)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _send_status(
|
||||
self, build, repository_owner, repository_name, sha, state, context, description
|
||||
):
|
||||
try:
|
||||
target_url = build["url"]
|
||||
res = yield self.createStatus(
|
||||
project_owner=repository_owner,
|
||||
repo_name=repository_name,
|
||||
sha=sha,
|
||||
state=state,
|
||||
target_url=target_url,
|
||||
context=context,
|
||||
description=description,
|
||||
)
|
||||
if res.code not in (200, 201, 204):
|
||||
message = yield res.json()
|
||||
message = message.get("message", "unspecified error")
|
||||
log.msg(
|
||||
'Could not send status "{state}" for '
|
||||
"{repo} at {sha}: {code} : {message}".format(
|
||||
state=state, repo=repository_name, sha=sha, code=res.code, message=message
|
||||
)
|
||||
)
|
||||
elif self.verbose:
|
||||
log.msg(
|
||||
'Status "{state}" sent for '
|
||||
"{repo} at {sha}.".format(state=state, repo=repository_name, sha=sha)
|
||||
)
|
||||
except Exception as e:
|
||||
log.err(
|
||||
e,
|
||||
'Failed to send status "{state}" for '
|
||||
"{repo} at {sha}".format(state=state, repo=repository_name, sha=sha),
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _send_impl(self, reports):
|
||||
for report in reports:
|
||||
try:
|
||||
builds = report["builds"]
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
for build in builds:
|
||||
builder_name = build["builder"]["name"]
|
||||
|
||||
props = Properties.fromDict(build["properties"])
|
||||
props.master = self.master
|
||||
|
||||
description = report.get("body", None)
|
||||
|
||||
if build["complete"]:
|
||||
state = {
|
||||
SUCCESS: "success",
|
||||
WARNINGS: "success" if self.warningAsSuccess else "warning",
|
||||
FAILURE: "failure",
|
||||
SKIPPED: "success",
|
||||
EXCEPTION: "error",
|
||||
RETRY: "pending",
|
||||
CANCELLED: "error",
|
||||
}.get(build["results"], "failure")
|
||||
else:
|
||||
state = "pending"
|
||||
|
||||
if "pr_id" in props:
|
||||
context = yield props.render(self.context_pr)
|
||||
else:
|
||||
context = yield props.render(self.context)
|
||||
|
||||
sourcestamps = build["buildset"]["sourcestamps"]
|
||||
|
||||
# BLENDER: some hardcoded logic for now.
|
||||
if (
|
||||
"-code-daily-" in builder_name
|
||||
or "-code-patch-" in builder_name
|
||||
or "-code-experimental-" in builder_name
|
||||
):
|
||||
repository_owner = "blender"
|
||||
repository_name = "blender"
|
||||
elif "-doc-manual-" in builder_name:
|
||||
repository_owner = "blender"
|
||||
repository_name = "blender-manual"
|
||||
elif "-doc-developer" in builder_name:
|
||||
repository_owner = "blender"
|
||||
repository_name = "blender-developer-docs"
|
||||
else:
|
||||
continue
|
||||
|
||||
# Source change from Git poller.
|
||||
for sourcestamp in sourcestamps:
|
||||
sha = sourcestamp["revision"]
|
||||
if sha not in {None, "", "HEAD"}:
|
||||
self._send_status(
|
||||
build,
|
||||
repository_owner,
|
||||
repository_name,
|
||||
sha,
|
||||
state,
|
||||
context,
|
||||
description,
|
||||
)
|
||||
continue
|
||||
|
||||
# Revision specified by get-revision step.
|
||||
if "revision" in props:
|
||||
sha = props["revision"]
|
||||
if sha not in {None, "", "HEAD"}:
|
||||
self._send_status(
|
||||
build,
|
||||
repository_owner,
|
||||
repository_name,
|
||||
sha,
|
||||
state,
|
||||
context,
|
||||
description,
|
||||
)
|
||||
|
||||
# Revision from blender-bot, so we can send a status before
|
||||
# the get-revision step runs.
|
||||
if "pull_revision" in props:
|
||||
sha = props["pull_revision"]
|
||||
if sha not in {None, "", "HEAD"}:
|
||||
self._send_status(
|
||||
build,
|
||||
repository_owner,
|
||||
repository_name,
|
||||
sha,
|
||||
state,
|
||||
context,
|
||||
description,
|
||||
)
|
||||
|
||||
continue
|
Loading…
Add table
Add a link
Reference in a new issue