Add back further changes from blender-devops

This commit is contained in:
Bart van der Braak 2024-11-19 21:41:39 +01:00
parent 18e653fd2e
commit 0a1454d250
61 changed files with 7917 additions and 1 deletions

21
config/gitea/LICENSE Normal file
View 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
View file

@ -0,0 +1,4 @@
### Buildbot Gitea Integration
Based on:
https://github.com/lab132/buildbot-gitea

0
config/gitea/__init__.py Normal file
View file

62
config/gitea/blender.py Normal file
View 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
View 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