diff options
| author | Tranch <tranch.xiao@gmail.com> | 2026-10-16 01:32:11 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-10-16 01:32:11 +0800 |
| commit | 6c001a951ae122b34c86eefcd9abc8f3a1e32a26 (patch) | |
| tree | 219c0840868e7494fc50d24ea952fdaaebefedd2 /.github | |
| parent | 3f7496d580f185c0974c5edc107570c471d0cdde (diff) | |
| parent | 3fbfb2bd4bb5e27509e8697018cddd105fca8dad (diff) | |
| download | AeroCore-OS-6c001a951ae122b34c86eefcd9abc8f3a1e32a26.tar.gz AeroCore-OS-6c001a951ae122b34c86eefcd9abc8f3a1e32a26.zip | |
Merge pull request #33 from AeroCore-IO/testing44.20261015
Promote tested Bazzite 44.20261012 updates to stable
Diffstat (limited to '.github')
| -rw-r--r-- | .github/scripts/generate_changelog.py | 194 | ||||
| -rw-r--r-- | .github/workflows/build.yml | 6 |
2 files changed, 170 insertions, 30 deletions
diff --git a/.github/scripts/generate_changelog.py b/.github/scripts/generate_changelog.py index c4ea8a2..4c5d7c1 100644 --- a/.github/scripts/generate_changelog.py +++ b/.github/scripts/generate_changelog.py @@ -7,6 +7,8 @@ import argparse import json import os import re +import urllib.error +import urllib.request import subprocess import tempfile from pathlib import Path @@ -73,6 +75,111 @@ def markdown_version(value: str | None) -> str: return value or "—" +MAJOR_PACKAGES = { + "kernel": "Kernel", + "kernel-core": "Kernel", + "kernel-modules": "Kernel", + "kernel-modules-core": "Kernel", + "kernel-modules-extra": "Kernel", + "kernel-tools": "Kernel", + "kernel-devel": "Kernel", + "kernel-headers": "Kernel", + "kernel-lts": "Kernel (Nvidia LTS)", + "linux-firmware": "Firmware", + "mesa-dri-drivers": "Mesa", + "mesa-filesystem": "Mesa", + "mesa-libEGL": "Mesa", + "mesa-libGL": "Mesa", + "mesa-libgbm": "Mesa", + "mesa-va-drivers": "Mesa", + "mesa-vulkan-drivers": "Mesa", + "gamescope": "Gamescope", + "gamescope-session": "Gamescope Session", + "mangohud": "MangoHUD", + "inputplumber": "InputPlumber", + "opengamepadui": "OpenGamepadUI", + "powerstation": "PowerStation", + "steamos-manager": "SteamOS-Manager", + "umu-launcher": "UMU Launcher", + "bazaar": "Bazaar", + "distrobox": "Distrobox", + "gnome-shell": "Gnome", + "plasma-desktop": "KDE", + "waydroid": "Waydroid", +} + + +def major_package_rows( + current_packages: dict[str, str], + previous_packages: dict[str, str] | None, +) -> list[str]: + selected: dict[str, tuple[str | None, str | None]] = {} + for name, current in current_packages.items(): + display_name = MAJOR_PACKAGES.get(name) + if not display_name: + continue + previous = (previous_packages or {}).get(name) + selected[display_name] = (previous, current) + + rows = [] + for display_name, (old, new) in selected.items(): + version = markdown_version(new) + if old and new and old != new: + version = f"{old} ➡️ {new}" + rows.append(f"| **{display_name}** | {version} |") + return rows + + +def all_image_rows(changes: list[tuple[str, str | None, str | None]]) -> list[str]: + rows = [] + for name, old, new in changes: + icon = "➕" if old is None else "➖" if new is None else "🔄" + rows.append( + f"| {icon} | `{name}` | {markdown_version(old)} | {markdown_version(new)} |" + ) + return rows + + +def upstream_release_commit(tag: str) -> str | None: + try: + request = urllib.request.Request( + f"https://api.github.com/repos/ublue-os/bazzite/git/ref/tags/{tag}", + headers={"Accept": "application/vnd.github+json", "User-Agent": "AeroCore-OS-release-notes"}, + ) + with urllib.request.urlopen(request, timeout=30) as response: + data = json.load(response) + obj = data["object"] + if obj.get("type") == "tag": + request = urllib.request.Request( + f"https://api.github.com/repos/ublue-os/bazzite/git/tags/{obj['sha']}", + headers={"Accept": "application/vnd.github+json", "User-Agent": "AeroCore-OS-release-notes"}, + ) + with urllib.request.urlopen(request, timeout=30) as response: + obj = json.load(response)["object"] + return obj.get("sha") + except (urllib.error.URLError, urllib.error.HTTPError, KeyError, json.JSONDecodeError): + return None + + +def upstream_compare_commits(start_revision: str | None, end_revision: str | None) -> list[tuple[str, str, str]]: + if not start_revision or not end_revision or start_revision == end_revision: + return [] + request = urllib.request.Request( + f"https://api.github.com/repos/ublue-os/bazzite/compare/{start_revision}...{end_revision}", + headers={"Accept": "application/vnd.github+json", "User-Agent": "AeroCore-OS-release-notes"}, + ) + with urllib.request.urlopen(request, timeout=60) as response: + compare = json.load(response) + return [ + ( + item["sha"], + item["commit"]["message"].splitlines()[0], + item["commit"].get("author", {}).get("name", "Unknown"), + ) + for item in compare.get("commits", []) + ] + + def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--image", required=True, help="registry/repository without tag") @@ -89,6 +196,7 @@ def main() -> None: current_info = image_info(args.image, args.current) current_packages = package_map(fetch_sbom(args.image, current_info["Digest"])) + base_image = current_info.get("Labels", {}).get("org.opencontainers.image.base.name") previous_packages: dict[str, str] | None = None if previous: try: @@ -107,47 +215,79 @@ def main() -> None: changes.append((name, old, new)) previous_info = image_info(args.image, previous) if previous else {} + previous_base = previous_info.get("Labels", {}).get("org.opencontainers.image.base.name", "") + previous_base_tag = previous_base.rpartition(":")[2] + current_base_tag = base_image.rpartition(":")[2] if base_image else "" + start_revision = upstream_release_commit(previous_base_tag) if previous_base_tag else None + end_revision = upstream_release_commit(current_base_tag) if current_base_tag else None + upstream_commits = upstream_compare_commits(start_revision, end_revision) + upstream_range_available = bool(start_revision and end_revision) + start_revision = previous_info.get("Labels", {}).get("org.opencontainers.image.revision") end_revision = current_info.get("Labels", {}).get("org.opencontainers.image.revision") - commits: list[str] = [] - if start_revision and end_revision: + aerocore_commits: list[tuple[str, str, str]] = [] + if start_revision and end_revision and start_revision != end_revision: try: - commits = run( - "git", - "log", - "--format=%H%x09%s%x09%an", - f"{start_revision}..{end_revision}", - ).splitlines() + aerocore_commits = [ + (item.split("\t", 2)[0], item.split("\t", 2)[1], item.split("\t", 2)[2]) + for item in run( + "git", "log", "--format=%H%x09%s%x09%an", f"{start_revision}..{end_revision}" + ).splitlines() + ] except subprocess.CalledProcessError as error: - # A release may be built after histories are intentionally joined - # or rewritten. In that case the previous image revision can be - # valid metadata but not a reachable Git revision in this checkout. - # Package changes and the release itself remain valid, so omit the - # commit section instead of failing the whole release job. + # Release metadata can point to revisions outside this checkout's + # history after histories are joined or rewritten. Keep the package + # and upstream changelog sections and omit only AeroCore commits. print( - "Warning: unable to determine commit range " + "Warning: unable to determine AeroCore commit range " f"{start_revision}..{end_revision}: {error}" ) lines = [args.handwritten.strip() or f"This is an automatically generated changelog for release `{args.current}`.", ""] + if base_image: + base_name, _, base_tag = base_image.rpartition(":") + if base_name and base_tag: + base_repo = base_name.removeprefix("docker://") + upstream_version = re.sub(r"^(?:stable|testing|testing-candidate)-", "", base_tag) + lines.append( + f"Based on upstream [{upstream_version}](https://github.com/ublue-os/bazzite/releases/tag/{base_tag}) " + f"(`{base_repo}`)." + ) + else: + lines.append(f"Based on upstream image `{base_image}`.") + lines.append("") if previous: - lines.append(f"From previous `{args.channel}` version `{previous}` there have been the following package changes.") - else: - lines.append("No previous release was found for this channel; package changes are shown against an empty baseline.") - lines += ["", "### Package changes", "", "| Name | Previous | New |", "| --- | --- | --- |"] - if previous and previous_packages is None: - lines.append("| — | Previous release has no attached SBOM | Diff starts with the next release |") - elif not changes: - lines.append("| — | — | — |") + lines.append(f"From previous `{args.channel}` version `{previous}` there have been the following changes. One package per new version shown.") else: - lines += [f"| `{name}` | {markdown_version(old)} | {markdown_version(new)} |" for name, old, new in changes] + lines.append("No previous release was found for this channel; changes are shown against an empty baseline.") + + lines += ["", "### Major packages", "", "| Name | Version |", "| --- | --- |"] + major_rows = major_package_rows(current_packages, previous_packages) + lines.extend(major_rows or ["| — | No major package changes |"]) lines += ["", "### Commits", "", "| Hash | Subject | Author |", "| --- | --- | --- |"] - for commit in commits: - commit_hash, subject, author = commit.split("\t", 2) + if upstream_commits: + lines.append("| **Upstream Bazzite** | | |") + for commit_hash, subject, author in upstream_commits: + lines.append(f"| [{commit_hash[:7]}](https://github.com/ublue-os/bazzite/commit/{commit_hash}) | {subject} | {author} |") + elif upstream_range_available: + lines.append("| **Upstream Bazzite** | No commits between the selected base versions | — |") + else: + lines.append("| **Upstream Bazzite** | Commit range unavailable (previous image may predate base image metadata) | — |") + if aerocore_commits: + lines.append("| **AeroCore OS** | | |") + for commit_hash, subject, author in aerocore_commits: lines.append(f"| [{commit_hash[:7]}](https://github.com/{args.repository}/commit/{commit_hash}) | {subject} | {author} |") - if not commits: - lines.append("| — | No commit range available | — |") + if not aerocore_commits: + lines.append("| **AeroCore OS** | No commits between the selected image versions | — |") + + lines += ["", "### All Images", "", "| | Name | Previous | New |", "| --- | --- | --- | --- |"] + if previous and previous_packages is None: + lines.append("| — | Previous release has no attached SBOM | — | Diff starts with the next release |") + elif not changes: + lines.append("| — | No package changes | — | — |") + else: + lines.extend(all_image_rows(changes)) lines += ["", "### How to switch", "", "For current users, switch to the channel image with:", "", "```bash", f"sudo bootc switch {args.image}:{args.channel}", "", "# Or switch to this exact image:", f"sudo bootc switch {args.image}:{args.current}", "```", ""] args.output.write_text("\n".join(lines)) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0b6b8df..5ec0da4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ env: IMAGE_LOGO_URL: ${{ vars.IMAGE_LOGO_URL || 'https://avatars.githubusercontent.com/u/120078124?s=200&v=4' }} DEFAULT_TAG: ${{ vars.DEFAULT_TAG || 'stable' }} BIB_IMAGE: ${{ vars.BIB_IMAGE || 'quay.io/centos-bootc/bootc-image-builder:latest' }} - BASE_IMAGE: ${{ vars.BASE_IMAGE || 'ghcr.io/ublue-os/bazzite-deck:stable-44.20260908' }} + BASE_IMAGE: ${{ vars.BASE_IMAGE || 'ghcr.io/ublue-os/bazzite-deck:stable-44.20261012' }} FLATPAK_REMOTE_URL: ${{ vars.FLATPAK_REMOTE_URL }} HOMEBREW_BOTTLE_DOMAIN: ${{ vars.HOMEBREW_BOTTLE_DOMAIN }} HOMEBREW_API_DOMAIN: ${{ vars.HOMEBREW_API_DOMAIN }} @@ -95,7 +95,7 @@ jobs: - name: Generate Version and Tags id: gen-version env: - BASE_IMAGE: ${{ vars.BASE_IMAGE || 'ghcr.io/ublue-os/bazzite-deck:stable-44.20260908' }} + BASE_IMAGE: ${{ vars.BASE_IMAGE || 'ghcr.io/ublue-os/bazzite-deck:stable-44.20261012' }} run: | set -euo pipefail @@ -162,7 +162,7 @@ jobs: id: build-image env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BASE_IMAGE: ${{ vars.BASE_IMAGE || 'ghcr.io/ublue-os/bazzite-deck:stable-44.20260908' }} + BASE_IMAGE: ${{ vars.BASE_IMAGE || 'ghcr.io/ublue-os/bazzite-deck:stable-44.20261012' }} FLATPAK_REMOTE_URL: ${{ vars.FLATPAK_REMOTE_URL }} HOMEBREW_BOTTLE_DOMAIN: ${{ vars.HOMEBREW_BOTTLE_DOMAIN }} HOMEBREW_API_DOMAIN: ${{ vars.HOMEBREW_API_DOMAIN }} |
