From c4c4ef7425d8bd1cb256726c170373dbbf60adcb Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Nov 2026 10:58:02 -0600 Subject: [PATCH] ci: the release deploys /apt from a commit Pages has not seen, and checks it lists the release Pages keeps the first deploy of a commit, and the tagged commit was deployed by its own push before the release had its .deb files: 2.4.0's /apt stayed at 2.3.0. update-apt now runs after commit-package-files, starts pages.yml on main's newest commit (the package-files commit, which nothing deployed), and reads /apt's Packages for amd64 and arm64 until they list the release. pages.yml drops the chore: release guard and its workflow_call trigger. --- .github/workflows/pages.yml | 19 +++--------- .github/workflows/release.yml | 57 ++++++++++++++++++++++++++++++----- CHANGELOG.md | 2 ++ RELEASE.md | 4 +-- 4 files changed, 58 insertions(+), 24 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 11cd62c..438430d 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -2,9 +2,10 @@ name: Pages # proc-cli.com: the Jekyll site in docs/, plus the signed apt repository at # /apt, built from the .deb files of the last three releases that have them -# (pkg/apt/build-repo.sh). Runs on changes to the site, and from release.yml -# after each release, since a release made by the workflow's own token starts -# no other workflow. +# (pkg/apt/build-repo.sh). Runs on changes to the site, and after each release, +# whose update-apt job starts it on main's newest commit (release.yml says why +# that commit), since a release made by the workflow's own token starts no +# other workflow. on: push: branches: [main] @@ -13,10 +14,6 @@ on: - 'pkg/apt/**' - '.github/workflows/pages.yml' workflow_dispatch: - workflow_call: - secrets: - APT_SIGNING_KEY: - required: false permissions: contents: read @@ -31,14 +28,6 @@ concurrency: jobs: build: name: Build site and apt repository - # A deploy is named after its commit, and Pages keeps the first deploy of a - # commit: the release commit's own push to main would deploy it before the - # release has its .deb files, and the release's deploy of the same commit - # would change nothing (2.3.0's apt repository stayed at 2.2.0). The release - # deploys that commit itself, from update-apt in release.yml. - if: >- - !(github.ref == 'refs/heads/main' - && startsWith(github.event.head_commit.message, 'chore: release v')) runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 698e22f..9b3bf0c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -760,17 +760,60 @@ jobs: git diff --staged --quiet || git commit -m "proc ${{ github.ref_name }}" git push + # Pages keeps the first deploy of a commit and ignores the next, and nearly + # every push to main deploys (each change regenerates docs/changelog.md), so + # the tagged commit was deployed before the release had its .deb files: 2.4.0 + # deployed it again here, and /apt stayed at 2.3.0. main's newest commit is + # the one commit-package-files pushed, which nothing has deployed (a push + # with this workflow's token starts no workflow), so pages.yml deploys that update-apt: name: Update the apt repository - needs: create-release - if: github.event_name == 'push' + needs: [create-release, commit-package-files] + if: ${{ !cancelled() && github.event_name == 'push' && needs.create-release.result == 'success' }} + runs-on: ubuntu-latest + timeout-minutes: 30 permissions: + actions: write contents: read - pages: write - id-token: write - uses: ./.github/workflows/pages.yml - secrets: - APT_SIGNING_KEY: ${{ secrets.APT_SIGNING_KEY }} + steps: + - name: Deploy main's newest commit + env: + GH_TOKEN: ${{ github.token }} + run: | + head=$(gh api "repos/$GITHUB_REPOSITORY/commits/main" --jq .sha) + if [ "$head" = "$GITHUB_SHA" ]; then + echo "::error::main's newest commit is the tagged one, which Pages deployed before ${GITHUB_REF_NAME}'s packages existed (commit-package-files pushed nothing). After the next push to main, run: gh workflow run pages.yml --ref main" + exit 1 + fi + gh workflow run pages.yml --repo "$GITHUB_REPOSITORY" --ref main + run= + for _ in $(seq 30); do + sleep 10 + run=$(gh run list --repo "$GITHUB_REPOSITORY" --workflow pages.yml \ + --event workflow_dispatch --commit "$head" --limit 1 \ + --json databaseId --jq '.[0].databaseId // empty') + [ -n "$run" ] && break + done + [ -n "$run" ] || { echo "::error::no Pages run started for $head in 5 minutes"; exit 1; } + gh run watch "$run" --repo "$GITHUB_REPOSITORY" --exit-status --interval 15 + + # Pages serves with a 10-minute cache that a query string does not get + # past, so the check reads until the cached copy has expired + - name: Check that /apt lists the release + run: | + version=${GITHUB_REF_NAME#v} + for arch in amd64 arm64; do + url=https://proc-cli.com/apt/dists/stable/main/binary-$arch/Packages + for _ in $(seq 30); do + if curl -fsS "$url" | grep -qx "Version: $version"; then + echo "$url lists $version" + continue 2 + fi + sleep 30 + done + echo "::error::$url does not list $version after 15 minutes" + exit 1 + done update-winget: name: Update winget diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e8fee2..f5e44fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- **The apt repository gets the release's packages, and the release checks it.** 2.4.0's `/apt` kept listing 2.3.0 until it was redeployed by hand. Pages keeps the first deploy of a commit and ignores the next, and nearly every push to main deploys, so the tagged commit had been deployed before the release had its `.deb` files; the guard added in 2.3.0 skipped only a commit titled `chore: release v…`, and 2.4.0 tagged a later commit. `update-apt` now waits for "Commit the package files" and starts `pages.yml` on main's newest commit, which that job pushed and nothing has deployed, then reads `/apt`'s package lists for amd64 and arm64 until they show the release, and fails if they don't within 15 minutes. If no package commit was pushed, it fails at once and says how to deploy. `pages.yml` drops the guard and its `workflow_call` trigger. Nothing changed in proc + - **Two more tests no longer fail on timing.** `coloured_text_is_the_plain_text_plus_escape_codes` runs `proc list` with and without colour and compares the text. 2.4.0 made it rerun the pair until both printed the same cells, but on Windows CI 10 pairs in a row differed, the last on the listener's uptime (10s against 11s). Digits are now compared as digits, not as values, so a ticking figure matches; a figure that changes its width, or a cell that changes its word, still reruns the pair, and the spacing must still match. It still fails when colour changes the spacing (checked by planting a space in coloured cells). `a_process_records_its_parents_name_and_its_children` compared a `sleep`'s parent name with its shell's name from a later read of the process table. On macOS `sh` is a launcher that turns into `bash`, and under load one read could see the shell as `sh` and the `sleep` that `bash` started (the unit tests failed 4 of 8 runs on a Mac, 0 of 8 after); it now compares the two from the same read. Nothing changed in proc ## [2.4.0] - 2026-11-11 diff --git a/RELEASE.md b/RELEASE.md index c9be565..2d757e9 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -222,7 +222,7 @@ After tag push, monitor GitHub Actions: - [ ] Homebrew tap updated - [ ] Scoop bucket updated - [ ] Docker image pushed -- [ ] "Update the apt repository" passed: https://proc-cli.com/apt/dists/stable/main/binary-amd64/Packages lists the new version. The release commit's own push to main deploys nothing (`pages.yml` skips a commit titled `chore: release v…`, since Pages keeps only the first deploy of a commit), so the site, the new version on it included, changes when this job deploys +- [ ] "Update the apt repository" passed: https://proc-cli.com/apt/dists/stable/main/binary-amd64/Packages lists the new version; the job checks it itself, for amd64 and arm64, and fails if it doesn't. Pages keeps only the first deploy of a commit, and the tagged commit was deployed by its own push, before the release had its `.deb` files, so the job deploys main's newest commit instead: the one "Commit the package files" pushed. If that job pushed nothing, this one fails and says so: deploy after the next push to main with `gh workflow run pages.yml --ref main` - [ ] "Update winget" opened the pull request for the new version on microsoft/winget-pkgs (until the first version is merged it skips, with a notice). The day the first version (2.2.0, microsoft/winget-pkgs#469298) is merged, rerun that job in the latest release's run, so winget catches up without waiting for the next release: `gh run rerun --job ` (the ids are in `gh run view --json jobs`) - [ ] The PPA's builds for the new version succeeded on every release and both architectures (https://launchpad.net/~yazeedaloyoun/+archive/ubuntu/proc-cli/+packages) - [ ] "Update COPR" passed: the build for the new version succeeded on every chroot (https://copr.fedorainfracloud.org/coprs/yazeed/proc-cli/builds/) @@ -347,7 +347,7 @@ On tag push, GitHub Actions handles: 6. **Homebrew**: Update yazeed/homebrew-proc tap 7. **Scoop**: Update yazeed/scoop-bucket-proc bucket 8. **Docker**: Push to yazeed/proc-cli on Docker Hub, and the same build to yazeed/proc (the image's original name). A separate workflow (`docker.yml`) with its own tag check: it stops if the tag isn't `v` + Cargo.toml's version -9. **apt repository**: `update-apt` runs `pages.yml`, which deploys proc-cli.com with `/apt` rebuilt from the `.deb` files of the last three releases and signed with `APT_SIGNING_KEY` (`pkg/apt/build-repo.sh`) +9. **apt repository**: `update-apt`, after `commit-package-files`, starts `pages.yml` on main's newest commit and checks that `/apt` lists the release; `pages.yml` deploys proc-cli.com with `/apt` rebuilt from the `.deb` files of the last three releases and signed with `APT_SIGNING_KEY` (`pkg/apt/build-repo.sh`) 10. **winget**: `update-winget` opens the pull request for the new version on microsoft/winget-pkgs from the `yazeed/winget-pkgs` fork, with `WINGET_TOKEN` (winget-releaser; the fork must keep that name). It skips, with a notice, until a first version of `yazeed.proc-cli` is in winget-pkgs 11. **COPR**: `update-copr` sends the version to the project's custom webhook (`COPR_WEBHOOK`). COPR runs the package's build script (`pkg/copr/copr-build.sh`, kept in COPR), which fetches `pkg/copr/sources.sh` and the spec at the tag and makes the source RPM: the spec at that version with a changelog entry, the tag's tarball and every crate `Cargo.lock` names. COPR then builds it for each chroot of `yazeed/proc-cli` (Fedora, EPEL 9 and 10, Amazon Linux 2023); the job follows the build on COPR's API and fails if it fails. Fedora's new releases join the project by themselves ("Follow Fedora branching"). To change the script COPR keeps, edit the file and run `copr-cli edit-package-custom proc-cli --script pkg/copr/copr-build.sh --script-builddeps "curl cargo tar xz"`; `pkg/copr/srpm.sh X.Y.Z` builds the same source RPM locally 12. **PyPI**: `pip install proc-cli` (also `pipx` and `uv tool`). `package-pypi` repacks the five release binaries into five wheels with `pkg/pypi/build-wheels.py` (standard library only; no maturin, no second Rust build): `manylinux_2_17`/`manylinux2014`/`musllinux_1_1` for Linux x86_64 and aarch64 (the static musl binaries), `macosx_10_12_x86_64` and `macosx_11_0_arm64` (each binary's own minimum macOS, read with `vtool -show-build`; check it again when the build target changes) and `win_amd64`, each holding the binary as the `proc` command. It checks the metadata with `twine check` and expects exactly five wheels. `test-pypi` installs the wheel with pip on its own OS (Ubuntu x86_64 and arm64, an Alpine container for musl, macOS arm64 and Intel, Windows) with `pkg/pypi/test-install.sh` and checks `proc --version`. `publish-pypi` runs for a tag, after the GitHub Release and every `test-pypi` job, and uploads the wheels with trusted publishing (environment `pypi`). The wheels are not release files. There is no TestPyPI run: its `proc-cli` belongs to an unrelated project