ci: every push to master is a release, the metainfo's newest
Some checks failed
Flatpak / flatpak (push) Has been cancelled

A push to master published the build as the rolling `beta` branch and
refreshed a `latest` prerelease; a tag cut the stable release. Now every
push to master is the release: CI takes the version from the
metainfo's newest <release>, publishes `stable`, tags the pushed commit
and creates the release with that entry's notes. A version that is
released already fails the job before anything is built or published,
and so does a lookup that cannot tell, so a push to master adds a new
<release>. Publishing is master's alone: a manual run on another branch
builds and tests and cuts nothing. Tags are no longer a trigger, and the
rolling `beta` and `latest` steps are gone. The README and AGENTS say
so, and the first release's entry, 1.0.0, takes the date of its push
and names what it ships.
This commit is contained in:
Jorijn van der Graaf 2026-11-02 10:57:23 +01:00
commit 2b4faea87b
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
4 changed files with 47 additions and 57 deletions

View file

@ -2,11 +2,14 @@
# SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® # SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
name: Flatpak name: Flatpak
# Crafter.Build's workflow, for this app. One job, three outcomes: # Crafter.Build's workflow, for this app, with one change: every push to
# master is a release (2026-11-02: no rolling `beta` or `latest` builds).
# One job, two outcomes:
# pull request -> build the Flatpak, run the suite inside it, smoke-test it # pull request -> build the Flatpak, run the suite inside it, smoke-test it
# push master -> also publish it as the `beta` branch of the Catcrafts # push master -> also publish it as `stable` and cut release X.Y.Z, the
# repo and refresh the rolling `latest` release # metainfo's newest <release>: its tag at the pushed commit
# tag X.Y.Z -> publish it as `stable` and create release X.Y.Z # and its notes. A version that is released already fails
# the job before anything is built or published.
# #
# It builds on the Crafter.Build Flatpak (`base:` in the manifest), whose # It builds on the Crafter.Build Flatpak (`base:` in the manifest), whose
# crafter-build and LLVM compile this project, so the runner installs that # crafter-build and LLVM compile this project, so the runner installs that
@ -27,7 +30,6 @@ on:
branches: [master] branches: [master]
push: push:
branches: [master] branches: [master]
tags: ['[0-9]*.[0-9]*.[0-9]*']
workflow_dispatch: workflow_dispatch:
env: env:
@ -79,29 +81,22 @@ jobs:
id: meta id: meta
run: | run: |
set -eu set -eu
if [ "${GITHUB_REF_TYPE}" = tag ]; then # The metainfo's newest release is the version and its notes. On
version="$GITHUB_REF_NAME" # master it must be new: its tag must not exist yet, and a lookup
branch=stable # that cannot tell stops the job as well.
# The metainfo's newest release is the release notes and must be version=$(grep -m1 -oP '<release version="\K[^"]+' "$METAINFO")
# the version being tagged. if [ "${GITHUB_REF}" = refs/heads/master ]; then
top=$(grep -m1 -oP '<release version="\K[^"]+' "$METAINFO") code=0
if [ "$top" != "$version" ]; then git ls-remote --exit-code --tags origin "refs/tags/$version" > /dev/null || code=$?
echo "metainfo lists $top as the newest release, but the tag is $version" >&2 case "$code" in
exit 1 0) echo "the metainfo's newest release, $version, is released already: a push to master names a new <release> in $METAINFO" >&2; exit 1 ;;
fi 2) ;;
else *) echo "git ls-remote exited $code: cannot tell whether $version is released" >&2; exit 1 ;;
# Named after the release it follows, as a checkout describes
# itself: 1.0.0-3-g21746b1 is three commits past 1.0.0.
described=$(git describe --tags --always --exclude=latest)
case "$described" in
[0-9]*.[0-9]*.[0-9]*) version="$described" ;;
*) version="0.0.0-dev+$described" ;;
esac esac
branch=beta
fi fi
echo "version=$version" >> "$GITHUB_OUTPUT" echo "version=$version" >> "$GITHUB_OUTPUT"
echo "branch=$branch" >> "$GITHUB_OUTPUT" echo "branch=stable" >> "$GITHUB_OUTPUT"
echo "version $version, flatpak branch $branch" echo "version $version, flatpak branch stable"
- name: Build - name: Build
# The manifest is rewritten beside the original so its relative # The manifest is rewritten beside the original so its relative
@ -163,9 +158,9 @@ jobs:
if [ "$code" != 2 ]; then echo "the dry run exited $code, not 2" >&2; exit 1; fi if [ "$code" != 2 ]; then echo "the dry run exited $code, not 2" >&2; exit 1; fi
ls scratch/*-dry/prompts | head -3' ls scratch/*-dry/prompts | head -3'
# Everything below publishes and only runs on master and on tags. # Everything below publishes and only runs on master.
- name: Bundle - name: Bundle
if: github.event_name != 'pull_request' if: github.ref == 'refs/heads/master'
run: | run: |
mkdir -p dist mkdir -p dist
flatpak build-bundle repo "dist/crafter-review-${{ steps.meta.outputs.version }}.flatpak" "$APP_ID" "${{ steps.meta.outputs.branch }}" flatpak build-bundle repo "dist/crafter-review-${{ steps.meta.outputs.version }}.flatpak" "$APP_ID" "${{ steps.meta.outputs.branch }}"
@ -174,7 +169,7 @@ jobs:
ls -la dist ls -la dist
- name: Upload bundle - name: Upload bundle
if: github.event_name != 'pull_request' if: github.ref == 'refs/heads/master'
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: crafter-review-${{ steps.meta.outputs.version }} name: crafter-review-${{ steps.meta.outputs.version }}
@ -182,7 +177,7 @@ jobs:
if-no-files-found: error if-no-files-found: error
- name: Publish to the Catcrafts repo - name: Publish to the Catcrafts repo
if: github.event_name != 'pull_request' if: github.ref == 'refs/heads/master'
run: | run: |
set -eu set -eu
if [ ! -s /run/crafter-flatpak/signing-key.asc ] || [ ! -s /run/crafter-flatpak/key-id ]; then if [ ! -s /run/crafter-flatpak/signing-key.asc ] || [ ! -s /run/crafter-flatpak/key-id ]; then
@ -208,29 +203,16 @@ jobs:
sed "s|GPGKey=.*|GPGKey=$key|" packaging/flatpak/net.catcrafts.CrafterReview.flatpakref > "$WEB_DIR/net.catcrafts.CrafterReview.flatpakref" sed "s|GPGKey=.*|GPGKey=$key|" packaging/flatpak/net.catcrafts.CrafterReview.flatpakref > "$WEB_DIR/net.catcrafts.CrafterReview.flatpakref"
flock -u 9 flock -u 9
- name: Rolling 'latest' release - name: Tag the release
if: github.event_name != 'pull_request' && github.ref_type != 'tag' if: github.ref == 'refs/heads/master'
run: | run: |
git config user.email "ci@catcrafts.net" # The release's tag at the pushed commit. Never forced: a tag that
git config user.name "Crafter Review CI" # appeared since the version check fails the push.
git tag -f latest git tag "${{ steps.meta.outputs.version }}" "$GITHUB_SHA"
git push origin latest --force git push origin "refs/tags/${{ steps.meta.outputs.version }}"
- name: Publish rolling 'latest' release
if: github.event_name != 'pull_request' && github.ref_type != 'tag'
uses: https://code.forgejo.org/actions/forgejo-release@v2
with:
direction: upload
url: ${{ github.server_url }}
repo: ${{ github.repository }}
tag: latest
title: Latest master build
prerelease: true
override: true
release-dir: dist
token: ${{ secrets.GITHUB_TOKEN }}
- name: Release notes - name: Release notes
if: github.ref_type == 'tag' if: github.ref == 'refs/heads/master'
run: | run: |
# The newest <release> block's description as Markdown, the way # The newest <release> block's description as Markdown, the way
# Crafter.Build's workflow writes its notes. # Crafter.Build's workflow writes its notes.
@ -261,14 +243,14 @@ jobs:
print("\nInstall:\n\n flatpak remote-add --if-not-exists catcrafts https://flatpak.catcrafts.net/catcrafts.flatpakrepo\n flatpak install catcrafts net.catcrafts.CrafterReview\n") print("\nInstall:\n\n flatpak remote-add --if-not-exists catcrafts https://flatpak.catcrafts.net/catcrafts.flatpakrepo\n flatpak install catcrafts net.catcrafts.CrafterReview\n")
EOF EOF
- name: Publish release - name: Publish release
if: github.ref_type == 'tag' if: github.ref == 'refs/heads/master'
uses: https://code.forgejo.org/actions/forgejo-release@v2 uses: https://code.forgejo.org/actions/forgejo-release@v2
with: with:
direction: upload direction: upload
url: ${{ github.server_url }} url: ${{ github.server_url }}
repo: ${{ github.repository }} repo: ${{ github.repository }}
tag: ${{ github.ref_name }} tag: ${{ steps.meta.outputs.version }}
title: crafter-review ${{ github.ref_name }} title: crafter-review ${{ steps.meta.outputs.version }}
release-notes-file: release-notes.md release-notes-file: release-notes.md
release-dir: dist release-dir: dist
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}

View file

@ -239,7 +239,7 @@ Runs and Commands drop every `REVIEW_GATES_*`, `CRAFTER_REVIEW_*`, `SEATS_ENV_FI
`.forgejo/workflows/ci.yaml` is Crafter.Build's workflow for this app. `.forgejo/workflows/ci.yaml` is Crafter.Build's workflow for this app.
- **Builds.** A pull request builds the Flatpak, runs the suite inside it and smoke-tests the app as it ships: the version and home, every library resolved and no RUNPATH outside `/app`, the bundled tools, and a freeze and a dry run on a scratch repository. - **Builds.** A pull request builds the Flatpak, runs the suite inside it and smoke-tests the app as it ships: the version and home, every library resolved and no RUNPATH outside `/app`, the bundled tools, and a freeze and a dry run on a scratch repository.
- **Publishing.** A push to master also publishes `beta`, and a tag `X.Y.Z` publishes `stable` and creates the release. The tag must equal the metainfo's newest `<release>`. - **Publishing.** Every push to master is a release (2026-11-02, Jorijn: no rolling `beta` or `latest` builds): CI publishes `stable`, tags the pushed commit with the version of the metainfo's newest `<release>` and creates the release with its notes. A push to master therefore adds a new `<release>`; one whose version is released already fails the job before anything is built or published.
- **The runner.** It runs on the `crafter-flatpak` runner, registered to Crafter.Build alone today: until this repository has such a runner, the workflow does not run, and it is unverified on the forge. Its smoke test passes when run by hand against a local build. - **The runner.** It runs on the `crafter-flatpak` runner, registered to Crafter.Build alone today: until this repository has such a runner, the workflow does not run, and it is unverified on the forge. Its smoke test passes when run by hand against a local build.
- **The shared repo.** Both apps publish into one repo. The publish step holds `/srv/flatpak/.publish.lock`, which protects anything only once Crafter.Build's workflow takes the same lock. This one writes its own flatpakref and never the shared `catcrafts.flatpakrepo`. - **The shared repo.** Both apps publish into one repo. The publish step holds `/srv/flatpak/.publish.lock`, which protects anything only once Crafter.Build's workflow takes the same lock. This one writes its own flatpakref and never the shared `catcrafts.flatpakrepo`.

View file

@ -23,7 +23,7 @@ flatpak install catcrafts net.catcrafts.CrafterReview
alias crafter-review='flatpak run net.catcrafts.CrafterReview' alias crafter-review='flatpak run net.catcrafts.CrafterReview'
``` ```
`master` builds are the `beta` branch (`net.catcrafts.CrafterReview//beta`). The alias is for people: the `/prepush` skill spells every command as `flatpak run net.catcrafts.CrafterReview …`, because Claude's Bash tool sees no aliases. Every push to `master` is a release, published as `stable`. The alias is for people: the `/prepush` skill spells every command as `flatpak run net.catcrafts.CrafterReview …`, because Claude's Bash tool sees no aliases.
What the machine provides: What the machine provides:

View file

@ -27,10 +27,18 @@
</provides> </provides>
<content_rating type="oars-1.1"/> <content_rating type="oars-1.1"/>
<releases> <releases>
<release version="1.0.0" date="2026-10-31"> <release version="1.0.0" date="2026-11-02">
<description> <description>
<p>First release: the pre-push review gates in C++26, shipped as a Flatpak.</p> <p>New</p>
<p>Every lens is off until the repository's config turns it on. The commit-truth lens, repo-facts, reads the commit messages and the documentation of the range as Gate 4.</p> <ul>
<li>Pre-push review gates for a commit range: Claude processes review the approach, the running application, a bug proof, security and the commit messages, and a range is send-ready only when every gate passes on its exact frozen hash.</li>
<li><code>crafter-review init</code> sets a repository up: its config and the <code>/prepush</code> skill.</li>
<li>Modes in the repository's config (<code>modes.&lt;name&gt;</code>): the kind of artifact, the lenses it runs and their effort. Every lens is off until a mode lists it.</li>
<li>Seats from a dotenv file - <code>--env-file</code>, <code>$SEATS_ENV_FILE</code>, the working directory's <code>.env</code> or the machine's own <code>~/.config/crafter-review/env</code> - over the environment's, on one seat board for every driver on a machine.</li>
<li>A repository's own section appended to a lens's charter (<code>lenses.&lt;name&gt;.section</code>).</li>
<li>Pre-send review of a kernel patch series or a mailing-list reply (<code>--mode series</code>, <code>--mode reply</code>).</li>
<li>Shipped as a Flatpak with its own git, Node and ripgrep.</li>
</ul>
</description> </description>
</release> </release>
</releases> </releases>