From aa1173f7d9be3ff8783c4eef081f0815b6baecc5 Mon Sep 17 00:00:00 2001 From: Simon Quigley Date: Tue, 3 Dec 2024 21:29:53 -0600 Subject: [PATCH] Initial commit --- .gitignore | 1 + build-packages | 408 ++++++++++++++++++++++++++++++++++++++++ common.py | 28 +++ configs/britney.conf | 126 +++++++++++++ configs/cmake.yaml | 10 + configs/kde.yaml | 306 ++++++++++++++++++++++++++++++ configs/lxqt.yaml | 45 +++++ configs/qt6.yaml | 110 +++++++++++ fetch-indexes | 161 ++++++++++++++++ grim-reaper | 64 +++++++ lintian-ppa | 167 ++++++++++++++++ pending-packages | 103 ++++++++++ run-britney | 38 ++++ systemd/britney.service | 11 ++ systemd/britney.timer | 10 + 15 files changed, 1588 insertions(+) create mode 100644 .gitignore create mode 100755 build-packages create mode 100755 common.py create mode 100644 configs/britney.conf create mode 100644 configs/cmake.yaml create mode 100644 configs/kde.yaml create mode 100644 configs/lxqt.yaml create mode 100644 configs/qt6.yaml create mode 100755 fetch-indexes create mode 100755 grim-reaper create mode 100755 lintian-ppa create mode 100755 pending-packages create mode 100755 run-britney create mode 100644 systemd/britney.service create mode 100644 systemd/britney.timer diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/build-packages b/build-packages new file mode 100755 index 0000000..85fb1f1 --- /dev/null +++ b/build-packages @@ -0,0 +1,408 @@ +#!/usr/bin/env python3 + +import subprocess +import io +import os +import sys +import yaml +import argparse +import logging +from datetime import datetime +import tarfile +import shutil +from git import Repo, GitCommandError +import tempfile +from concurrent.futures import ThreadPoolExecutor, wait, FIRST_COMPLETED +import fnmatch +import re +from debian.copyright import Header, Copyright +import uuid +from common import clean_old_logs + +BASE_DIR = "/srv/lubuntu-ci/repos" +DEBFULLNAME = "Lugito" +DEBEMAIL = "info@lubuntu.me" +OUTPUT_DIR = os.path.join(BASE_DIR, "build_output") +SUPPRESSED_LINTIAN_TAGS = [ + "orig-tarball-missing-upstream-signature", + "package-has-long-file-name", + "adopted-extended-field" +] +BASE_OUTPUT_DIR = "/srv/lubuntu-ci/output" +LOG_DIR = os.path.join(BASE_OUTPUT_DIR, "logs", "source_builds") +BASE_LINTIAN_DIR = os.path.join(BASE_OUTPUT_DIR, f"lintian.tmp.{str(uuid.uuid4())[:8]}") +REAL_LINTIAN_DIR = os.path.join(BASE_OUTPUT_DIR, "lintian") + +os.makedirs(LOG_DIR, exist_ok=True) +os.makedirs(OUTPUT_DIR, exist_ok=True) +os.makedirs(BASE_LINTIAN_DIR, exist_ok=True) + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", + handlers=[ + logging.FileHandler(log_file), + logging.StreamHandler() + ] +) +logger = logging.getLogger("TimeBasedLogger") + +def run_command(cmd, cwd=None, env=None, show_output=False): + logging.info(f"Executing: {' '.join(cmd)} in {cwd or 'current directory'}") + try: + result = subprocess.run( + cmd, + cwd=cwd, + env=env, + check=True, + capture_output=True, + text=True + ) + if show_output: + if result.stdout: + logging.info(f"Output: {result.stdout.strip()}") + if result.stderr: + logging.warning(f"Output: {result.stderr.strip()}") + logging.info(f"Command succeeded: {' '.join(cmd)}") + except subprocess.CalledProcessError as e: + logging.error(f"Command failed: {' '.join(cmd)}") + logging.error(e.stderr) + raise + +def parse_version(changelog_path): + try: + with open(changelog_path, "r") as f: + first_line = f.readline().strip() + version_match = first_line.split("(")[1].split(")")[0] + # Remove Debian revision + upstream_version = version_match.split("-")[0] + # Remove '+git...' and '~release' if present + upstream_version = re.sub(r'(\+git[0-9]+)?(~[a-z]+)?$', '', upstream_version) + logging.info(f"Upstream version extracted: {upstream_version}") + current_date = datetime.now().strftime("%Y%m%d%H%M") + version = f"{upstream_version}+git{current_date}" + logging.info(f"Parsed VERSION: {version}") + return version + except (IndexError, FileNotFoundError) as e: + logging.error(f"Error parsing version from {changelog_path}: {e}") + raise + +def get_exclusions(packaging): + exclusions = [] + with io.open(os.path.join(packaging, "debian/copyright"), "rt", encoding="utf-8") as f: + copyright_obj = Copyright(f) + for paragraph in copyright_obj.all_paragraphs(): + if isinstance(paragraph, Header): + if paragraph.files_excluded: + for file_name in paragraph.files_excluded: + exclusions.append(file_name) + break + return exclusions + +def create_tarball(name, source_dir, exclusions=[]): + tar_filename = f"{name}_MAIN.orig.tar.gz" + logging.info(f"Creating tarball: {tar_filename}") + exclusions.append(".git/") + + def exclusion_func(tarinfo): + for exclusion in exclusions: + if exclusion in tarinfo.name: + return None + + return tarinfo + + with tarfile.open(tar_filename, "w:gz") as tar: + tar.add(source_dir, arcname=os.path.basename(source_dir), filter=exclusion_func) + logging.info(f"Tarball created and compressed: {tar_filename}") + +def update_changelog(packaging_dir, release, version, env): + name = os.path.basename(packaging_dir) + logging.info(f"Updating changelog for {name} to version {version}-0ubuntu1~ppa1") + run_command(["git", "checkout", "debian/changelog"], cwd=packaging_dir) + cmd = [ + "dch", + "--distribution", release, + "--package", name, + "--newversion", f"{version}-0ubuntu1~ppa1", + "--urgency", "low", + "CI upload." + ] + run_command(cmd, cwd=packaging_dir, env=env) + +def build_package(packaging_dir, env): + name = os.path.basename(packaging_dir) + logging.info(f"Building source package for {name}") + + temp_dir = tempfile.mkdtemp() + try: + temp_packaging_dir = os.path.join(temp_dir, name) + os.makedirs(temp_packaging_dir, exist_ok=True) + shutil.copytree(packaging_dir + "/debian", temp_packaging_dir + "/debian") + + tarball_name = f"{name}_{env['VERSION']}.orig.tar.gz" + tarball_source = os.path.join(BASE_DIR, tarball_name) + tarball_dest = os.path.join(temp_dir, tarball_name) + shutil.copyfile(tarball_source, tarball_dest) + + cmd_build = ["debuild", "--no-lintian", "-S", "-d", "-sa"] + run_command(cmd_build, cwd=temp_packaging_dir, env=env) + run_command(["git", "checkout", "debian/changelog"], cwd=packaging_dir) + + pattern = f"{name}_{env['VERSION']}*" + for filename in os.listdir(temp_dir): + if fnmatch.fnmatch(filename, pattern): + source_file = os.path.join(temp_dir, filename) + dest_file = os.path.join(OUTPUT_DIR, filename) + shutil.copyfile(source_file, dest_file) + logging.info(f"Copied {filename} to {OUTPUT_DIR}") + + changes_files = [f for f in os.listdir(OUTPUT_DIR) if f.startswith(f"{name}_{env['VERSION']}") and f.endswith("_source.changes")] + if changes_files: + changes_file = os.path.join(OUTPUT_DIR, changes_files[-1]) + logging.info(f"Built package, changes file: {changes_file}") + return changes_file + else: + logging.error("No changes file found after build.") + raise FileNotFoundError("Changes file not found.") + finally: + shutil.rmtree(temp_dir) + +def load_config(config_path): + try: + with open(config_path, "r") as f: + config = yaml.safe_load(f) + if "packages" not in config or "releases" not in config: + raise ValueError("Config file must contain 'packages' and 'releases' sections.") + return config + except Exception as e: + logging.error(f"Error loading config file: {e}") + sys.exit(1) + +def clone_or_update_repo(destination, repo_url, repo_branch=None): + if os.path.exists(destination): + logging.info(f"Repository already exists at {destination}, checking branch and remote URL.") + try: + repo = Repo(destination) + + current_remote_url = repo.remotes.origin.url + if current_remote_url != repo_url: + logging.info(f"Remote URL differs for {destination}. Removing and recloning.") + shutil.rmtree(destination) + else: + repo.git.reset("--hard", "HEAD") + current_branch = repo.active_branch.name + if repo_branch and current_branch != repo_branch: + logging.info(f"Branch differs for {destination}. Removing and recloning.") + shutil.rmtree(destination) + else: + logging.info(f"Repository matches desired remote and branch, pulling updates.") + repo.git.checkout(repo_branch or current_branch) + try: + repo.remotes.origin.pull() + repo.submodule_update(recursive=True) + logging.info(f"Pulled latest changes for {destination}") + except GitCommandError as e: + if 'non-fast-forward' in str(e): + logging.error(f"Pull failed due to non-fast-forward update: {e}") + logging.info(f"Removing repository {destination} and cloning again.") + shutil.rmtree(destination) + else: + logging.error(f"Pull failed for {destination}: {e}") + raise + else: + return + except Exception as e: + logging.error(f"Error updating repository {destination}: {e}") + logging.info(f"Removing repository {destination} and cloning again.") + shutil.rmtree(destination) + try: + logging.info(f"Cloning repository {repo_url} into {destination}") + repo = Repo.clone_from(repo_url, destination, recurse_submodules=True) + if repo_branch: + repo.git.checkout(repo_branch) + logging.info(f"Checked out {repo_branch} in {destination}") + except GitCommandError as e: + logging.error(f"Git clone failed for {repo_url}: {e}") + raise + +def publish_lintian(): + if os.path.exists(BASE_LINTIAN_DIR): + for root, dirs, files in os.walk(BASE_LINTIAN_DIR): + for file in files: + # Determine the source and destination paths + src_path = os.path.join(root, file) + rel_path = os.path.relpath(src_path, BASE_LINTIAN_DIR) + dest_path = os.path.join(REAL_LINTIAN_DIR, rel_path) + + # Ensure the destination directory exists + os.makedirs(os.path.dirname(dest_path), exist_ok=True) + + # Copy the file + shutil.copy2(src_path, dest_path) + + # Remove the temporary directory + shutil.rmtree(BASE_LINTIAN_DIR) + +def run_source_lintian(name, sources_path): + logging.info(f"Running Lintian for {name}") + with tempfile.NamedTemporaryFile(mode='w+', suffix='.txt') as temp_file: + temp_file.write("\n".join(SUPPRESSED_LINTIAN_TAGS)) + temp_file.flush() + temp_file_path = temp_file.name + + cmd = [ + "lintian", + "-EvIL", + "+pedantic", + "--suppress-tags-from-file", + f"{temp_file_path}", + sources_path + ] + + result = subprocess.run( + cmd, + capture_output=True, + text=True + ) + + stderr, stdout = None, None + if result.stderr: + stderr = result.stderr.strip() + if result.stdout: + stdout = result.stdout.strip() + + lintian_output = None + if stderr == stdout: + lintian_output = stderr + else: + lintian_output = f"{stderr}\n{stdout}".strip() + + if lintian_output: + pkgdir = os.path.join(BASE_LINTIAN_DIR, name) + if not os.path.exists(pkgdir): + os.mkdir(pkgdir) + output_file = os.path.join(pkgdir, "source.txt") + with open(output_file, "a") as f: + f.write(lintian_output) + + logging.info(f"Lintian run for {name} is complete") + +def main(): + parser = argparse.ArgumentParser(description="Automate Lubuntu package builds.") + parser.add_argument("config", help="Path to the YAML configuration file.") + parser.add_argument("--skip-dput", action="store_true", help="Skip the dput upload step.") + parser.add_argument("--skip-cleanup", action="store_true", help="Skip removal of build_output.") + args = parser.parse_args() + + config = load_config(args.config) + packages = config["packages"] + releases = config["releases"] + + os.makedirs(BASE_DIR, exist_ok=True) + logging.info(f"Using base directory: {BASE_DIR}") + os.chdir(BASE_DIR) + + with ThreadPoolExecutor(max_workers=5) as executor: + def dput_source(name, upload_target, changes_files, devel_changes_files): + if changes_files: + hr_changes = ", ".join(changes_files) + logging.info(f"Uploading {hr_changes} to {upload_target} using dput") + cmd_upload = ["dput", upload_target] + changes_files + run_command(cmd_upload, cwd=OUTPUT_DIR) + logging.info(f"Completed upload of {hr_changes} to {upload_target}") + + for file in devel_changes_files: + if file: + futures.add(executor.submit(run_source_lintian, name, file)) + + def prepare_package(pkg): + name = pkg.get("name") + if not name: + logging.warning(f"Skipping package due to missing name: {pkg}") + return + upstream_url = pkg.get("upstream_url") or f"https://github.com/lxqt/{name}.git" + upstream_destination = os.path.join(BASE_DIR, f"upstream-{name}") + clone_or_update_repo(upstream_destination, upstream_url) + packaging_url = pkg.get("packaging_url") or f"https://git.lubuntu.me/Lubuntu/{name}-packaging.git" + packaging_branch = pkg.get("packaging_branch") or f"ubuntu/{releases[0]}" if releases else None + packaging_destination = os.path.join(BASE_DIR, name) + clone_or_update_repo(packaging_destination, packaging_url, packaging_branch) + exclusions = get_exclusions(packaging_destination) + create_tarball(name, upstream_destination, exclusions) + run_command(["update-maintainer"], cwd=packaging_destination) + futures.add(executor.submit(process_package, pkg)) + + def process_package(pkg): + name = pkg.get("name") + upload_target = pkg.get("upload_target", "ppa:lubuntu-ci/unstable-ci-proposed") + + if not name: + logging.warning(f"Skipping package due to missing name: {pkg}") + return [] + + package_changes = [] + + packaging_destination = os.path.join(BASE_DIR, name) + changelog_path = os.path.join(packaging_destination, "debian", "changelog") + version = parse_version(changelog_path) + + for release in releases: + logging.info(f"Building {name} for {release}") + try: + release_version = f"{version}~{release}" + tarball_name = f"{name}_{release_version}.orig.tar.gz" + tarball_source = os.path.join(BASE_DIR, f"{name}_MAIN.orig.tar.gz") + tarball_dest = os.path.join(BASE_DIR, tarball_name) + shutil.copyfile(tarball_source, tarball_dest) + + env = os.environ.copy() + env["DEBFULLNAME"] = DEBFULLNAME + env["DEBEMAIL"] = DEBEMAIL + env["VERSION"] = release_version + env["UPLOAD_TARGET"] = upload_target + + # Update changelog and build package + update_changelog(packaging_destination, release, release_version, env) + changes_file = build_package(packaging_destination, env) + if changes_file: + package_changes.append((changes_file, env)) + os.remove(os.path.join(BASE_DIR, tarball_name)) + + except Exception as e: + logging.error(f"Error processing package '{name}' for release '{release}': {e}") + + changes_files = [os.path.basename(cf) for cf, env in package_changes] + devel_changes_files = set(os.path.join(OUTPUT_DIR, file) if releases[0] in file else None for file in changes_files) + if args.skip_dput: + for changes_file in devel_changes_files: + if changes_file: + futures.add(executor.submit(run_source_lintian, name, changes_file)) + else: + upload_target = package_changes[0][1]["UPLOAD_TARGET"] + futures.add(executor.submit(dput_source, name, upload_target, changes_files, devel_changes_files)) + + os.remove(os.path.join(BASE_DIR, f"{name}_MAIN.orig.tar.gz")) + + futures = set(executor.submit(prepare_package, pkg) for pkg in packages) + + while futures: + done, not_done = wait(futures, return_when=FIRST_COMPLETED) + + for future in done: + try: + result = future.result() + except Exception as e: + logging.exception("Task generated an exception") + finally: + futures.remove(future) + + if not args.skip_cleanup: + shutil.rmtree(OUTPUT_DIR) + logging.info("Publishing Lintian output...") + publish_lintian() + clean_old_logs(LOG_DIR) + + logging.info("Script completed successfully.") + +if __name__ == "__main__": + main() diff --git a/common.py b/common.py new file mode 100755 index 0000000..92c78aa --- /dev/null +++ b/common.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 Simon Quigley +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +from datetime import datetime + +def clean_old_logs(log_dir, max_age_seconds=86400): + now = datetime.utcnow() + for file_name in os.listdir(log_dir): + file_path = os.path.join(log_dir, file_name) + if os.path.isfile(file_path): + file_age = now - os.path.getmtime(file_path) + if file_age > max_age_seconds: + os.remove(file_path) diff --git a/configs/britney.conf b/configs/britney.conf new file mode 100644 index 0000000..59da571 --- /dev/null +++ b/configs/britney.conf @@ -0,0 +1,126 @@ +# Configuration file for britney + +# Paths for control files +TESTING = data/%(SERIES) +UNSTABLE = data/%(SERIES)-proposed +PARTIAL_UNSTABLE = yes + +# Output +NONINST_STATUS = data/%(SERIES)/non-installable-status +EXCUSES_OUTPUT = output/%(SERIES)/excuses.html +EXCUSES_YAML_OUTPUT = output/%(SERIES)/excuses.yaml.xz +UPGRADE_OUTPUT = output/%(SERIES)/output.txt +HEIDI_OUTPUT = output/%(SERIES)/HeidiResult + +# External policy/constraints/faux-packages information that +# (presumably) rarely changes. Examples include "constraints". +STATIC_INPUT_DIR = data/%(SERIES)/input + +# Directory for input files that Britney will update herself +# (e.g. aging information) or will need regular updates +# (e.g. urgency information). +STATE_DIR = data/%(SERIES)/state + +# List of architectures that Britney should consider. +# - defaults to the value in testing's Release file (if it is present). +# - Required for the legacy layout. +ARCHITECTURES = amd64 arm64 armhf ppc64el riscv64 s390x + +# if you're not in this list, arch: all packages are allowed to break on you +NOBREAKALL_ARCHES = amd64 + +# primary architecture used for checking Build-Depends-Indep +ALL_BUILDARCH = amd64 + +# is arch-all built separately? i.e. can it fail independently of another arch? +HAS_ARCH_ALL_BUILDDS = no + +# if you're in this list, your packages may not stay in sync with the source +OUTOFSYNC_ARCHES = + +# if you're in this list, your uninstallability count may increase +BREAK_ARCHES = + +# if you're in this list, you are a new architecture +NEW_ARCHES = + +# priorities and delays +MINDAYS_LOW = 0 +MINDAYS_MEDIUM = 0 +MINDAYS_HIGH = 0 +MINDAYS_CRITICAL = 0 +MINDAYS_EMERGENCY = 0 +DEFAULT_URGENCY = medium +NO_PENALTIES = high critical emergency +BOUNTY_MIN_AGE = 2 + +HINTSDIR = data/%(SERIES)-proposed/Hints + +# hint permissions +HINTS_LANEY = ALL +HINTS_STEFANOR = ALL +HINTS_STGRABER = ALL +HINTS_VORLON = ALL +HINTS_PITTI = ALL +HINTS_UBUNTU-RELEASE = ALL +# Kernel team automated testing +HINTS_KERNEL-TESTING = block unblock +# SRU team +HINTS_APW = ALL +HINTS_ARGES = ALL +HINTS_BRIAN-MURRAY = ALL +HINTS_RACB = ALL +HINTS_RAOF = ALL +HINTS_SIL2100 = ALL +HINTS_TJAALTON = ALL +HINTS_UBUNTU-SRU = ALL +HINTS_FREEZE = block block-all + +# support for old libraries in testing (smooth update) +# use ALL to enable smooth updates for all the sections +# +# naming a non-existent section will effectively disable new smooth +# updates but still allow removals to occur +SMOOTH_UPDATES = libs oldlibs + +IGNORE_CRUFT = 0 + +REMOVE_OBSOLETE = no + +CHECK_BUILDD = nxo + +IMPLICIT_DEPS = no + +ADT_ENABLE = no +#ADT_ARCHES = amd64 i386 armhf ppc64el arm64 +#ADT_AMQP = amqp://test_request:password@autopkgtest-amqp.internal +# space separate list of PPAs to add for test requests and for polling results; +# the *last* one determines the swift container name +ADT_PPAS = +# set this to the path of a (r/o) autopkgtest-results.cache for running many parallel +# britney instances for PPAs without updating the cache +ADT_SHARED_RESULTS_CACHE = +# Swift base URL with the results (must be publicly readable and browsable) +# or file location if results are pre-fetched +#ADT_SWIFT_URL = https://objectstorage.prodstack5.canonical.com/swift/v1/AUTH_0f9aae918d5b4744bf7b827671c86842/ +# Base URL for autopkgtest site, used for links in the excuses +#ADT_CI_URL = https://autopkgtest.ubuntu.com/ +# URL for the autopkgtest database, if used +#ADT_DB_URL = https://autopkgtest.ubuntu.com/static/autopkgtest.db +#ADT_HUGE = 20 + +# Autopkgtest results can be used to influence the aging +ADT_REGRESSION_PENALTY = +ADT_SUCCESS_BOUNTY = +ADT_BASELINE = reference +ADT_RETRY_URL_MECH = +ADT_RETRY_OLDER_THAN = +ADT_REFERENCE_MAX_AGE = + +# email uploaders for stuck uploads +EMAIL_ENABLE = no +# email SRU bugs when regressions are detected +SRUREGRESSIONEMAIL_ENABLE = no + +# we don't run piuparts testing in Ubuntu +PIUPARTS_ENABLE = no diff --git a/configs/cmake.yaml b/configs/cmake.yaml new file mode 100644 index 0000000..5d133f0 --- /dev/null +++ b/configs/cmake.yaml @@ -0,0 +1,10 @@ +packages: + - name: cmake + upstream_url: "https://gitlab.kitware.com/cmake/cmake.git" + packaging_url: "https://git.lubuntu.me/Lubuntu/cmake.git" + packaging_branch: "ci/unstable" + +releases: + - plucky + - oracular + - noble diff --git a/configs/kde.yaml b/configs/kde.yaml new file mode 100644 index 0000000..ac5b4de --- /dev/null +++ b/configs/kde.yaml @@ -0,0 +1,306 @@ +packages: + - name: kf6-extra-cmake-modules + upstream_url: "https://invent.kde.org/frameworks/extra-cmake-modules.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-extra-cmake-modules" + packaging_branch: "kubuntu_unstable" + - name: kf6-attica + upstream_url: "https://invent.kde.org/frameworks/attica.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-attica" + packaging_branch: "kubuntu_unstable" + - name: kf6-baloo + upstream_url: "https://invent.kde.org/frameworks/baloo.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-baloo" + packaging_branch: "kubuntu_unstable" + - name: kf6-bluez-qt + upstream_url: "https://invent.kde.org/frameworks/bluez-qt.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-bluez-qt" + packaging_branch: "kubuntu_unstable" + - name: kf6-breeze-icons + upstream_url: "https://invent.kde.org/frameworks/breeze-icons.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-breeze-icons" + packaging_branch: "kubuntu_unstable" + - name: kf6-frameworkintegration + upstream_url: "https://invent.kde.org/frameworks/frameworkintegration.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-frameworkintegration" + packaging_branch: "kubuntu_unstable" + - name: kf6-kapidox + upstream_url: "https://invent.kde.org/frameworks/kapidox.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kapidox" + packaging_branch: "kubuntu_unstable" + - name: kf6-karchive + upstream_url: "https://invent.kde.org/frameworks/karchive.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-karchive" + packaging_branch: "kubuntu_unstable" + - name: kf6-kauth + upstream_url: "https://invent.kde.org/frameworks/kauth.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kauth" + packaging_branch: "kubuntu_unstable" + - name: kf6-kbookmarks + upstream_url: "https://invent.kde.org/frameworks/kbookmarks.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kbookmarks" + packaging_branch: "kubuntu_unstable" + - name: kf6-kcalendarcore + upstream_url: "https://invent.kde.org/frameworks/kcalendarcore.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kcalendarcore" + packaging_branch: "kubuntu_unstable" + - name: kf6-kcmutils + upstream_url: "https://invent.kde.org/frameworks/kcmutils.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kcmutils" + packaging_branch: "kubuntu_unstable" + - name: kf6-kcodecs + upstream_url: "https://invent.kde.org/frameworks/kcodecs.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kcodecs" + packaging_branch: "kubuntu_unstable" + - name: kf6-kcolorscheme + upstream_url: "https://invent.kde.org/frameworks/kcolorscheme.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kcolorscheme" + packaging_branch: "kubuntu_unstable" + - name: kf6-kcompletion + upstream_url: "https://invent.kde.org/frameworks/kcompletion.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kcompletion" + packaging_branch: "kubuntu_unstable" + - name: kf6-kconfig + upstream_url: "https://invent.kde.org/frameworks/kconfig.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kconfig" + packaging_branch: "kubuntu_unstable" + - name: kf6-kconfigwidgets + upstream_url: "https://invent.kde.org/frameworks/kconfigwidgets.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kconfigwidgets" + packaging_branch: "kubuntu_unstable" + - name: kf6-kcoreaddons + upstream_url: "https://invent.kde.org/frameworks/kcoreaddons.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kcoreaddons" + packaging_branch: "kubuntu_unstable" + - name: kf6-kcrash + upstream_url: "https://invent.kde.org/frameworks/kcrash.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kcrash" + packaging_branch: "kubuntu_unstable" + - name: kf6-kdbusaddons + upstream_url: "https://invent.kde.org/frameworks/kdbusaddons.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kdbusaddons" + packaging_branch: "kubuntu_unstable" + - name: kf6-kdeclarative + upstream_url: "https://invent.kde.org/frameworks/kdeclarative.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kdeclarative" + packaging_branch: "kubuntu_unstable" + - name: kf6-kded + upstream_url: "https://invent.kde.org/frameworks/kded.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kded" + packaging_branch: "kubuntu_unstable" + - name: kf6-kdesu + upstream_url: "https://invent.kde.org/frameworks/kdesu.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kdesu" + packaging_branch: "kubuntu_unstable" + - name: kf6-kdnssd + upstream_url: "https://invent.kde.org/frameworks/kdnssd.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kdnssd" + packaging_branch: "kubuntu_unstable" + - name: kf6-kdoctools + upstream_url: "https://invent.kde.org/frameworks/kdoctools.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kdoctools" + packaging_branch: "kubuntu_unstable" + - name: kf6-kfilemetadata + upstream_url: "https://invent.kde.org/frameworks/kfilemetadata.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kfilemetadata" + packaging_branch: "kubuntu_unstable" + - name: kf6-kglobalaccel + upstream_url: "https://invent.kde.org/frameworks/kglobalaccel.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kglobalaccel" + packaging_branch: "kubuntu_unstable" + - name: kf6-kguiaddons + upstream_url: "https://invent.kde.org/frameworks/kguiaddons.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kguiaddons" + packaging_branch: "kubuntu_unstable" + - name: kf6-kholidays + upstream_url: "https://invent.kde.org/frameworks/kholidays.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kholidays" + packaging_branch: "kubuntu_unstable" + - name: kf6-ki18n + upstream_url: "https://invent.kde.org/frameworks/ki18n.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-ki18n" + packaging_branch: "kubuntu_unstable" + - name: kf6-kiconthemes + upstream_url: "https://invent.kde.org/frameworks/kiconthemes.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kiconthemes" + packaging_branch: "kubuntu_unstable" + - name: kf6-kidletime + upstream_url: "https://invent.kde.org/frameworks/kidletime.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kidletime" + packaging_branch: "kubuntu_unstable" + - name: kf6-kimageformats + upstream_url: "https://invent.kde.org/frameworks/kimageformats.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kimageformats" + packaging_branch: "kubuntu_unstable" + - name: kf6-kio + upstream_url: "https://invent.kde.org/frameworks/kio.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kio" + packaging_branch: "kubuntu_unstable" + - name: kf6-kirigami + upstream_url: "https://invent.kde.org/frameworks/kirigami.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kirigami" + packaging_branch: "kubuntu_unstable" + - name: kf6-kitemmodels + upstream_url: "https://invent.kde.org/frameworks/kitemmodels.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kitemmodels" + packaging_branch: "kubuntu_unstable" + - name: kf6-kitemviews + upstream_url: "https://invent.kde.org/frameworks/kitemviews.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kitemviews" + packaging_branch: "kubuntu_unstable" + - name: kf6-kjobwidgets + upstream_url: "https://invent.kde.org/frameworks/kjobwidgets.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kjobwidgets" + packaging_branch: "kubuntu_unstable" + - name: kf6-knewstuff + upstream_url: "https://invent.kde.org/frameworks/knewstuff.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-knewstuff" + packaging_branch: "kubuntu_unstable" + - name: kf6-knotifications + upstream_url: "https://invent.kde.org/frameworks/knotifications.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-knotifications" + packaging_branch: "kubuntu_unstable" + - name: kf6-knotifyconfig + upstream_url: "https://invent.kde.org/frameworks/knotifyconfig.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-knotifyconfig" + packaging_branch: "kubuntu_unstable" + - name: kf6-kpackage + upstream_url: "https://invent.kde.org/frameworks/kpackage.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kpackage" + packaging_branch: "kubuntu_unstable" + - name: kf6-kparts + upstream_url: "https://invent.kde.org/frameworks/kparts.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kparts" + packaging_branch: "kubuntu_unstable" + - name: kf6-kpeople + upstream_url: "https://invent.kde.org/frameworks/kpeople.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kpeople" + packaging_branch: "kubuntu_unstable" + - name: kf6-kplotting + upstream_url: "https://invent.kde.org/frameworks/kplotting.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kplotting" + packaging_branch: "kubuntu_unstable" + - name: kf6-kpty + upstream_url: "https://invent.kde.org/frameworks/kpty.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kpty" + packaging_branch: "kubuntu_unstable" + - name: kf6-kquickcharts + upstream_url: "https://invent.kde.org/frameworks/kquickcharts.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kquickcharts" + packaging_branch: "kubuntu_unstable" + - name: kf6-krunner + upstream_url: "https://invent.kde.org/frameworks/krunner.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-krunner" + packaging_branch: "kubuntu_unstable" + - name: kf6-kservice + upstream_url: "https://invent.kde.org/frameworks/kservice.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kservice" + packaging_branch: "kubuntu_unstable" + - name: kf6-kstatusnotifieritem + upstream_url: "https://invent.kde.org/frameworks/kstatusnotifieritem.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kstatusnotifieritem" + packaging_branch: "kubuntu_unstable" + - name: kf6-ksvg + upstream_url: "https://invent.kde.org/frameworks/ksvg.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-ksvg" + packaging_branch: "kubuntu_unstable" + - name: kf6-ktexteditor + upstream_url: "https://invent.kde.org/frameworks/ktexteditor.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-ktexteditor" + packaging_branch: "kubuntu_unstable" + - name: kf6-ktexttemplate + upstream_url: "https://invent.kde.org/frameworks/ktexttemplate.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-ktexttemplate" + packaging_branch: "kubuntu_unstable" + - name: kf6-ktextwidgets + upstream_url: "https://invent.kde.org/frameworks/ktextwidgets.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-ktextwidgets" + packaging_branch: "kubuntu_unstable" + - name: kf6-kunitconversion + upstream_url: "https://invent.kde.org/frameworks/kunitconversion.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kunitconversion" + packaging_branch: "kubuntu_unstable" + - name: kf6-kuserfeedback + upstream_url: "https://invent.kde.org/frameworks/kuserfeedback.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kuserfeedback" + packaging_branch: "kubuntu_unstable" + - name: kf6-kwallet + upstream_url: "https://invent.kde.org/frameworks/kwallet.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kwallet" + packaging_branch: "kubuntu_unstable" + - name: kf6-kwidgetsaddons + upstream_url: "https://invent.kde.org/frameworks/kwidgetsaddons.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kwidgetsaddons" + packaging_branch: "kubuntu_unstable" + - name: kf6-kwindowsystem + upstream_url: "https://invent.kde.org/frameworks/kwindowsystem.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kwindowsystem" + packaging_branch: "kubuntu_unstable" + - name: kf6-kxmlgui + upstream_url: "https://invent.kde.org/frameworks/kxmlgui.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-kxmlgui" + packaging_branch: "kubuntu_unstable" + - name: kf6-modemmanager-qt + upstream_url: "https://invent.kde.org/frameworks/modemmanager-qt.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-modemmanager-qt" + packaging_branch: "kubuntu_unstable" + - name: kf6-networkmanager-qt + upstream_url: "https://invent.kde.org/frameworks/networkmanager-qt.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-networkmanager-qt" + packaging_branch: "kubuntu_unstable" + - name: kf6-prison + upstream_url: "https://invent.kde.org/frameworks/prison.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-prison" + packaging_branch: "kubuntu_unstable" + - name: kf6-purpose + upstream_url: "https://invent.kde.org/frameworks/purpose.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-purpose" + packaging_branch: "kubuntu_unstable" + - name: kf6-qqc2-desktop-style + upstream_url: "https://invent.kde.org/frameworks/qqc2-desktop-style.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-qqc2-desktop-style" + packaging_branch: "kubuntu_unstable" + - name: kf6-solid + upstream_url: "https://invent.kde.org/frameworks/solid.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-solid" + packaging_branch: "kubuntu_unstable" + - name: kf6-sonnet + upstream_url: "https://invent.kde.org/frameworks/sonnet.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-sonnet" + packaging_branch: "kubuntu_unstable" + - name: kf6-syndication + upstream_url: "https://invent.kde.org/frameworks/syndication.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-syndication" + packaging_branch: "kubuntu_unstable" + - name: kf6-syntax-highlighting + upstream_url: "https://invent.kde.org/frameworks/syntax-highlighting.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-syntax-highlighting" + packaging_branch: "kubuntu_unstable" + - name: kf6-threadweaver + upstream_url: "https://invent.kde.org/frameworks/threadweaver.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kf6-threadweaver" + packaging_branch: "kubuntu_unstable" + - name: kpmcore + upstream_url: "https://invent.kde.org/system/kpmcore.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kpmcore" + packaging_branch: "kubuntu_unstable" + - name: plasma-discover + upstream_url: "https://invent.kde.org/plasma/discover.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/discover" + packaging_branch: "kubuntu_unstable" + - name: skanlite + upstream_url: "https://invent.kde.org/graphics/skanlite.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/skanlite" + packaging_branch: "kubuntu_unstable" + - name: libksane + upstream_url: "https://invent.kde.org/graphics/libksane.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/libksane" + packaging_branch: "kubuntu_unstable" + - name: ksanecore + upstream_url: "https://invent.kde.org/libraries/ksanecore.git" + packaging_url: "https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/ksanecore" + packaging_branch: "kubuntu_unstable" + +releases: + - plucky + - oracular + - noble diff --git a/configs/lxqt.yaml b/configs/lxqt.yaml new file mode 100644 index 0000000..3be9461 --- /dev/null +++ b/configs/lxqt.yaml @@ -0,0 +1,45 @@ +packages: + - name: lxqt-build-tools + - name: libdbusmenu-lxqt + packaging_branch: "ci/unstable" + - name: libqtxdg + - name: lxqt-menu-data + - name: liblxqt + - name: libsysstat + - name: qtxdg-tools + - name: libfm-qt + - name: lxqt-globalkeys + - name: lxqt-qtplugin + - name: qtermwidget + - name: lxqt-panel + - name: pcmanfm-qt + - name: qterminal + - name: lxqt-powermanagement + - name: lxqt-runner + - name: lxqt-themes + - name: lxqt-admin + - name: lxqt-notificationd + - name: lxqt-about + - name: lxqt-config + - name: lxqt-policykit + - name: lxqt-sudo + - name: lxqt-openssh-askpass + - name: lxqt-session + - name: pavucontrol-qt + - name: xdg-desktop-portal-lxqt + - name: lxqt-archiver + - name: screengrab + - name: lximage-qt + - name: qps + - name: obconf-qt + - name: nm-tray + upstream_url: "https://github.com/palinek/nm-tray.git" + - name: calamares + upstream_url: "https://github.com/calamares/calamares.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/ubuntu/+source/calamares/+git/calamares" + packaging_branch: "ci/unstable" + +releases: + - plucky + - oracular + - noble diff --git a/configs/qt6.yaml b/configs/qt6.yaml new file mode 100644 index 0000000..f8ac18a --- /dev/null +++ b/configs/qt6.yaml @@ -0,0 +1,110 @@ +packages: + - name: qt6-base + upstream_url: "https://code.qt.io/qt/qtbase.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-base" + packaging_branch: "ci/unstable" + - name: qt6-imageformats + upstream_url: "https://code.qt.io/qt/qtimageformats.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-imageformats" + packaging_branch: "ci/unstable" + - name: qt6-languageserver + upstream_url: "https://code.qt.io/qt/qtlanguageserver.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-languageserver" + packaging_branch: "ci/unstable" + - name: qt6-shadertools + upstream_url: "https://code.qt.io/qt/qtshadertools.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-shadertools" + packaging_branch: "ci/unstable" + - name: qt6-svg + upstream_url: "https://code.qt.io/qt/qtsvg.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-svg" + packaging_branch: "ci/unstable" + - name: qt6-networkauth + upstream_url: "https://code.qt.io/qt/qtnetworkauth.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-networkauth" + packaging_branch: "ci/unstable" + - name: qt6-serialport + upstream_url: "https://code.qt.io/qt/qtserialport.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-serialport" + packaging_branch: "ci/unstable" + - name: qt6-declarative + upstream_url: "https://code.qt.io/qt/qtdeclarative.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-declarative" + packaging_branch: "ci/unstable" + - name: qt6-lottie + upstream_url: "https://code.qt.io/qt/qtlottie.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-lottie" + packaging_branch: "ci/unstable" + - name: qt6-websockets + upstream_url: "https://code.qt.io/qt/qtwebsockets.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-websockets" + packaging_branch: "ci/unstable" + - name: qt6-5compat + upstream_url: "https://code.qt.io/qt/qt5compat.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-5compat" + packaging_branch: "ci/unstable" + - name: qt6-connectivity + upstream_url: "https://code.qt.io/qt/qtconnectivity.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-connectivity" + packaging_branch: "ci/unstable" + - name: qt6-scxml + upstream_url: "https://code.qt.io/qt/qtscxml.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-scxml" + packaging_branch: "ci/unstable" + - name: qt6-sensors + upstream_url: "https://code.qt.io/qt/qtsensors.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-sensors" + packaging_branch: "ci/unstable" + - name: qt6-wayland + upstream_url: "https://code.qt.io/qt/qtwayland.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-wayland" + packaging_branch: "ci/unstable" + - name: qt6-datavis3d + upstream_url: "https://code.qt.io/qt/qtdatavis3d.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-datavis3d" + packaging_branch: "ci/unstable" + - name: qt6-grpc + upstream_url: "https://code.qt.io/qt/qtgrpc.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-grpc" + packaging_branch: "ci/unstable" + - name: qt6-positioning + upstream_url: "https://code.qt.io/qt/qtpositioning.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-positioning" + packaging_branch: "ci/unstable" + - name: qt6-quicktimeline + upstream_url: "https://code.qt.io/qt/qtquicktimeline.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-quicktimeline" + packaging_branch: "ci/unstable" + - name: qt6-serialbus + upstream_url: "https://code.qt.io/qt/qtserialbus.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-serialbus" + packaging_branch: "ci/unstable" + - name: qt6-tools + upstream_url: "https://code.qt.io/qt/qttools.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-tools" + packaging_branch: "ci/unstable" + - name: qt6-webchannel + upstream_url: "https://code.qt.io/qt/qtwebchannel.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-webchannel" + packaging_branch: "ci/unstable" + - name: qt6-httpserver + upstream_url: "https://code.qt.io/qt/qthttpserver.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-httpserver" + packaging_branch: "ci/unstable" + - name: qt6-remoteobjects + upstream_url: "https://code.qt.io/qt/qtremoteobjects.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-remoteobjects" + packaging_branch: "ci/unstable" + - name: qt6-location + upstream_url: "https://code.qt.io/qt/qtlocation.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-location" + packaging_branch: "ci/unstable" + - name: qt6-translations + upstream_url: "https://code.qt.io/qt/qttranslations.git" + packaging_url: "https://git.launchpad.net/~ubuntu-qt-code/+git/qt6-translations" + packaging_branch: "ci/unstable" + +releases: + - plucky + - oracular + - noble diff --git a/fetch-indexes b/fetch-indexes new file mode 100755 index 0000000..1a86750 --- /dev/null +++ b/fetch-indexes @@ -0,0 +1,161 @@ +#!/bin/bash +# download current package indexes to data/{,-proposed}/ for running +# britney against a PPA. The PPA will play the role of "-proposed" (i. e. +# "unstable" in britney terms, containing the updated packages to test), the +# Ubuntu archive has the "-release" part (i. e. "testing" in britney terms, in +# which the -proposed packages are being landed). +# +# Copyright (C) 2019-2024 Simon Quigley +# Copyright (C) Canonical Ltd +# Author: Martin Pitt +# Author: Robert Bruce Park +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set -u + +./pending-packages $RELEASE || exit 0 + +export MAIN_ARCHIVE="http://us.archive.ubuntu.com/ubuntu/dists/" +export PORTS_ARCHIVE="http://us.ports.ubuntu.com/ubuntu-ports/dists/" +export LP_TEAM="lubuntu-ci" +export SOURCE_PPA="unstable-ci-proposed" +export DEST_PPA="unstable-ci" +export SOURCE_PPA_URL="https://ppa.launchpadcontent.net/$LP_TEAM/$SOURCE_PPA/ubuntu/dists/$RELEASE/main"; +export DEST_PPA_URL="https://ppa.launchpadcontent.net/$LP_TEAM/$DEST_PPA/ubuntu/dists/$RELEASE/main"; +export ARCHES="amd64" +export PORTS_ARCHES="arm64 armhf ppc64el riscv64 s390x" +export BRITNEY_CACHE="cache/" +export BRITNEY_DATADIR="data/" +export BRITNEY_OUTDIR="output/" +export BRITNEY_HINTDIR="../hints-ubuntu/" +export BRITNEY_LOC="/srv/lubuntu-ci/repos/britney2-ubuntu/britney.py" +export BRITNEY_TIMESTAMP=$(date +"%Y-%m-%d_%H:%M:%S") + +echo "Release: $RELEASE"; +echo "Timestamp: $BRITNEY_TIMESTAMP" + +# Download files in parallel in background, only if there is an update +refresh() { + DIR=$BRITNEY_CACHE/$pocket/$(echo $1 | rev | cut --delimiter=/ --fields=2,3 | rev) + mkdir --parents $DIR + touch --no-create $BRITNEY_CACHE $BRITNEY_CACHE/$pocket "$(dirname $DIR)" $DIR # Timestamp thwarts expire.sh + wget --directory-prefix $DIR --timestamping $1 --append-output $DIR/$$-wget-log --no-verbose & +} + +echo 'Refreshing package indexes...' + +for pocket in $RELEASE $RELEASE-updates; do + for component in main restricted universe multiverse; do + for arch in $ARCHES; do + refresh $MAIN_ARCHIVE/$pocket/$component/binary-$arch/Packages.gz + done + for arch in $PORTS_ARCHES; do + refresh $PORTS_ARCHIVE/$pocket/$component/binary-$arch/Packages.gz + done + refresh $MAIN_ARCHIVE/$pocket/$component/source/Sources.gz + done +done + +# Treat the destination PPA as just another pocket +for pocket in $RELEASE-ppa-proposed; do + for arch in $ARCHES $PORTS_ARCHES; do + refresh $DEST_PPA_URL/source/Sources.gz + refresh $DEST_PPA_URL/binary-$arch/Packages.gz + done +done + +# Get the source PPA +pocket=$SOURCE_PPA-$RELEASE +for arch in $ARCHES $PORTS_ARCHES; do + refresh $SOURCE_PPA_URL/binary-$arch/Packages.gz +done +refresh $SOURCE_PPA_URL/source/Sources.gz + +wait # for wgets to finish + +find $BRITNEY_DATADIR -name "$$-wget-log*" -exec cat '{}' \; -delete 1>&2 + +echo 'Building britney indexes...' + +mkdir --parents "$BRITNEY_OUTDIR/$BRITNEY_TIMESTAMP/" + +# "Unstable" is SOURCE_PPA +DEST=$BRITNEY_DATADIR/$RELEASE-proposed +mkdir --parents $DEST +mkdir -pv $BRITNEY_DATADIR/$RELEASE-proposed/state/ +touch $BRITNEY_DATADIR/$RELEASE-proposed/state/age-policy-dates +touch --no-create $DEST +ln --verbose --symbolic --force --no-dereference $BRITNEY_HINTDIR $DEST/Hints +zcat $BRITNEY_CACHE/$SOURCE_PPA-$RELEASE/*/source/Sources.gz > $DEST/Sources +for arch in $ARCHES $PORTS_ARCHES; do + zcat $BRITNEY_CACHE/$SOURCE_PPA-$RELEASE/*/binary-$arch/Packages.gz > $DEST/Packages_${arch} +done +touch $DEST/Blocks $DEST/Dates + +# "Testing" is a combination of the archive and DEST_PPA +DEST=$BRITNEY_DATADIR/$RELEASE +mkdir --parents $DEST +mkdir -pv $BRITNEY_DATADIR/$RELEASE/state/ +touch $BRITNEY_DATADIR/$RELEASE/state/age-policy-dates +touch --no-create $DEST +ln --verbose --symbolic --force --no-dereference $BRITNEY_HINTDIR $DEST/Hints +zcat $BRITNEY_CACHE/$RELEASE*/*/source/Sources.gz > $DEST/Sources +sed -i "s/Section: universe\//Section: /g" $DEST/Sources +for arch in $ARCHES $PORTS_ARCHES; do + zcat $BRITNEY_CACHE/$RELEASE*/*/binary-$arch/Packages.gz > $DEST/Packages_${arch} + sed -i "s/Section: universe\//Section: /g" $DEST/Packages_${arch} +done +touch $DEST/Blocks +touch "$BRITNEY_DATADIR/$SOURCE_PPA-$RELEASE/Dates" + +# Create config file atomically. +CONFIG="britney.conf" +cp $CONFIG $CONFIG.bak +envsubst < "$CONFIG.bak" > "$CONFIG" +rm $CONFIG.bak + +echo 'Running britney...' +$BRITNEY_LOC -v --config "$CONFIG" --series $RELEASE + +echo 'Syncing output to frontend...' +rmdir output/; +rsync -da output/ ../../output/britney + +echo "$0 done." + +echo "Moving packages..." + +egrep -v '^#' output/$RELEASE/HeidiResultDelta > candidates || echo "No candidates found."; + +while read -r -a package; do + # This only acts on sources; binaries require manual cleanup + if [ ${#package[@]} = 2 ]; then + COPY="../ubuntu-archive-tools/copy-package" + REMOVE="../ubuntu-archive-tools/remove-package" + if echo ${package[0]} | egrep -q "^-"; then + PACKAGE=$(echo ${package[0]} | sed 's/-//') + echo "Demoting $PACKAGE..." + $COPY -y -b -s $RELEASE --from "ppa:$LP_TEAM/ubuntu/$DEST_PPA" --to "ppa:$LP_TEAM/ubuntu/$SOURCE_PPA" --version "${package[1]}" "$PACKAGE"; + $REMOVE -y -s $RELEASE --archive "ppa:$LP_TEAM/ubuntu/$DEST_PPA" --version "${package[1]}" --removal-comment="demoted to proposed" "$PACKAGE"; + else + echo "Migrating ${package[0]}..." + $COPY -y -b -s $RELEASE --from "ppa:$LP_TEAM/ubuntu/$SOURCE_PPA" --to "ppa:$LP_TEAM/ubuntu/$DEST_PPA" --version "${package[1]}" "${package[0]}"; + $REMOVE -y -s $RELEASE --archive "ppa:$LP_TEAM/ubuntu/$SOURCE_PPA" --version "${package[1]}" --removal-comment="moved to release" "${package[0]}"; + fi + fi +done < candidates; +rm candidates; + +echo "Run the grim reaper..." +./grim-reaper diff --git a/grim-reaper b/grim-reaper new file mode 100755 index 0000000..375762f --- /dev/null +++ b/grim-reaper @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 Simon Quigley +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from concurrent.futures import ThreadPoolExecutor, as_completed +from datetime import datetime, timedelta +from launchpadlib.launchpad import Launchpad + +now = datetime.now() + +def print_log(string): + global now + old_now = now + now = datetime.now() + time_elapsed = now - old_now + print(f"[{now}] (took {time_elapsed}) {string}") + +print(f"[{now}] Logging into Launchpad...") +launchpad = Launchpad.login_with("grim-reaper", "production", version="devel") + +print_log("Logged in. Initializing repositories...") +ubuntu = launchpad.distributions["ubuntu"] +lubuntu_ci = launchpad.people["lubuntu-ci"] +regular = lubuntu_ci.getPPAByName(distribution=ubuntu, name="unstable-ci") +proposed = lubuntu_ci.getPPAByName(distribution=ubuntu, name="unstable-ci-proposed") + +print_log("IS THAT THE GRIM REAPER?!?!?!?!!!") + +# Fetch packages once +two_weeks_ago = datetime.now() - timedelta(days=14) +packages = [proposed.getPublishedSources(status="Superseded"), regular.getPublishedSources(status="Superseded")] +total_removals = sum(len(packageset) for packageset in packages) + +print_log(f"Total packages to remove: {total_removals}") +current_package = 1 +current_percentage = 0 +for packageset in packages: + for pkg in packageset: + # Cancel all running builds for the package: + for build in pkg.getBuilds(): + if build.buildstate in ["Currently building", "Needs building"]: + # Only cancel the build if we can + if build.can_be_cancelled: + build.cancel() + # Delete the source package + pkg.requestDeletion(removal_comment="superseded") + new_percentage = int(current_package / total_removals) + if new_percentage > current_percentage: + current_percentage = new_percentage + print_log(f"{new_percentage}% complete ({current_package}/{total_removals})") + current_package += 1 diff --git a/lintian-ppa b/lintian-ppa new file mode 100755 index 0000000..a84cc5f --- /dev/null +++ b/lintian-ppa @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 Simon Quigley +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import argparse +import logging +import os +import shutil +import subprocess +import tempfile +import uuid +from common import clean_old_logs +from concurrent.futures import ThreadPoolExecutor, wait, FIRST_COMPLETED +from datetime import datetime, timedelta, timezone +from debian.deb822 import Changes +from launchpadlib.launchpad import Launchpad +from pathlib import Path + +BASE_OUTPUT_DIR = "/srv/lubuntu-ci/output/" +LOG_DIR = os.path.join(BASE_OUTPUT_DIR, "logs/lintian/") + +parser = argparse.ArgumentParser(description="") +parser.add_argument("--user", "-u", required=True) +parser.add_argument("--ppa", "-p", required=True) +parser.add_argument("--ppa2", "-p2") +args = parser.parse_args() + +os.makedirs(LOG_DIR, exist_ok=True) +current_time = datetime.utcnow().strftime("%H-%M-%S") +log_file = os.path.join(LOG_DIR, f"{current_time}.log") +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", + handlers=[ + logging.FileHandler(log_file) + ] +) +logger = logging.getLogger("TimeBasedLogger") + +launchpad = Launchpad.login_with("lintian-ppa", "production", version="devel") +ubuntu = launchpad.distributions["ubuntu"] +current_series = ubuntu.current_series + +user = launchpad.people[args.user] +ppa = user.getPPAByName(distribution=ubuntu, name=args.ppa) +if args.ppa2: + ppa2 = user.getPPAByName(distribution=ubuntu, name=args.ppa) + +if not os.path.exists(args.user): + os.mkdir(args.user) + +lintian = os.path.join(BASE_OUTPUT_DIR, "lintian") +lintian_tmp = os.path.join(BASE_OUTPUT_DIR, f".lintian.tmp.{str(uuid.uuid4())[:8]}") +if not os.path.exists(lintian): + os.mkdir(lintian) +if os.path.exists(lintian_tmp): + shutil.rmtree(lintian_tmp) +os.mkdir(lintian_tmp) + +def rsync(source, destination): + src = Path(source) + dst = Path(destination) + dst.mkdir(parents=True, exist_ok=True) + + for item in src.iterdir(): + src_path = item + dst_path = dst / item.name + + if src_path.is_symlink(): + if dst_path.exists() or dst_path.is_symlink(): + dst_path.unlink() + os.symlink(os.readlink(src_path), dst_path) + elif src_path.is_dir(): + shutil.copytree(src_path, dst_path, symlinks=True, dirs_exist_ok=True) + else: + shutil.copy2(src_path, dst_path) + +def process_sources(url): + tmpdir = os. + changes_file = url.split("/")[-1] + logging.info(f"Downloading {changes_file} and friends via dget") + dget_command = ["dget", "-u", url] + result = subprocess.run(dget_command, cwd=tmpdir, capture_output=True) + + with open(os.path.join(tmpdir, changes_file), "r") as f: + changes_obj = Changes(f) + source = changes_obj["Source"] + arch = changes_obj["Architecture"].replace("all", "").replace("_translations", "").split(" ")[0].strip() + + if arch == "": + return + + logging.info(f"Running Lintian for {source} on {arch}") + lintian_command = ["lintian", "-EvIL", "+pedantic", changes_file] + result = subprocess.run(lintian_command, cwd=tmpdir, capture_output=True) + stderr = result.stderr.decode("utf-8").strip() + stdout = result.stdout.decode("utf-8").strip() + + if stderr == stdout: + lintian_output = stderr + elif stderr != "" and stdout == "": + lintian_output = stderr + elif stderr == "" and stdout != "": + lintian_output = stdout + else: + lintian_output = f"{stderr}\n{stdout}" + + output_path = os.path.join(lintian_tmp, source) + if not os.path.exists(output_path): + os.mkdir(output_path) + + with open(os.path.join(output_path, f"{arch}.txt"), "w") as f: + f.write(lintian_output) + +with ThreadPoolExecutor(max_workers=30) as executor: + futures = set() + + def main_source_iter(): + last_run_file = os.path.join(args.user, ".LAST_RUN") + last_run_datetime = datetime.now(timezone.utc) - timedelta(days=365) + if os.path.exists(last_run_file): + with open(last_run_file, "r") as file: + last_run_time = file.read().strip() + + last_run_datetime = datetime.fromisoformat(last_run_time) + last_run_datetime = last_run_datetime.replace(tzinfo=timezone.utc) + logging.info(f"Last run: {last_run_datetime}") + + with open(last_run_file, "w") as file: + current_time = datetime.now(timezone.utc).isoformat() + file.write(current_time) + + for source in ppa.getPublishedSources(status="Published", distro_series=current_series): + for build in source.getBuilds(): + if build.buildstate == "Successfully built" and build.datebuilt >= last_run_datetime: + futures.add(executor.submit(process_sources, build.changesfile_url)) + + futures.add(executor.submit(main_source_iter)) + + while futures: + done, not_done = wait(futures, return_when=FIRST_COMPLETED) + + for future in done: + try: + result = future.result() + except Exception as e: + logging.exception("Task generated an exception:") + finally: + futures.remove(future) + +rsync(lintian_tmp, lintian) +shutil.rmtree(lintian_tmp) +clean_old_logs(LOG_DIR) +logging.info("Done") diff --git a/pending-packages b/pending-packages new file mode 100755 index 0000000..d508b29 --- /dev/null +++ b/pending-packages @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 Simon Quigley +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import argparse +from datetime import datetime, timedelta, timezone +from launchpadlib.launchpad import Launchpad + +print(f"Logging into Launchpad...") +launchpad = Launchpad.login_with("pending-packages", "production", version="devel") + +print("Logged in. Initializing repositories...") +ubuntu = launchpad.distributions["ubuntu"] +lubuntu_ci = launchpad.people["lubuntu-ci"] +regular = lubuntu_ci.getPPAByName(distribution=ubuntu, name="unstable-ci") +proposed = lubuntu_ci.getPPAByName(distribution=ubuntu, name="unstable-ci-proposed") + +parser = argparse.ArgumentParser() +parser.add_argument("release") +args = parser.parse_args() +series = ubuntu.getSeries(name_or_version=args.release) + +# First, check if any sources are still publishing +print("Repositories initialized. Checking for pending sources...") +records = [regular.getPublishedSources(status="Pending", distro_series=series), + proposed.getPublishedSources(status="Pending", distro_series=series)] +total_pending = sum([len(i) for i in records]) +has_pending = total_pending != 0 + +if has_pending: + print(f"Total sources pending: {total_pending}") + print("Sources are still pending, not running Britney") + exit(1) + +# Finally, check if any builds are still running/queued +print("No pending sources, continuing. Checking for pending builds...") +total_pending = 0 +total_retried = 0 +for archive in [proposed, regular]: + one_hour_ago = datetime.now(timezone.utc) - timedelta(hours=1) + for source in archive.getPublishedSources(status="Published", distro_series=series): + for build in source.getBuilds(): + if build.buildstate == "Currently building": + if build.date_started >= one_hour_ago: + total_pending += 1 + elif build.buildstate == "Needs building": + total_pending += 1 + # This isn't technically related, but retry failed builds without logs + elif build.buildstate == "Chroot problem" or (build.buildstate == "Failed to build" and not build.build_log_url): + if build.can_be_retried: + build.retry() + total_pending += 1 + total_retried += 1 + +if total_retried != 0: + print(f"Total builds retried due to builder flakiness: {total_retried}") + +if total_pending != 0: + print(f"Total builds pending: {total_pending}") + print("Builds are still running, not running Britney") + exit(1) + +print("No pending builds, continuing. Checking for pending binaries...") +has_pending = False +for pocket in [proposed, regular]: + if has_pending: + break + three_hours_ago = datetime.now(timezone.utc) - timedelta(hours=3) + check_builds = set() + current_builds = set() + source_packages = [] + + for build in pocket.getBuildRecords(build_state="Successfully built"): + if build.datebuilt < three_hours_ago: + del source_packages + break + check_builds.add(build.title) + source_package = build.current_source_publication + if source_package and source_package.distro_series == series and source_package not in source_packages: + source_packages.append(source_package) + for binary in source_package.getPublishedBinaries(): + current_builds.add(binary.build.title) + + has_pending = not check_builds.issuperset(current_builds) or has_pending + +if has_pending: + print("Binaries are still pending, not running Britney") + exit(1) + +print("All clear. Starting Britney.") diff --git a/run-britney b/run-britney new file mode 100755 index 0000000..f1cc699 --- /dev/null +++ b/run-britney @@ -0,0 +1,38 @@ +#!/bin/bash +# +# Copyright (C) 2024 Simon Quigley +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Configuration +LOG_DIR="/srv/lubuntu-ci/output/logs/britney" +SCRIPT_PATH="fetch-indexes" +MAX_LOG_AGE=86400 # 24 hours in seconds + +# Ensure the log directory exists +mkdir -p "$LOG_DIR" + +# Log rotation: Remove logs older than MAX_LOG_AGE +find "$LOG_DIR" -type f -mtime +1 -exec rm -f {} \; + +# Execute the fetch-indexes script for each release and log output +for release in plucky oracular noble; do + export RELEASE="$release" + + # Log file named by current UTC time (HH-MM-SS) + LOG_FILE="$LOG_DIR/$RELEASE_$(date -u +"%H-%M-%S").log" + + echo "$(date -u +"%Y-%m-%d %H:%M:%S") - Running Britney for $RELEASE" >> "$LOG_FILE" + "$SCRIPT_PATH" >> "$LOG_FILE" 2>&1 +done diff --git a/systemd/britney.service b/systemd/britney.service new file mode 100644 index 0000000..e1f0dbe --- /dev/null +++ b/systemd/britney.service @@ -0,0 +1,11 @@ +[Unit] +Description=Britney +Wants=britney.timer +After=network.target + +[Service] +Type=simple +User=lugito +Group=lugito +WorkingDirectory=/srv/lubuntu-ci/repos/ci-tools +ExecStart=/usr/bin/python3 /srv/lubuntu-ci/repos/ci-tools/run-britney diff --git a/systemd/britney.timer b/systemd/britney.timer new file mode 100644 index 0000000..1852542 --- /dev/null +++ b/systemd/britney.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Britney timer + +[Timer] +OnBootSec=5min +OnUnitActiveSec=30min +Persistent=true + +[Install] +WantedBy=timers.target