From 96e80da5357c5181e0ea00cb271eb7f3f2815abf Mon Sep 17 00:00:00 2001 From: Compot Developer Date: Sun, 18 Oct 2026 12:58:18 +0000 Subject: [PATCH 1/2] check-version.sh: compare with HEAD^1, skip Markdown, count build.yml as build, no-release label (#68, #69) --- .github/check-version.sh | 60 +++++++++++++++++++++++++------------ .github/workflows/build.yml | 15 ++++++---- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/.github/check-version.sh b/.github/check-version.sh index 8e3e9bb..60dcc1a 100755 --- a/.github/check-version.sh +++ b/.github/check-version.sh @@ -2,39 +2,56 @@ # # Copyright (c) OpenIPC https://openipc.org MIT License # -# check-version.sh — fail a pull request that changes code or the build -# but not CAMEX_VERSION in src/version.h (#63). The new version must be -# MAJOR.MINOR.PATCH without leading zeros, greater than the base one, -# and have its section in CHANGELOG.md ("## — "). -# src/, android/, the Makefile, ci/ and scripts/ count as code or build; -# docs, tests, screenshots and the workflows in .github/ do not need a new -# version. Same script as OpenIPC/vectis, other paths and version macro. +# check-version.sh — fail a pull request that changes the code or the build +# but not CAMEX_VERSION in src/version.h. A new version must be +# MAJOR.MINOR.PATCH without leading zeros, greater than the base one, and +# have its section in CHANGELOG.md ("## — YYYY-MM-DD") that the +# base branch does not have yet. src/, android/, the Makefile, ci/, +# scripts/ and the build workflow (.github/workflows/build.yml) count as code +# or build, without the Markdown files in them; docs, tests, screenshots and +# the rest of .github/ need no new version. NO_RELEASE=true (the pull +# request's `no-release` label) lets a change to the code or the build +# through without a new version, for changes that leave the release files as +# they are (a test or publication step, a build-script tidy-up, a comment). # -# Usage: .github/check-version.sh [BASE] (default origin/master) +# Usage: .github/check-version.sh [BASE] (default origin/master; CI passes +# HEAD^1, the base side of the pull request's merge commit) # set -eu base=${1:-origin/master} -code="src android Makefile ci scripts" +header=src/version.h +code="src android Makefile ci scripts .github/workflows/build.yml" -ver() { sed -n 's/^#define CAMEX_VERSION *"\(.*\)"/\1/p'; } - -new=$(ver < src/version.h) -old=$(git show "$base:src/version.h" | ver) +# The one CAMEX_VERSION definition (comments and other text do not count). +ver() { + v=$(sed -n 's/^#define CAMEX_VERSION "\([^"]*\)"[[:space:]]*$/\1/p') + if [ "$(printf '%s\n' "$v" | grep -c .)" -ne 1 ]; then + echo "::error::$1:$header: expected one CAMEX_VERSION definition," \ + "found: $(printf '%s' "$v" | tr '\n' ' ')" >&2 + exit 1 + fi + printf '%s\n' "$v" +} -if ! echo "$new" | grep -Eq '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'; then - echo "::error::CAMEX_VERSION \"$new\" is not MAJOR.MINOR.PATCH" - exit 1 -fi +new=$(ver HEAD < "$header") +old=$(git show "$base:$header" | ver "$base") # shellcheck disable=SC2086 # $code is a list of paths -changed=$(git diff --name-only "$base"...HEAD -- $code) +changed=$(git diff --name-only "$base"...HEAD -- $code ':(exclude,glob)**/*.md') if [ "$new" = "$old" ]; then + if [ -n "$changed" ] && [ "${NO_RELEASE:-}" = true ]; then + echo "::notice::code or build changed, CAMEX_VERSION stays $old: the no-release" \ + "label says the release files do not change" + echo "$changed" + exit 0 + fi if [ -n "$changed" ]; then echo "::error::code or build changed, CAMEX_VERSION is still $old:" \ - "bump PATCH (fix) or MINOR (feature) and add its CHANGELOG.md section" + "bump PATCH (fix) or MINOR (feature) and add its CHANGELOG.md section," \ + "or label the pull request no-release if the release files do not change" echo "$changed" exit 1 fi @@ -42,6 +59,11 @@ if [ "$new" = "$old" ]; then exit 0 fi +if ! echo "$new" | grep -Eq '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'; then + echo "::error::CAMEX_VERSION \"$new\" is not MAJOR.MINOR.PATCH" + exit 1 +fi + top=$(printf '%s\n%s\n' "$old" "$new" | sort -V | tail -n 1) if [ "$top" != "$new" ]; then echo "::error::CAMEX_VERSION $new is not greater than $old" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d2bc133..2b5d160 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,6 +17,8 @@ on: branches: [master, main, develop] pull_request: branches: [master, main] + # labeled / unlabeled: the version check reads the no-release label + types: [opened, synchronize, reopened, labeled, unlabeled] # a manual run on master rebuilds and republishes "latest" workflow_dispatch: @@ -35,8 +37,11 @@ env: jobs: # ---------------------------------------------------------------- version - # Pull requests: a change to the code or the build comes with a new - # CAMEX_VERSION (MAJOR.MINOR.PATCH) and its CHANGELOG.md section (#63) + # Pull requests: a change to the code or the build (this workflow included) + # comes with a new CAMEX_VERSION (MAJOR.MINOR.PATCH) and its CHANGELOG.md + # section (#63), unless the no-release label says the release files do not + # change (#69). The checkout is the merge commit; its first parent is the + # base it was made from (#68). version: name: Version bump if: github.event_name == 'pull_request' @@ -49,9 +54,9 @@ jobs: - name: Code changes come with a new version env: - # through the environment, not pasted into the script - BASE: ${{ github.base_ref }} - run: .github/check-version.sh "origin/$BASE" + # a change that leaves the release files as they are may skip the new version + NO_RELEASE: ${{ contains(github.event.pull_request.labels.*.name, 'no-release') }} + run: .github/check-version.sh HEAD^1 # ------------------------------------------------------------------ linux linux: From e933f1c1b9d45a2fcf1225fb27272e2accde5ae0 Mon Sep 17 00:00:00 2001 From: Compot Developer Date: Sun, 18 Oct 2026 13:10:39 +0000 Subject: [PATCH 2/2] ci: the version check runs in its own workflow; every CAMEX_VERSION definition counts (review) --- .github/check-version.sh | 23 +++++++++++-------- .github/workflows/build.yml | 25 ++------------------ .github/workflows/version.yml | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/version.yml diff --git a/.github/check-version.sh b/.github/check-version.sh index 60dcc1a..ad0cf91 100755 --- a/.github/check-version.sh +++ b/.github/check-version.sh @@ -9,10 +9,11 @@ # base branch does not have yet. src/, android/, the Makefile, ci/, # scripts/ and the build workflow (.github/workflows/build.yml) count as code # or build, without the Markdown files in them; docs, tests, screenshots and -# the rest of .github/ need no new version. NO_RELEASE=true (the pull -# request's `no-release` label) lets a change to the code or the build -# through without a new version, for changes that leave the release files as -# they are (a test or publication step, a build-script tidy-up, a comment). +# the rest of .github/ (this check and its workflow, version.yml, included) +# need no new version. NO_RELEASE=true (the pull request's `no-release` +# label) lets a change to the code or the build through without a new +# version, for changes that leave the release files as they are (a test or +# publication step, a build-script tidy-up, a comment). # # Usage: .github/check-version.sh [BASE] (default origin/master; CI passes # HEAD^1, the base side of the pull request's merge commit) @@ -24,12 +25,16 @@ base=${1:-origin/master} header=src/version.h code="src android Makefile ci scripts .github/workflows/build.yml" -# The one CAMEX_VERSION definition (comments and other text do not count). +# The one CAMEX_VERSION definition. Every "#define CAMEX_VERSION" counts, +# however it is spaced ("# define" too), and it must be the plain form +# '#define CAMEX_VERSION "X.Y.Z"' that the release job reads. ver() { - v=$(sed -n 's/^#define CAMEX_VERSION "\([^"]*\)"[[:space:]]*$/\1/p') - if [ "$(printf '%s\n' "$v" | grep -c .)" -ne 1 ]; then - echo "::error::$1:$header: expected one CAMEX_VERSION definition," \ - "found: $(printf '%s' "$v" | tr '\n' ' ')" >&2 + h=$(cat) + n=$(printf '%s\n' "$h" | grep -cE '^[[:space:]]*#[[:space:]]*define[[:space:]]+CAMEX_VERSION([[:space:]]|$)' || true) + v=$(printf '%s\n' "$h" | sed -n 's/^#define CAMEX_VERSION "\([^"]*\)"[[:space:]]*$/\1/p') + if [ "$n" -ne 1 ] || [ -z "$v" ]; then + echo "::error::$1:$header: expected one '#define CAMEX_VERSION \"X.Y.Z\"'," \ + "found $n definition(s)" >&2 exit 1 fi printf '%s\n' "$v" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2b5d160..ea01acd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,8 +17,6 @@ on: branches: [master, main, develop] pull_request: branches: [master, main] - # labeled / unlabeled: the version check reads the no-release label - types: [opened, synchronize, reopened, labeled, unlabeled] # a manual run on master rebuilds and republishes "latest" workflow_dispatch: @@ -36,27 +34,8 @@ env: # actions target Node 24 natively (checkout@v5, upload-artifact@v5, download-artifact@v5, gh-release@v3) jobs: - # ---------------------------------------------------------------- version - # Pull requests: a change to the code or the build (this workflow included) - # comes with a new CAMEX_VERSION (MAJOR.MINOR.PATCH) and its CHANGELOG.md - # section (#63), unless the no-release label says the release files do not - # change (#69). The checkout is the merge commit; its first parent is the - # base it was made from (#68). - version: - name: Version bump - if: github.event_name == 'pull_request' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Code changes come with a new version - env: - # a change that leaves the release files as they are may skip the new version - NO_RELEASE: ${{ contains(github.event.pull_request.labels.*.name, 'no-release') }} - run: .github/check-version.sh HEAD^1 + # The version check of pull requests runs in version.yml: a label change + # re-runs only that check, not the builds. # ------------------------------------------------------------------ linux linux: diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml new file mode 100644 index 0000000..428f94a --- /dev/null +++ b/.github/workflows/version.yml @@ -0,0 +1,43 @@ +# +# Copyright (c) OpenIPC https://openipc.org MIT License +# +# version.yml — the version check of pull requests (#63, #68, #69) +# +# A change to the code or the build (build.yml included) comes with a new +# CAMEX_VERSION (MAJOR.MINOR.PATCH) and its CHANGELOG.md section, unless the +# no-release label says the release files do not change. A workflow of its +# own: adding or removing a label re-runs this check, not the builds. +# + +name: version + +on: + pull_request: + branches: [master, main] + # labeled / unlabeled: the check reads the no-release label + types: [opened, synchronize, reopened, labeled, unlabeled] + +permissions: + contents: read + +# a newer event of the same pull request cancels the older check +concurrency: + group: version-${{ github.ref }} + cancel-in-progress: true + +jobs: + version: + name: Version bump + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + # The checkout is the merge commit; its first parent is the base it was made from. + - name: Code changes come with a new version + env: + # a change that leaves the release files as they are may skip the new version + NO_RELEASE: ${{ contains(github.event.pull_request.labels.*.name, 'no-release') }} + run: .github/check-version.sh HEAD^1