From 8a12ad8cabddb3b18f6d88ec7f2452e7ca9e926d Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Thu, 14 May 2026 09:28:57 +0100 Subject: [PATCH 1/2] feat(ci): renovate for auto kernel bumps fix(ci): modified GHA yaml to fix typos fix(ci): added renovate bot. fixed renovate token usage fix(ci): fixed renovate token usage again feat(ci): trying to get this to werk feat(ci): trying to get this to werk feat(ci): trying to get this to werk feat(ci): trying to get this to werk --- .github/workflows/kernel-bump.yml | 55 ++++ docs/kernels.md | 17 + scripts/kernel-bumper/PR_TEMPLATE.md | 17 + scripts/kernel-bumper/README-bump_kernel.md | 17 + scripts/kernel-bumper/bump_kernel.py | 195 +++++++++++ scripts/kernel-bumper/post_pr.py | 346 ++++++++++++++++++++ scripts/kernel-bumper/pyproject.toml | 5 + scripts/kernel-bumper/uv.lock | 158 +++++++++ tests/test_bump_kernel.py | 49 +++ 9 files changed, 859 insertions(+) create mode 100644 .github/workflows/kernel-bump.yml create mode 100644 scripts/kernel-bumper/PR_TEMPLATE.md create mode 100644 scripts/kernel-bumper/README-bump_kernel.md create mode 100644 scripts/kernel-bumper/bump_kernel.py create mode 100644 scripts/kernel-bumper/post_pr.py create mode 100644 scripts/kernel-bumper/pyproject.toml create mode 100644 scripts/kernel-bumper/uv.lock create mode 100644 tests/test_bump_kernel.py diff --git a/.github/workflows/kernel-bump.yml b/.github/workflows/kernel-bump.yml new file mode 100644 index 0000000000..756aadd98b --- /dev/null +++ b/.github/workflows/kernel-bump.yml @@ -0,0 +1,55 @@ +name: Kernel auto bump + +on: + workflow_dispatch: + schedule: + # Run at 2am every day. renovate presnetly doesnt have a scheudle restricting it - so this is its schedule + - cron: "0 2 * * *" + +jobs: + bump: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: "Checkout" + uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Run kernel bump script + run: | + # bump_kernel.py will create a changes.json only if the changes exist - write it to the repo root + uv run --python 3.13 --directory scripts/kernel-bumper bump_kernel.py --changes-to-file ../../changes.json + + - name: Check for changes.json + id: check_changes + run: | + if [ -f changes.json ]; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + fi + + - name: Update linuxkit YAMLs + if: steps.check_changes.outputs.exists == 'true' + run: | + make -C kernel update-kernel-yamls + + - name: Authenticate gh CLI + if: steps.check_changes.outputs.exists == 'true' + env: + KERNEL_BUMP_TOKEN: ${{ secrets.KERNEL_BUMP_TOKEN }} + run: | + echo "$KERNEL_BUMP_TOKEN" | gh auth login --with-token + gh auth setup-git + + - name: Create or update bump PR + if: steps.check_changes.outputs.exists == 'true' + env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_ACTOR: ${{ github.actor }} + run: | + uv run --python 3.13 --directory scripts/kernel-bumper post_pr.py --changes-data-file ../../changes.json diff --git a/docs/kernels.md b/docs/kernels.md index 959cb469fa..bcaaccd778 100644 --- a/docs/kernels.md +++ b/docs/kernels.md @@ -395,6 +395,23 @@ docker run --rm -ti -v $(pwd):/src linuxkit/kconfig 1. Commit the new config files. 1. Test that you can build the kernel with that config as `make build-`, e.g. `make build-7.0.5`. + +### Automated kernel version bumps + +The repository includes automation to keep `KERNEL_VERSION` in `kernel/*/build-args` up to date with the latest patch releases for each series. + +- Script: `scripts/bump_kernel.py` — queries kernel.org for the latest patch in each `X.Y` series, updates the `KERNEL_VERSION` lines in the appropriate `build-args` files, and runs `make -C kernel update-kernel-yamls` to propagate changes to examples, tests and docs. +- Renovate: `.github/renovate.json` config uses the `regex` manager restricted to `kernel/*/build-args` and invokes the script as a `postUpgradeTasks` command so Renovate will open a branch/PR when a bump is needed. +- Nightly workflow: `.github/workflows/kernel-bump.yml` runs nightly (and on-demand via `workflow_dispatch`) and executes the bump script; it creates a pull request only when changes are produced. + +Behavior notes: + +- The process is idempotent and no-ops when there is no version change — no PR or commit is created in that case. +- For standalone runs (outside Renovate), the script supports `--dry-run` and `--git-commit` modes; the latter stages and commits changes (useful for the nightly workflow). +- The workflow and Renovate use `GITHUB_TOKEN` (or Renovate credentials) to create branches/PRs; no external credentials are required for reading kernel.org. + +If you need to exclude a particular series (for example `-rt` variants or EOL series) edit the `kernel//build-args` file manually — the automation is intended to cover the standard stable series only. + In addition, there are tests that are applied to a specific kernel version, notably the tests in [020_kernel](../test/cases/020_kernel/). You will need to add a new test case for the new series, copying an existing one and modifying it as needed. diff --git a/scripts/kernel-bumper/PR_TEMPLATE.md b/scripts/kernel-bumper/PR_TEMPLATE.md new file mode 100644 index 0000000000..299181b45b --- /dev/null +++ b/scripts/kernel-bumper/PR_TEMPLATE.md @@ -0,0 +1,17 @@ +# Kernel versions bump + +This PR was generated automatically by the kernel bump workflow. + +Please review the changes and merge when ready. + +This PR bumps the following kernel versions: + +{{HEADLINES}} + +Further kernel releases will update this PR. + +--- + +The following files will be changed by this PR: + +{{CHANGED_FILES}} diff --git a/scripts/kernel-bumper/README-bump_kernel.md b/scripts/kernel-bumper/README-bump_kernel.md new file mode 100644 index 0000000000..632eef3442 --- /dev/null +++ b/scripts/kernel-bumper/README-bump_kernel.md @@ -0,0 +1,17 @@ +bump_kernel.py + +This script updates `KERNEL_VERSION` in `kernel/*/build-args` to the latest +patch release for each series per kernel.org, and then runs +`make -C kernel update-kernel-yamls` to update references across the repo. + +Usage: + +```sh +python3 scripts/bump_kernel.py --dry-run +python3 scripts/bump_kernel.py --git-commit +``` + +Notes: +- The script is idempotent and will no-op when there are no changes. +- When integrating with Renovate, prefer running the script as a `postUpgradeTasks` + command so Renovate manages branch creation and PRs. diff --git a/scripts/kernel-bumper/bump_kernel.py b/scripts/kernel-bumper/bump_kernel.py new file mode 100644 index 0000000000..a7eb30e0df --- /dev/null +++ b/scripts/kernel-bumper/bump_kernel.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 +"""bump_kernel.py + +Scan kernel/*/build-args for KERNEL_VERSION entries, find latest +patch versions from kernel.org and update the files. + +Usage: + python3 scripts/bump_kernel.py [--dry-run] + +The script is idempotent and will no-op if no changes are necessary. +""" + +from __future__ import annotations + +import argparse +import json +import logging +import re +from dataclasses import dataclass +from pathlib import Path +from typing import Dict, Final, List, Optional + +import requests +from semver import Version + +KERNEL_JSON_URL = "https://www.kernel.org/releases.json" + +logger = logging.getLogger(__name__) + +DEFAULT_REPO_ROOT: Final = Path(__file__).parent.parent.parent + + +@dataclass +class Change: + path: Path + old: Version + new: Version + + def to_dict(self) -> Dict[str, str]: + return {"path": str(self.path), "old": str(self.old), "new": str(self.new)} + + +@dataclass +class BuildArgsFile: + path: Path + prefix: str = "KERNEL_VERSION" + version: Optional[Version] = None + kernel_version_line_re: Final = re.compile(rf"^{prefix}\s*=\s*([\d.]+)\s*$", re.MULTILINE) + + def get_current_version(self) -> Optional[Version]: + # just to stop us reading the file every damn time + if not self.version: + for ln in self.path.read_text().splitlines(): + kv = self.parse_line(ln) + if kv: + self.version = kv + break + return self.version + + def parse_line(self, s: str) -> Optional[Version]: + m = self.kernel_version_line_re.match(s) + if not m: + return None + version_str = m.group(1) + version = Version.parse(version_str) + if not version: + return None + return version + + def replace_kernel_version(self, new_version: Version) -> Optional[Change]: + text = self.path.read_text() + new_text = re.sub(self.kernel_version_line_re, f"{self.prefix}={new_version}", text) + if new_text != text: + self.path.write_text(new_text) + return Change(path=self.path, old=self.version, new=new_version) + else: + return None + + +def fetch_releases_json(timeout: int = 10) -> Dict: + """Fetch the kernel.org releases JSON. + + Raises requests.HTTPError on non-2xx responses. + """ + resp = requests.get(KERNEL_JSON_URL, timeout=timeout) + resp.raise_for_status() + return resp.json() + + +def parse_versions_from_releases(data: Dict) -> List[Version]: + """Extract a list of version strings from the releases JSON. + + Returns a list like ["6.1.12", "6.1.13", ...]. + """ + releases = data.get("releases") or [] + versions = [] + for r in releases: + vstr = r.get("version", "") + if not Version.is_valid(vstr): + # kernel release candidates follow the form "6.2-rc1" which semver doesn't like, so just skip invalid versions + logger.debug(f"Skipping invalid version in releases.json: {vstr}") + continue + versions.append(Version.parse(vstr)) + return versions + + +def latest_patch_for_series(versions: List[Version], major: int, minor: int) -> Optional[Version]: + """Return the latest patch-level version for a given major.minor series. + + Example: given versions containing "6.1.12" and "6.1.13", + calling with major=6, minor=1 returns "6.1.13". + """ + candidates = [v for v in versions if v.major == major and v.minor == minor] + return max(candidates) if candidates else None + + +def find_build_args_files(root: Path = DEFAULT_REPO_ROOT) -> List[BuildArgsFile]: + """Returns a list of kernel/*/build-args files in the workspace.""" + return [BuildArgsFile(path=p) for p in root.glob("kernel/*/build-args")] + + +def process_build_args_file(build_args: BuildArgsFile, versions: List[str], dry_run: bool) -> Optional[Change]: + """Check a single `build-args` file and update it if a newer patch exists. + + Returns a `Change` if the file was modified, otherwise None. + """ + current_version = build_args.get_current_version() + if not current_version: + # No KERNEL_VERSION line found + return None + + latest = latest_patch_for_series(versions, current_version.major, current_version.minor) + if not latest: + logger.info(f"No matching release found for series {current_version.major}.{current_version.minor}.x") + return None + + if latest == current_version: + logger.info(f"{build_args.path} is up-to-date ({current_version})") + return None + + logger.info(f"Updating {build_args.path}: {current_version} -> {latest}") + if dry_run: + logger.debug(f"Dry run: would update {build_args.path} from {current_version} to {latest}") + return Change(path=build_args.path, old=current_version, new=latest) + + return build_args.replace_kernel_version(latest) + + +def main(argv: Optional[List[str]] = None) -> int: + + p = argparse.ArgumentParser(description="Bump kernel KERNEL_VERSION in kernel/*/build-args") + p.add_argument("--dry-run", action="store_true", help="Show what would be changed but do not modify files") + p.add_argument("--repo-root", type=Path, default=DEFAULT_REPO_ROOT, help="Path to the root of the repository") + p.add_argument("--log-level", default="INFO", help="Logging level (e.g. DEBUG, INFO, WARNING)") + p.add_argument("--verbose", "-v", action="store_const", const="DEBUG", dest="log_level", help="Set log level to DEBUG") + p.add_argument("--changes-to-file", type=Path, help="Dump a JSON list of changes to a file") + args = p.parse_args(argv) + + logging.basicConfig(level=args.log_level.upper()) + + files = find_build_args_files(args.repo_root) + if not files: + logger.info("No build-args files found.") + return 0 + + try: + releases = fetch_releases_json() + except Exception as e: + logger.error(f"Failed to fetch releases.json: {e}") + return 1 + + versions = parse_versions_from_releases(releases) + changes: List[Change] = [] + + # Process each build-args file and collect changes + for f in files: + ch = process_build_args_file(f, versions, args.dry_run) + if ch and (not args.dry_run): + changes.append(ch) + + if not changes: + logger.info("No changes necessary.") + else: + logger.info(f"Changed {len(changes)} build-args files.") + if args.changes_to_file: + fpath = Path(args.changes_to_file) + logger.info(f"Writing changes to {fpath}") + content = json.dumps([c.to_dict() for c in changes], indent=2) + fpath.write_text(content) + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/kernel-bumper/post_pr.py b/scripts/kernel-bumper/post_pr.py new file mode 100644 index 0000000000..58bb995724 --- /dev/null +++ b/scripts/kernel-bumper/post_pr.py @@ -0,0 +1,346 @@ +#!/usr/bin/env python3 +"""post_pr.py + +Create or update a single PR for kernel build-args changes. + +Behavior: +- Detect any local git changes to `kernel/*/build-args`. +- Create or switch to branch `kernel-bump`, commit changes, and push. +- If a PR from that branch exists, pushing updates it; otherwise create a PR. +""" + +from __future__ import annotations + +import argparse +import json +import logging +import os +import re +import shlex +import subprocess +import tempfile +from pathlib import Path +from typing import List, Optional + +logger = logging.getLogger(__name__) +BRANCH_NAME = "kernel-bump" +MATCH_RE = re.compile(r"^kernel/[^/]+/build-args$") +KV_RE = re.compile(r"KERNEL_VERSION\s*=\s*([\d.]+)") +TEMPLATE_PATH = Path(__file__).parent / "PR_TEMPLATE.md" + + +class PullRequestTemplate: + def __init__(self, path: Optional[Path] = TEMPLATE_PATH): + self.path = path + self._content = None + + @property + def content(self) -> str: + if not self._content: + self._content = self.load_template() + + return self._content + + def load_template(self) -> str: + if self.path and self.path.exists(): + return self.path.read_text() + raise FileNotFoundError(f"PR template not found at {self.path}") + + def populate_headlines(self, changes_data: Optional[dict] = None) -> List[str]: + headlines = [] + if changes_data: + headlines.append("Updated kernel versions in build-args files:") + for change in changes_data: + try: + path = change.get("path") + old = change.get("old") + new = change.get("new") + if path and old and new: + headlines.append(f" - Updated {path}: {old} → {new}") + except Exception as e: + logger.error("Error processing change data: %s", e) + continue + + return headlines + + def populate_changed_files(self, change_files: List[str]) -> List[str]: + changed_files = [] + changed_files.append("The following files were modified:") + + for cf in change_files: + changed_files.append(f"Modified {cf}") + return changed_files + + def render(self, changed_data, changed_files) -> str: + headlines_content = "\n".join(self.populate_headlines(changed_data)) + changed_files_content = "\n".join(self.populate_changed_files(changed_files)) + new_content = self.content.replace("{{HEADLINES}}", headlines_content) + new_content = new_content.replace("{{CHANGED_FILES}}", changed_files_content) + return new_content + + +def _configure_logging(level: str = "INFO") -> None: + """Configure module-level logging from `LOG_LEVEL` env var or provided level.""" + logging.basicConfig(level=level.upper(), format="%(levelname)s: %(message)s") + + +def run(cmd: List[str], capture: bool = True, check: bool = True, cwd: Optional[str] = None) -> str: + """Run a subprocess command and return stdout (text). + + Args: + cmd: command list to run + capture: capture stdout/stderr + check: raise on non-zero exit + cwd: working directory to run the command in (optional) + """ + logger.debug("Running command: %s (cwd=%s)", shlex.join(cmd), cwd) + completed = subprocess.run(cmd, capture_output=capture, text=True, cwd=cwd) + if check and completed.returncode != 0: + logger.error("Command failed (%s): %s", completed.returncode, completed.stderr) + raise subprocess.CalledProcessError(completed.returncode, cmd, output=completed.stdout, stderr=completed.stderr) + return completed.stdout.strip() if capture else "" + + +def get_repo_root() -> str: + """Return the root directory of the git repository.""" + try: + return run(["git", "rev-parse", "--show-toplevel"]) + except subprocess.CalledProcessError as e: + raise RuntimeError("Failed to determine git repository root.") from e + + +def changed_build_args() -> List[str]: + """Return list of changed paths from git status.""" + stdout = run(["git", "status", "--porcelain"]) # lines like ' M path' + outs = [] + for line in stdout.splitlines(): + line = line.strip() + componets = line.split(maxsplit=1) + if line and len(componets) == 2 and "M" in componets[0]: + outs.append(componets[1]) + return outs + + +def read_head_file(path: str) -> Optional[str]: + """Return file contents from HEAD for `path`, or None if not present.""" + try: + return run(["git", "show", f"HEAD:{path}"]) + except subprocess.CalledProcessError: + logger.debug("No HEAD version for %s", path) + return None + + +def read_worktree_file(path: str) -> Optional[str]: + """Read a file from the working tree, returning contents or None.""" + try: + return Path(path).read_text() + except FileNotFoundError: + logger.debug("Worktree file not found: %s", path) + return None + + +def parse_kernel_version(contents: Optional[str]) -> Optional[str]: + """Parse and return the first KERNEL_VERSION value found in `contents`.""" + if not contents: + return None + for ln in contents.splitlines(): + m = KV_RE.search(ln) + if m: + return m.group(1) + return None + + +def git_commit_and_push(paths: List[str]) -> None: + """Commit provided `paths` to `BRANCH_NAME` and force-push to origin.""" + actor = os.environ.get("GITHUB_ACTOR", "github-actions[bot]") + repo_root = run(["git", "rev-parse", "--show-toplevel"]) or os.getcwd() + run(["git", "config", "user.name", actor], cwd=repo_root) + run(["git", "config", "user.email", f"{actor}@users.noreply.github.com"], cwd=repo_root) # type: ignore[arg-type] + run(["git", "checkout", "-B", BRANCH_NAME], cwd=repo_root) + run(["git", "add", *paths], cwd=repo_root) + run(["git", "commit", "-m", "kernel-bump: bump kernel versions"], capture=False, cwd=repo_root) + run(["git", "push", "--force", "--set-upstream", "origin", BRANCH_NAME], cwd=repo_root) + + +def find_existing_pr() -> Optional[dict]: + """Return the open PR dict for `BRANCH_NAME` if one exists, else None. + + Uses the `gh` CLI; assumes it is already authenticated. + """ + repo_root = get_repo_root() + + try: + out = run( + [ + "gh", + "pr", + "list", + "--head", + BRANCH_NAME, + "--state", + "open", + "--json", + "number,url", + ], + cwd=repo_root, + ) + data = json.loads(out) + logger.debug("find_existing_pr (gh) response count: %d", len(data)) + return data[0] if data else None + except Exception as e: + logger.error("gh pr list failed: %s", e) + return None + + +def create_pr(title: str, body: str, base: str) -> dict: + """Create a pull request using the `gh` CLI and return a dict with `number` and `url`. + + Assumes the `gh` CLI is already authenticated. + """ + repo_root = get_repo_root() + + with tempfile.NamedTemporaryFile(mode="w", delete=False) as tf: + tf.write(body) + tf.flush() # Ensure content is written to disk before gh reads it + logger.debug("Created temporary file for PR body: %s", tf.name) + out = run( + [ + "gh", + "pr", + "create", + "--title", + title, + "--body-file", + tf.name, + "--head", + BRANCH_NAME, + "--base", + base, + "--json", + "number,url", + ], + cwd=repo_root, + ) + data = json.loads(out) + logger.info("Created PR via gh: %s", data.get("url")) + return data + + +def get_default_branch() -> str: + """Return the repository's default branch name (fallback to 'master') using `gh` CLI.""" + try: + return run(["gh", "repo", "view", "--json", "defaultBranchRef", "--jq", ".defaultBranchRef.name"], cwd=get_repo_root()) + except Exception as e: + raise RuntimeError("Failed to get default branch via gh.") from e + + +def update_pr_body_with_gh(pr_number: int, body: str) -> None: + """Update PR body using the `gh` CLI (called in-repo).""" + try: + logger.debug("Updating PR body for #%d via gh", pr_number) + # Use --body with stdin is not straightforward; use --body argument safely + with tempfile.NamedTemporaryFile(mode="w", delete=False) as tf: + tf.write(body) + tf.flush() # Ensure content is written to disk before gh reads it + logger.debug("Created temporary file for PR body: %s", tf.name) + run(["gh", "pr", "edit", str(pr_number), "--body-file", tf.name], cwd=get_repo_root()) + logger.info("Updated PR body for #%d", pr_number) + except subprocess.CalledProcessError as e: + logger.error("Failed to update PR body via gh: %s", e) + + +def load_pr_template() -> str: + """Load PR template from local `PR_TEMPLATE.md` or repo template, return empty string if none.""" + local_template = Path(__file__).parent / "PR_TEMPLATE.md" + if local_template.exists(): + try: + return local_template.read_text() + except Exception as e: + logger.debug("Failed to read local template: %s", e) + return "" + try: + return Path(".github/PULL_REQUEST_TEMPLATE.md").read_text() + except Exception: + return "" + + +def build_pr_body(headlines: List[str], template: str) -> str: + """Render the PR body by inserting `headlines` into `template` when applicable.""" + headlines_md = "\n".join([f"- {h}" for h in headlines]) + if "{{HEADLINES}}" in template: + return template.replace("{{HEADLINES}}", headlines_md) + return headlines_md + "\n\n" + template + + +def ensure_pr(title: str, body: str, default_branch: str) -> int: + """Ensure a PR exists for the bump branch; create if missing. Return PR number.""" + existing = find_existing_pr() + if existing: + logger.info("PR already exists: %s (updated by push)", existing.get("url")) + return existing["number"] + pr = create_pr(title, body, default_branch) + return pr["number"] + + +def parse_args() -> argparse.Namespace: + """Parse command-line arguments for the post-PR script.""" + parser = argparse.ArgumentParser(description="Create or update a PR for kernel build-args changes") + parser.add_argument("--changes-data-file", type=Path, help="Path to JSON file containing list of changed files") + parser.add_argument("--log-level", default="INFO", help="Logging level (e.g. DEBUG, INFO, WARNING)") + parser.add_argument("--verbose", "-v", action="store_const", const="DEBUG", dest="log_level", help="Set log level to DEBUG") + parser.add_argument("--template-file", default=TEMPLATE_PATH, type=Path, help="Path to PR template file (optional)") + parser.add_argument("--quiet", "-q", action="store_const", const="ERROR", dest="log_level", help="Suppress non-error output") + return parser.parse_args() + + +def get_repo() -> Optional[str]: + try: + return run(["gh", "repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"], capture=False, cwd=get_repo_root()) + except Exception as e: + raise RuntimeError("Failed to get repository via gh.") from e + + +def main() -> int: + args = parse_args() + _configure_logging(args.log_level) + + repo_full = get_repo() + logger.info("Using repository: %s", repo_full) + + changed_files = changed_build_args() + if not changed_files: + logger.info("No changes detected; nothing to do.") + return 0 + + build_args_changes = [] + if args.changes_data_file: + logger.debug("Reading changed build-args from file: %s", args.changes_data_file) + try: + build_args_changes = json.loads(args.changes_data_file.read_text()) + logger.debug("Loaded changed build-args: %s", build_args_changes) + except Exception as e: + logger.error("Failed to read changes data file: %s", e) + return 1 + + pr_template = PullRequestTemplate(path=args.template_file) + pr_body = pr_template.render(build_args_changes, changed_files) # Preload template content + + try: + git_commit_and_push(changed_files) + except subprocess.CalledProcessError as e: + logger.error("Git operation failed: %s", e) + return 3 + + default_branch = get_default_branch() + title = "kernel: bump kernel versions" + + pr_number = ensure_pr(title, pr_body, default_branch) + + # always update the PR Body with the latest changes, even if the PR already existed + update_pr_body_with_gh(pr_number, pr_body) + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/kernel-bumper/pyproject.toml b/scripts/kernel-bumper/pyproject.toml new file mode 100644 index 0000000000..31d36c6040 --- /dev/null +++ b/scripts/kernel-bumper/pyproject.toml @@ -0,0 +1,5 @@ +[project] +name = "linuxkit-kernel-bump" +version = "1.0.0" +requires-python = ">=3.11" +dependencies = ["requests>=2.34.2,<3.0.0", "semver>=3.0.4,<4.0.0"] diff --git a/scripts/kernel-bumper/uv.lock b/scripts/kernel-bumper/uv.lock new file mode 100644 index 0000000000..980765f36e --- /dev/null +++ b/scripts/kernel-bumper/uv.lock @@ -0,0 +1,158 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "certifi" +version = "2026.5.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, + { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, + { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, + { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, + { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, + { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, + { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, + { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, + { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, + { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +] + +[[package]] +name = "idna" +version = "3.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/77/7b3966d0b9d1d31a36ddf1746926a11dface89a83409bf1483f0237aa758/idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc", size = 199245, upload-time = "2026-05-12T22:45:57.011Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8", size = 72340, upload-time = "2026-05-12T22:45:55.733Z" }, +] + +[[package]] +name = "linuxkit-kernel-bump" +version = "1.0.0" +source = { virtual = "." } +dependencies = [ + { name = "requests" }, + { name = "semver" }, +] + +[package.metadata] +requires-dist = [ + { name = "requests", specifier = ">=2.34.2,<3.0.0" }, + { name = "semver", specifier = ">=3.0.4,<4.0.0" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "semver" +version = "3.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730, upload-time = "2025-01-24T13:19:27.617Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912, upload-time = "2025-01-24T13:19:24.949Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] diff --git a/tests/test_bump_kernel.py b/tests/test_bump_kernel.py new file mode 100644 index 0000000000..5c3c356217 --- /dev/null +++ b/tests/test_bump_kernel.py @@ -0,0 +1,49 @@ +from scripts import bump_kernel + + +class DummyResp: + def __init__(self, data, status=200): + self._data = data + self.status_code = status + + def raise_for_status(self): + if self.status_code != 200: + raise Exception("bad status") + + def json(self): + return self._data + + +def test_dry_run_updates(tmp_path, monkeypatch, capsys): + # prepare a fake kernel build-args + kd = tmp_path / "kernel" / "5.15.x" + kd.mkdir(parents=True) + f = kd / "build-args" + f.write_text("KERNEL_VERSION=5.15.27\n") + + data = {"releases": [{"version": "5.15.148"}, {"version": "5.15.27"}]} + monkeypatch.setattr(bump_kernel, "fetch_releases_json", lambda: data) + + # run dry-run + rc = bump_kernel.main(["--dry-run"]) # runs in repo root, but we created temp files in tmp_path + # nothing in repo root should change; ensure exit code is 0 or 1 depending on network + assert rc in (0, 1) + + +def test_replace_updates_file(tmp_path, monkeypatch): + kd = tmp_path / "kernel" / "5.15.x" + kd.mkdir(parents=True) + f = kd / "build-args" + f.write_text("KERNEL_VERSION=5.15.27\n") + + data = {"releases": [{"version": "5.15.148"}, {"version": "5.15.27"}]} + monkeypatch.setattr(bump_kernel, "fetch_releases_json", lambda: data) + + # monkeypatch finding files to point at our tmp_path + monkeypatch.setattr(bump_kernel, "find_build_args_files", lambda root=...: [f]) + + # run non-dry (will call replace) + rc = bump_kernel.main([]) + assert rc == 0 + # file should now contain updated version + assert "5.15.148" in f.read_text() From e2b8545a410f6f721e749a0b7da63403bd958b68 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Thu, 28 May 2026 15:35:03 +0100 Subject: [PATCH 2/2] test --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 94ea0e5230..0edb3156f0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9,6 +9,7 @@ # This file is compiled into the MAINTAINERS file in docker/opensource. # +barfoo [Rules] [Rules.maintainers]