From cc95c7c28a1f7eaa2b49d1e328fec8d3a7843619 Mon Sep 17 00:00:00 2001 From: Mathih13 Date: Sat, 10 Oct 2026 13:52:58 +0200 Subject: [PATCH] ci(packages): tag the collection after Package API checks pass --- .github/tag-api-version.sh | 19 ++++++++++++++ .github/test-tag-api-version.sh | 46 +++++++++++++++++++++++++++++++++ .github/workflows/core-tip.yml | 32 +++++++++++++++++++++++ README.md | 15 ++++++++--- 4 files changed, 108 insertions(+), 4 deletions(-) create mode 100755 .github/tag-api-version.sh create mode 100755 .github/test-tag-api-version.sh diff --git a/.github/tag-api-version.sh b/.github/tag-api-version.sh new file mode 100755 index 00000000..1d522cc1 --- /dev/null +++ b/.github/tag-api-version.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +version=${1:-} +if [[ $# -ne 1 || ! "$version" =~ ^[1-9][0-9]*$ ]]; then + echo "usage: $0 PACKAGE-API-VERSION" >&2 + exit 2 +fi + +checked_sha=$(git rev-parse HEAD) +main_ref=$(git ls-remote --exit-code origin refs/heads/main) +main_sha=${main_ref%%$'\t'*} +if [[ "$checked_sha" != "$main_sha" ]]; then + echo "Skipping api-v$version: main has advanced beyond the checked collection." + exit 0 +fi + +# Each version keeps its own tag when Core moves to a newer Package API. +git push origin "$checked_sha:refs/tags/api-v$version" --force diff --git a/.github/test-tag-api-version.sh b/.github/test-tag-api-version.sh new file mode 100755 index 00000000..4a63eac5 --- /dev/null +++ b/.github/test-tag-api-version.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_root=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +test_root=$(mktemp -d) +trap 'rm -rf -- "$test_root"' EXIT + +git init --bare -q "$test_root/remote" +git init -b main -q "$test_root/collection" +cd "$test_root/collection" +git config user.name 'Package tag test' +git config user.email 'package-tag@example.invalid' +git remote add origin "$test_root/remote" +git -c commit.gpgsign=false commit -qm first --allow-empty +git push -q origin main +first=$(git rev-parse HEAD) + +"$script_root/tag-api-version.sh" 1 +test "$(git --git-dir="$test_root/remote" rev-parse refs/tags/api-v1)" = "$first" + +git -c commit.gpgsign=false commit -qm second --allow-empty +git push -q origin main +second=$(git rev-parse HEAD) +"$script_root/tag-api-version.sh" 1 +test "$(git --git-dir="$test_root/remote" rev-parse refs/tags/api-v1)" = "$second" + +git -c commit.gpgsign=false commit -qm third --allow-empty +git push -q origin main +third=$(git rev-parse HEAD) +"$script_root/tag-api-version.sh" 2 +test "$(git --git-dir="$test_root/remote" rev-parse refs/tags/api-v2)" = "$third" +test "$(git --git-dir="$test_root/remote" rev-parse refs/tags/api-v1)" = "$second" + +# A delayed run must not replace a tag with an older collection commit. +git checkout -q --detach "$first" +"$script_root/tag-api-version.sh" 1 +test "$(git --git-dir="$test_root/remote" rev-parse refs/tags/api-v1)" = "$second" + +for invalid in '' 0 01 -1 '1/other'; do + if "$script_root/tag-api-version.sh" "$invalid"; then + echo "accepted invalid Package API version '$invalid'" >&2 + exit 1 + fi +done + +echo 'Package API tag publication checks passed.' diff --git a/.github/workflows/core-tip.yml b/.github/workflows/core-tip.yml index 0fa3a6e1..6238b409 100644 --- a/.github/workflows/core-tip.yml +++ b/.github/workflows/core-tip.yml @@ -30,6 +30,9 @@ jobs: ./.github/test-artifact-firewall.sh ./.github/check-artifact-firewall.sh + - name: Test Package API tag publication + run: ./.github/test-tag-api-version.sh + package-api-exemptions: runs-on: ubuntu-latest timeout-minutes: 5 @@ -54,6 +57,8 @@ jobs: needs: firewall runs-on: ubuntu-latest timeout-minutes: 30 + outputs: + package-api-version: ${{ steps.package-api.outputs.version }} steps: - name: Check out Packages @@ -73,6 +78,17 @@ jobs: - name: Install Rust 1.93.0 run: rustup toolchain install 1.93.0 --profile minimal --component rustfmt --component clippy + - name: Read the checked Core revision's Package API version + id: package-api + run: | + heading=$(head -n 1 lyracore/docs/package-api.md) + version=${heading#\# Package API, version } + if [[ "$heading" == "$version" || ! "$version" =~ ^[1-9][0-9]*$ ]]; then + echo "Core does not declare a Package API version" >&2 + exit 1 + fi + echo "version=$version" >> "$GITHUB_OUTPUT" + - name: Check Package test formatting, lints and discovery run: | ./collection/.github/check-core-tip.sh "$GITHUB_WORKSPACE/lyracore" \ @@ -88,6 +104,22 @@ jobs: - name: Compile every Package against the required Core revision run: ./collection/.github/check-core-tip.sh "$GITHUB_WORKSPACE/lyracore" + package-api-tag: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: [module, datascripts, package-api-exemptions] + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: write + steps: + - name: Check out the tested collection + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Move its Package API tag + env: + PACKAGE_API_VERSION: ${{ needs.module.outputs.package-api-version }} + run: ./.github/tag-api-version.sh "$PACKAGE_API_VERSION" + datascripts: needs: firewall runs-on: ubuntu-latest diff --git a/README.md b/README.md index 63ff8495..d58a7f6f 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,13 @@ This repository is LyraCore's Official Package Collection. Each visible top-level directory is one independently installable Package. There is no separate registry or index file. -`main` tracks LyraCore `main`. When LyraCore starts publishing releases, this repository will use -matching tags for compatible Package revisions. +Each Package API version has a tag, such as `api-v1`. After the compatibility checks pass on +`main`, CI moves the tag for the checked Core revision's Package API version to that collection +commit. Tags for older API versions stay at their last compatible commit. + +`lyracore packages add ` and `lyracore packages update` select the tag from the version in +the checkout's `docs/package-api.md`. A missing tag refuses the operation. Each installed Package's +Provenance Stamp records the exact collection commit it came from. ## Packages @@ -20,7 +25,8 @@ core patch before installing it. CI installs every Package into a clean checkout of [`LyraCoreProject/LyraCore`](https://github.com/LyraCoreProject/LyraCore) and runs the Module library -tests against core tip. A Package API or schema incompatibility fails the collection build. +tests against the Core revision pinned in `.github/workflows/core-tip.yml`. A Package API or +schema incompatibility fails the collection build. To run the same check locally against a clean LyraCore checkout: @@ -28,7 +34,8 @@ To run the same check locally against a clean LyraCore checkout: ./.github/check-core-tip.sh /path/to/LyraCore ``` -The check refuses a core checkout whose `packages/` directory is not empty. +The check temporarily links collection Packages into Core. It restores any in-tree Packages with +matching names when it exits. ## Contributing