Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ include Makefile.common
pkgdata_BINS = $(shell find * -maxdepth 0 -executable -type f)
pkgdata_SCRIPTS=$(wildcard *.py *.pl *.sh)
pkgdata_SCRIPTS+=findfileconflicts publish_distro generate-release-packages verify-build-and-generatelists gocd/verify-repo-built-successful.py
pkgdata_DATA+=bs_copy metrics osclib pkglistgen $(wildcard *.pm *.testcase)
pkgdata_DATA+=bs_copy metrics osclib pkglistgen staginginstallchecker $(wildcard *.pm *.testcase)
VERSION = "build-$(shell date +%F)"

all:

install:
install -d -m 755 $(DESTDIR)$(bindir) $(DESTDIR)$(pkgdatadir) $(DESTDIR)$(unitdir) $(DESTDIR)$(oscplugindir) $(DESTDIR)$(sysconfdir)/$(package_name) $(DESTDIR)$(grafana_provisioning_dir)/dashboards $(DESTDIR)$(grafana_provisioning_dir)/datasources $(DESTDIR)$(logdir)/$(package_name) $(DESTDIR)$(varlibdir)/osrt-staging/check-bugowner $(DESTDIR)$(varlibdir)/osrt-slsa/pkglistgen $(DESTDIR)$(varlibdir)/osrt-slsa/relpkggen
install -d -m 755 $(DESTDIR)$(bindir) $(DESTDIR)$(pkgdatadir) $(DESTDIR)$(unitdir) $(DESTDIR)$(oscplugindir) $(DESTDIR)$(sysconfdir)/$(package_name) $(DESTDIR)$(grafana_provisioning_dir)/dashboards $(DESTDIR)$(grafana_provisioning_dir)/datasources $(DESTDIR)$(logdir)/$(package_name) $(DESTDIR)$(varlibdir)/osrt-staging/check-bugowner $(DESTDIR)$(varlibdir)/osrt-staging/git-installcheck $(DESTDIR)$(varlibdir)/osrt-slsa/pkglistgen $(DESTDIR)$(varlibdir)/osrt-slsa/relpkggen
for i in $(pkgdata_SCRIPTS); do install -m 755 $$i $(DESTDIR)$(pkgdatadir); done
chmod 644 $(DESTDIR)$(pkgdatadir)/osc-*.py
for i in $(pkgdata_DATA); do cp -a $$i $(DESTDIR)$(pkgdatadir); done
Expand Down
24 changes: 24 additions & 0 deletions config/osrt-git-installcheck.env.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copy this file to /etc/default/osrt-git-installcheck.env.<instance_name>
# where <instance_name> is the name of the unit instance (which should also be
# the name of the build service/gitea user)

# GITEA_URL: the base URL of the Gitea instance
GITEA_URL="https://src.suse.de"

# GITEA_ACCESS_TOKEN: the access token for the user
GITEA_ACCESS_TOKEN="<INSERT_TOKEN_HERE>"

# GIT_ALLOW_REPOS: allowed repositories to process.
# For the installcheck bot, these need to be specified otherwise
# the bot would refuse processing even when the bot itself
# is added as a reviewer.
# Use a comma to specify multiple repositories:
# GIT_ALLOW_REPOS="products/SLFO,products/SLES"
GIT_ALLOW_REPOS="products/SLFO"

# API_URL: the Open Build Service apiurl
API_URL="https://api.suse.de"

# OSC_CONFIG: the path to the oscrc configuration file
# to use to interact with the Open Build Service
OSC_CONFIG="/etc/openSUSE-release-tools/oscrc.example"
Comment thread
gleidi-suse marked this conversation as resolved.
12 changes: 11 additions & 1 deletion dist/package/openSUSE-release-tools.spec
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
%global __provides_exclude ^perl.*
%define source_dir openSUSE-release-tools
%define announcer_filename factory-package-news
%define services osrt-slsa.target osrt-check-bugowner-gitea@.service osrt-relpkggen@.timer osrt-relpkggen@.service osrt-pkglistgen@.timer osrt-pkglistgen@.service
%define services osrt-slsa.target osrt-check-bugowner-gitea@.service osrt-git-installcheck@.service osrt-relpkggen@.timer osrt-relpkggen@.service osrt-pkglistgen@.timer osrt-pkglistgen@.service
Name: openSUSE-release-tools
Version: 0
Release: 0
Expand Down Expand Up @@ -240,6 +240,8 @@ Requires: build
# TODO Update requirements.
Requires: osclib = %{version}
Requires: perl-XML-Simple
Requires: openSUSE-release-tools-scm = %{version}
Requires: openSUSE-release-tools-plat = %{version}
Requires(pre): shadow
BuildArch: noarch

Expand Down Expand Up @@ -287,6 +289,7 @@ Group: Development/Tools/Other
Requires: %{name} = %{version}
Requires: openSUSE-release-tools-check-bugowner
Requires: openSUSE-release-tools-pkglistgen
Requires: openSUSE-release-tools-repo-checker
%sysusers_requires
Recommends: logrotate
BuildArch: noarch
Expand Down Expand Up @@ -474,6 +477,7 @@ exit 0
%exclude %{_datadir}/%{source_dir}/metrics_release.py
%exclude %{_datadir}/%{source_dir}/origin-manager.py
%exclude %{_bindir}/osrt-staging-report
%exclude %{_datadir}/%{source_dir}/staginginstallchecker
%exclude %{_datadir}/%{source_dir}/pkglistgen
%exclude %{_datadir}/%{source_dir}/pkglistgen.py
%exclude %{_datadir}/%{source_dir}/maintenance-installcheck.py
Expand Down Expand Up @@ -542,10 +546,13 @@ exit 0
%{_datadir}/%{source_dir}/verify-repo-built-successful.py
%{_sysconfdir}/openSUSE-release-tools/ibsapi
%{_sysconfdir}/openSUSE-release-tools/osrt-check-bugowner-gitea.env.in
%{_sysconfdir}/openSUSE-release-tools/osrt-git-installcheck.env.in
%{_sysusersdir}/%{name}.conf
%{_sysusersdir}/%{name}-staging.conf
%{_unitdir}/osrt-check-bugowner-gitea@.service
%{_unitdir}/osrt-check-bugowner-gitea@.timer
%{_unitdir}/osrt-git-installcheck@.service
%{_unitdir}/osrt-git-installcheck@.timer
%{_unitdir}/osrt-pkglistgen@.service
%{_unitdir}/osrt-pkglistgen@.timer
%{_unitdir}/osrt-relpkggen@.service
Expand All @@ -559,6 +566,7 @@ exit 0
%dir %attr(750,osrt-slsa,osrt-slsa) %{_sharedstatedir}/osrt-slsa/relpkggen
%dir %attr(750,osrt-staging,osrt-staging) %{_sharedstatedir}/osrt-staging
%dir %attr(750,osrt-staging,osrt-staging) %{_sharedstatedir}/osrt-staging/check-bugowner
%dir %attr(750,osrt-staging,osrt-staging) %{_sharedstatedir}/osrt-staging/git-installcheck

%files maintenance
%{_bindir}/osrt-check_maintenance_incidents
Expand Down Expand Up @@ -608,9 +616,11 @@ exit 0
%files repo-checker
%{_bindir}/osrt-project-installcheck
%{_bindir}/osrt-staging-installcheck
%{_bindir}/osrt-git-installcheck
%{_bindir}/osrt-findfileconflicts
%{_bindir}/osrt-maintenance-installcheck
%{_bindir}/osrt-write_repo_susetags_file
%{_datadir}/%{source_dir}/staginginstallchecker
%{_datadir}/%{source_dir}/project-installcheck.py
%{_datadir}/%{source_dir}/findfileconflicts
%{_datadir}/%{source_dir}/write_repo_susetags_file.pl
Expand Down
206 changes: 206 additions & 0 deletions git-installcheck.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#!/usr/bin/python3
import os
import sys
import ReviewBot

import logging

import traceback

import urllib.error

import shutil

from osc import conf
from osclib.conf import Config
from osclib.stagingapi import StagingAPI
from staginginstallchecker.installchecker import InstallChecker, CheckResult

from osclib.cache_manager import CacheManager

DEFAULT_AUTOGITS_REVIEWER = "autogits_obs_staging_bot"
DEFAULT_ARCHITECTURES = "x86_64 s390x ppc64le aarch64"

CACHEDIR = CacheManager.directory("repository-meta")


class GitInstallCheckBot(ReviewBot.ReviewBot):
"""A review bot that runs staging-installcheck on staging QA projects"""

def __init__(self, *args, **kwargs):
ReviewBot.ReviewBot.__init__(self, *args, **kwargs)

conf.get_config()

self.apiurl = conf.config["apiurl"]

self.allowed_repositories = []

# This is heavily dependent on the GITEA platform
if self.platform.name != "GITEA":
raise Exception("Unsupported platform: this bot is only supported on Gitea")

def get_git_staging_configuration(self, owner, project, commit_sha):
# FIXME: support JWCC
return self.platform.get_path(
f"repos/{owner}/{project}/raw/staging.config?ref={commit_sha}"
).json()

@staticmethod
def is_request_approved_by(request, approver):
for review in request.reviews:
if review.by == approver and review.state == "accepted":
# We skip dismissed reviews, so we can afford returning
# as soon as we find a matching review
return True

return False

@staticmethod
def get_request_from_src_rev(requests, src_rev):
for request in requests:
if request.actions[0].src_rev == src_rev:
return request

return None

def check_source_submission(
self, src_owner, src_project, src_rev, target_owner, target_package
):
self.logger.info(f"Checking {src_project}: {src_owner} -> {target_owner}")

try:
result = self.run_installcheck(
src_owner, src_project, src_rev, target_owner, target_package
)
except Exception:
self.review_messages["declined"] = (
f"Unhandled exception:\n\n```{traceback.format_exc()}```"
)
return False

if result is None:
return None
elif result.success:
self.review_messages["accepted"] = "installcheck ran successfully"
else:
self.review_messages["declined"] = "\n".join(result.comment)

return result.success

def run_installcheck(
self, src_owner, src_project, src_rev, target_owner, target_package
):
"""
Runs repo_checker.

:return: either a CheckResult, or None (should skip/retry later)
"""

request = self.get_request_from_src_rev(self.requests, src_rev)
if not request:
self.logger.warning(f"Request for src_rev {src_rev} not found")
return None

if f"{request._owner}/{request._repo}" not in self.allowed_repositories:
self.logger.info(
f"{request._owner}/{request._repo} is not in the allowed repositories list"
)
return None

base_commit = request.actions[0].tgt_rev
staging_configuration = self.get_git_staging_configuration(
target_owner, target_package, base_commit
)

main_project = staging_configuration["ObsProject"]

codestream_project = (
f"{staging_configuration['StagingProject']}:{request._pr_id}"
)

Config(self.apiurl, main_project)
target_config = conf.config[main_project]

main_repo = target_config["main-repo"]

enabled_architectures = target_config.get(
"repo_checker-arch-whitelist", DEFAULT_ARCHITECTURES
).split(" ")

approver = target_config.get("repo_checker-approver", DEFAULT_AUTOGITS_REVIEWER)
if not self.is_request_approved_by(request, approver):
return None

api = StagingAPI(self.apiurl, codestream_project)
tool = InstallChecker(api, target_config)

try:
api.get_prj_meta(codestream_project)
except urllib.error.HTTPError as e:
if e.code == 404:
return CheckResult(
success=True, comment="Staging bot didn't create a project"
)
else:
raise

try:
return tool.staging_installcheck(
codestream_project, main_repo, enabled_architectures, devel=True
)
finally:
# Clean-up dynamic PR data - in the git workflow we
# have dynamic build projects, so the repo_mirrorer's stale
# object clean-up won't trigger
project_cache = os.path.join(CACHEDIR, codestream_project)

if os.path.exists(project_cache) and not os.path.exists(
os.path.join(project_cache, ".lock")
):
# Lock being present should actually never happen - we
# are the only users, and we run the check sequentially,
# however, let's check for a lock file anyway. Better safe
# than sorry.
self.logger.debug(f"Cleaning up {project_cache}")
shutil.rmtree(project_cache)
else:
# If the lock file is present, log an error, but don't
# try to remove it
self.logger.error(
f"{project_cache} has a lock file, and cannot be removed. This shouldn't happen. Skipping cleanup"
)


class CommandLineInterface(ReviewBot.CommandLineInterface):
def __init__(self, *args, **kwargs):
super().__init__(*args, *kwargs)
self.clazz = GitInstallCheckBot

def get_optparser(self):
parser = super().get_optparser()

# Add bot-specific options
# If ReviewBot/Cmdln moves to ArgumentParser, we can turn this into a
# string directly and use nargs=*.
parser.add_option(
"--git-allow-repos",
default="",
help="allowed git repositories (e.g. products/SLFO,products/SLES)",
)

return parser

def setup_checker(self):
instance = super().setup_checker()

instance.allowed_repositories = self.options.git_allow_repos.split(",")

return instance


if __name__ == "__main__":
app = CommandLineInterface()
logging.basicConfig(level=logging.DEBUG)

sys.exit(app.main())
Loading
Loading