From 4639c8ddacad452870c10131e71575956f19a6c7 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Mar 27 2024 19:42:00 +0000 Subject: Run check-missing on development releases as part of CI This is...wrong, but it's *usefully* wrong. comps PRs aren't the only thing that can cause check-missing to fail. They're not even the most *common* reason for check-missing to fail. It's more likely to be caused by a package being retired or a source package changing the binary packages it produces. However, we cannot currently gate package retirements and/or binary package set changes on this script. Doing so would require a whole ton more work than just...doing this. Doing this will cause us to notice problems the next time a comps PR is touched. This is a definite improvement on us noticing whenever I remember to run the script manually. It will be somewhat annoying/inconvenient for people submitting comps requests, but I think the benefit of problems in comps getting noticed and fixed much more rapidly outweighs that. Signed-off-by: Adam Williamson --- diff --git a/.zuul.yaml b/.zuul.yaml index 56fefdd..c9636eb 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -2,8 +2,14 @@ check: jobs: - validate-comps + - check-missing - job: name: validate-comps description: Validate comps files run: ci/validate-comps.yaml + + - job: + name: check-missing + description: Run CI check-missing script + run: ci/check-missing.yaml diff --git a/check-missing b/check-missing index 9a304ee..cff8471 100755 --- a/check-missing +++ b/check-missing @@ -14,6 +14,7 @@ import glob import argparse import subprocess +import sys import lxml.etree as ET from collections import defaultdict @@ -119,23 +120,38 @@ for lang in langpacks.getchildren(): lang.getparent().remove(lang) # Print out a summary -print('Packages with incorrect architecture tags:') -for pkg in sorted(archpkgs): - print(' {} only available on {}'.format(pkg, archpkgs[pkg])) - -print('\nRemoving packages:') -for pkg in sorted(removedpkgs): - print(' {} in group {}'.format(pkg, ', '.join(removedpkgs[pkg]))) - -print('\nRemoving empty groups:') -for group in sorted(removedgrps): - print(' {} in {}'.format(group, ', '.join(removedgrps[group]))) - -print('\nRemoving language packs for:') -for lang in removedlang: - print(' {}'.format(lang)) - +if archpkgs: + print('Packages with incorrect architecture tags:') + for pkg in sorted(archpkgs): + print(' {} only available on {}'.format(pkg, archpkgs[pkg])) + print() + +if removedpkgs: + print('Removing packages:') + for pkg in sorted(removedpkgs): + print(' {} in group {}'.format(pkg, ', '.join(removedpkgs[pkg]))) + print() + +if removedgrps: + print('Removing empty groups:') + for group in sorted(removedgrps): + print(' {} in {}'.format(group, ', '.join(removedgrps[group]))) + print() + +if removedlang: + print('Removing language packs for:') + for lang in removedlang: + print(' {}'.format(lang)) + print() + +if not archpkgs and not removedpkgs and not removedgrps and not removedlang: + print("No problems found!") # Write out the updated XML file if desired if args.update: tree.write(compsfile, encoding="UTF-8", xml_declaration=True) + sys.exit(0) + +if archpkgs or removedpkgs or removedgrps or removedlang: + sys.exit(1) +sys.exit(0) diff --git a/ci/check-missing b/ci/check-missing new file mode 100755 index 0000000..fc9ba15 --- /dev/null +++ b/ci/check-missing @@ -0,0 +1,54 @@ +#!/bin/python3 + +# This is a silly wrapper around check-missing that runs it on all current releases, +# in parallel. + +import asyncio +import requests +import subprocess +import sys + +# thanks, https://stackoverflow.com/questions/63782892 +async def run_command(*args, **kwargs): + """ + Run a command with subprocess such that we can run multiple + concurrently. + """ + # Create subprocess + process = await asyncio.create_subprocess_exec( + *args, + # stdout must a pipe to be accessible as process.stdout + stderr=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + **kwargs, + ) + # Wait for the subprocess to finish + stdout, stderr = await process.communicate() + # Return retcode, stdout and stderr + return (process.returncode, stdout.decode().strip(), stderr.decode().strip()) + +async def main(): + reljson = requests.get("https://fedorapeople.org/groups/qa/metadata/release.json").json()["fedora"] + rels = reljson.get("branched", []) + if rels: + # we got branched, add rawhide + rels.append(max(rels)+1) + else: + # only rawhide, figure out rawhide rel number + curr = max(reljson["stable"]) + rels = [curr+1] + tasks = [asyncio.create_task(run_command("./check-missing", str(rel))) for rel in rels] + rets = await asyncio.gather(*tasks, return_exceptions=True) + exitcode = 0 + for (ret, rel) in zip(rets, rels): + print(f"Release: {rel}") + if isinstance(ret, Exception): + print(f"Error! {str(ret)}") + exitcode = 1 + else: + print(ret[1]) + if ret[0]: + exitcode = 1 + sys.exit(exitcode) + +asyncio.run(main()) diff --git a/ci/check-missing.yaml b/ci/check-missing.yaml new file mode 100644 index 0000000..9649c71 --- /dev/null +++ b/ci/check-missing.yaml @@ -0,0 +1,11 @@ +- hosts: all + tasks: + - name: Install needed packages + package: + name: ['python3-lxml'] + state: present + become: yes + - name: Check for comps entries referring to missing packages + ansible.builtin.command: + chdir: "{{ zuul.project.src_dir }}" + cmd: ci/check-missing