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®
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
# push master -> also publish it as the `beta` branch of the Catcrafts
# repo and refresh the rolling `latest` release
# tag X.Y.Z -> publish it as `stable` and create release X.Y.Z
# push master -> also publish it as `stable` and cut release X.Y.Z, the
# metainfo's newest <release>: its tag at the pushed commit
# 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
# crafter-build and LLVM compile this project, so the runner installs that
@ -27,7 +30,6 @@ on:
branches: [master]
push:
branches: [master]
tags: ['[0-9]*.[0-9]*.[0-9]*']
workflow_dispatch:
env:
@ -79,29 +81,22 @@ jobs:
id: meta
run: |
set -eu
if [ "${GITHUB_REF_TYPE}" = tag ]; then
version="$GITHUB_REF_NAME"
branch=stable
# The metainfo's newest release is the release notes and must be
# the version being tagged.
top=$(grep -m1 -oP '<release version="\K[^"]+' "$METAINFO")
if [ "$top" != "$version" ]; then
echo "metainfo lists $top as the newest release, but the tag is $version" >&2
exit 1
fi
else
# 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" ;;
# The metainfo's newest release is the version and its notes. On
# master it must be new: its tag must not exist yet, and a lookup
# that cannot tell stops the job as well.
version=$(grep -m1 -oP '<release version="\K[^"]+' "$METAINFO")
if [ "${GITHUB_REF}" = refs/heads/master ]; then
code=0
git ls-remote --exit-code --tags origin "refs/tags/$version" > /dev/null || code=$?
case "$code" in
0) echo "the metainfo's newest release, $version, is released already: a push to master names a new <release> in $METAINFO" >&2; exit 1 ;;
2) ;;
*) echo "git ls-remote exited $code: cannot tell whether $version is released" >&2; exit 1 ;;
esac
branch=beta
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "branch=$branch" >> "$GITHUB_OUTPUT"
echo "version $version, flatpak branch $branch"
echo "branch=stable" >> "$GITHUB_OUTPUT"
echo "version $version, flatpak branch stable"
- name: Build
# 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
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
if: github.event_name != 'pull_request'
if: github.ref == 'refs/heads/master'
run: |
mkdir -p dist
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
- name: Upload bundle
if: github.event_name != 'pull_request'
if: github.ref == 'refs/heads/master'
uses: actions/upload-artifact@v3
with:
name: crafter-review-${{ steps.meta.outputs.version }}
@ -182,7 +177,7 @@ jobs:
if-no-files-found: error
- name: Publish to the Catcrafts repo
if: github.event_name != 'pull_request'
if: github.ref == 'refs/heads/master'
run: |
set -eu
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"
flock -u 9
- name: Rolling 'latest' release
if: github.event_name != 'pull_request' && github.ref_type != 'tag'
- name: Tag the release
if: github.ref == 'refs/heads/master'
run: |
git config user.email "ci@catcrafts.net"
git config user.name "Crafter Review CI"
git tag -f latest
git push origin latest --force
- 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 }}
# The release's tag at the pushed commit. Never forced: a tag that
# appeared since the version check fails the push.
git tag "${{ steps.meta.outputs.version }}" "$GITHUB_SHA"
git push origin "refs/tags/${{ steps.meta.outputs.version }}"
- name: Release notes
if: github.ref_type == 'tag'
if: github.ref == 'refs/heads/master'
run: |
# The newest <release> block's description as Markdown, the way
# 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")
EOF
- name: Publish release
if: github.ref_type == 'tag'
if: github.ref == 'refs/heads/master'
uses: https://code.forgejo.org/actions/forgejo-release@v2
with:
direction: upload
url: ${{ github.server_url }}
repo: ${{ github.repository }}
tag: ${{ github.ref_name }}
title: crafter-review ${{ github.ref_name }}
tag: ${{ steps.meta.outputs.version }}
title: crafter-review ${{ steps.meta.outputs.version }}
release-notes-file: release-notes.md
release-dir: dist
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.
- **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 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'
```
`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:

View file

@ -27,10 +27,18 @@
</provides>
<content_rating type="oars-1.1"/>
<releases>
<release version="1.0.0" date="2026-10-31">
<release version="1.0.0" date="2026-11-02">
<description>
<p>First release: the pre-push review gates in C++26, shipped as a Flatpak.</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>
<p>New</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>
</release>
</releases>