diff --git a/.github/check-version.sh b/.github/check-version.sh new file mode 100755 index 00000000..cd6d8131 --- /dev/null +++ b/.github/check-version.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# +# check-version.sh — fail a pull request that changes the app or its build +# but not versionName in android/app/build.gradle. 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. android/ counts as app or build (its unit +# tests in android/app/src/test do not); docs, screenshots and the +# workflows in .github/ need no new version. The format is checked only +# when the version changes, so the 2.xx versions before MAJOR.MINOR.PATCH +# stay valid until the next app change. +# +# Usage: .github/check-version.sh [BASE] (default origin/v2; CI passes +# HEAD^1, the base side of the pull request's merge commit) +# + +set -eu + +base=${1:-origin/v2} +gradle=android/app/build.gradle + +# The one versionName assignment (comments and other text do not count). +ver() { + v=$(sed -n 's/^[[:space:]]*versionName[[:space:]]*"\([^"]*\)"[[:space:]]*$/\1/p') + if [ "$(printf '%s\n' "$v" | grep -c .)" -ne 1 ]; then + echo "::error::$1:$gradle: expected one versionName assignment," \ + "found: $(printf '%s' "$v" | tr '\n' ' ')" >&2 + exit 1 + fi + printf '%s\n' "$v" +} + +new=$(ver HEAD < "$gradle") +old=$(git show "$base:$gradle" | ver "$base") + +changed=$(git diff --name-only "$base"...HEAD -- android ':(exclude)android/app/src/test') + +if [ "$new" = "$old" ]; then + if [ -n "$changed" ]; then + echo "::error::the app or its build changed, versionName is still $old:" \ + "bump PATCH (fix) or MINOR (feature) and add its CHANGELOG.md section" + echo "$changed" + exit 1 + fi + echo "version $new unchanged, no app or build changes" + 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::versionName \"$new\" is not MAJOR.MINOR.PATCH" + exit 1 +fi + +# A 2.xx version from before MAJOR.MINOR.PATCH is X.Y.0: 2.17.0 is 2.17. +case $old in +*.*.*) oldn=$old ;; +*) oldn=$old.0 ;; +esac +top=$(printf '%s\n%s\n' "$oldn" "$new" | sort -V | tail -n 1) +if [ "$new" = "$oldn" ] || [ "$top" != "$new" ]; then + echo "::error::versionName $new is not greater than $old" + exit 1 +fi + +# $new is digits and dots only (checked above): escape the dots, require a date. +re=$(printf '%s' "$new" | sed 's/\./\\./g') +if ! grep -Eq "^## $re — [0-9]{4}-[0-9]{2}-[0-9]{2}\$" CHANGELOG.md; then + echo "::error::CHANGELOG.md has no section \"## $new — YYYY-MM-DD\"" + exit 1 +fi + +# The section must come with this pull request, not be one the base +# branch already has (a version taken from there brings no notes). +if git show "$base:CHANGELOG.md" 2>/dev/null | grep -Eq "^## $re — "; then + echo "::error::the section \"## $new\" is already on $base: take a new version" + exit 1 +fi + +echo "version $old -> $new, CHANGELOG.md section found" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6d9369a4..42004ca3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,6 +18,23 @@ concurrency: cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }} jobs: + # Pull requests: a change to the app or its build comes with a new versionName + # (MAJOR.MINOR.PATCH) and its CHANGELOG.md section (.github/check-version.sh, #230) + version: + # basic keeps its own workflow and version file (app/build.gradle) + if: github.event_name == 'pull_request' && github.base_ref == 'v2' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # The checkout is the pull request's merge commit: its first parent is the + # base it was made from, so both versions come from the same base. + - name: App changes come with a new version + run: .github/check-version.sh HEAD^1 + # Unit tests and lint; also runs for pull requests from forks (no secrets needed) test: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 915e7dc3..46a0f397 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ newest `v2` and `basic` builds, and in the OpenIPC Telegram channel; there are n per version (#194). This file is the change history: one section per `v2` version, newest first, then the legacy `basic` line. +Versions after 2.17 are `MAJOR.MINOR.PATCH` (2.17 is followed by 2.17.1 or 2.18.0; see +`docs/testing.md`, "Versions and releases"); the headings below keep the numbers as they +were released. + ## 2.17 — 2026-10-17 - Turn in the camera settings (Auto, 0°, 90°, 180°, 270°), stored per slot; H.264/H.265 are @@ -108,10 +112,10 @@ Versions 1.x of the `v2` line, up to 1.28 (2026-05-04) and the work merged until `basic` is the original app, `decoder.apk` in the `latest` release; it gets fixes only. -### 1.07.1 — 2026-10-12 +### 1.7.1 — 2026-10-12 -- Robust RTSP handshake, end-of-stream handling, thread lifecycle and SDP parsing (PR #41, - #36–#40). +- Released as 1.07.1 (written 1.7.1 since #230). Robust RTSP handshake, end-of-stream + handling, thread lifecycle and SDP parsing (PR #41, #36–#40). ### 1.07 — 2025-11-11 diff --git a/docs/testing.md b/docs/testing.md index d1561c82..0f575138 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -47,8 +47,8 @@ CI is the reference: the project does not depend on local builds. ## Versions and releases -- `v2` is **2.xx** (from 2.00). Every pull request that changes the app bumps `android/app/build.gradle` as its last commit before the merge: `versionName` +0.01, `versionCode` +1. Docs-only and CI-only pull requests do not. -- `basic` keeps its 1.07.x line. +- Versions are **`MAJOR.MINOR.PATCH`** (`versionName` in `android/app/build.gradle`): PATCH for fixes and small changes, MINOR for a new feature, MAJOR for an incompatible change or a large update, only when the maintainer decides. Every pull request that changes the app or its build (`android/`, except the unit tests) bumps the version as its last commit before the merge: `versionName` by that rule and `versionCode` +1. Docs-only, test-only and CI-only pull requests do not. Numbers are not reserved for open pull requests: each one takes the next number when it is merged. CI checks this on every pull request (`.github/check-version.sh`): a new number must be canonical (no leading zeros), greater than the base one, and come with its own `CHANGELOG.md` section. +- Until 2.17 `v2` counted **2.xx** (+0.01 per pull request); 2.17 is followed by 2.17.1 or 2.18.0. `basic` keeps its 1.7.x line (1.07.1 is 1.7.1). - **`CHANGELOG.md`** is the change history: the version bump commit of a pull request that changes the app adds the version's section (`## — `, newest first) in the same pull request. - Development is continuous, so there is **no release per version** (#194). The [`latest`](https://github.com/OpenIPC/decoder/releases/tag/latest) release always holds the newest `v2` and `basic` builds. Every `v2` and `basic` build is also posted to the OpenIPC Telegram channel with its version and commit, and that is where their older builds can be found. Builds of other branches are only workflow artifacts of their runs (90 days). - **Test pre-releases**: to let a reporter test a branch, a pre-release named after the issue is made by hand from the branch's CI artifact, e.g. [`toys-187-test2`](https://github.com/OpenIPC/decoder/releases/tag/toys-187-test2) for #187. It is deleted when the test is over, or replaced by the next one.