Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .github/check-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/sh
#
# Copyright (c) OpenIPC https://openipc.org MIT License
#
# check-version.sh — fail a pull request that changes the code or the build
# but not VTESSE_VERSION in include/vtesse/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 ("## <version> — YYYY-MM-DD") that the
# base branch does not have yet. The sources, android/ (except its unit
# tests), the Makefile, ci/ and scripts/ count as code or build, without the
# Markdown files in them (server/README.md, android/README.md); docs,
# tests/, bench/, screenshots and the workflows in .github/ need no new
# version. The format is checked only when the version changes, so the
# MAJOR.MM versions up to 1.12 stay valid until the next code change.
#
# Usage: .github/check-version.sh [BASE] (default origin/main; CI passes
# HEAD^1, the base side of the pull request's merge commit)
#

set -eu

base=${1:-origin/main}
header=include/vtesse/version.h
code="include netcore cli vtun port server scripts third_party tools android Makefile ci"
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Ci-only changes force a version bump 📎 Requirement gap ≡ Correctness

The code path list includes ci, so changes under ci/ populate changed and require a new
VTESSE_VERSION. A pull request that changes only CI files therefore reaches the unchanged-version
error even though CI-only changes are exempt from version bumps.
Agent Prompt
## Issue description
The version check treats changes under `ci/` as code changes, requiring a version bump for CI-only pull requests even though the compliance policy exempts CI-only changes.

## Fix Focus Areas
- .github/check-version.sh[24-24]

## Recommended Fix
Remove CI-only paths from the set of paths that require a version bump, while continuing to check the source and build paths that the policy identifies as versioned code.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


# The one VTESSE_VERSION definition (comments and other text do not count).
ver() {
v=$(sed -n 's/^#define VTESSE_VERSION "\([^"]*\)"[[:space:]]*$/\1/p')
if [ "$(printf '%s\n' "$v" | grep -c .)" -ne 1 ]; then
echo "::error::$1:$header: expected one VTESSE_VERSION definition," \
"found: $(printf '%s' "$v" | tr '\n' ' ')" >&2
exit 1
fi
printf '%s\n' "$v"
}

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 ':(exclude)android/app/src/test' \
':(exclude,glob)**/*.md')

if [ "$new" = "$old" ]; then
if [ -n "$changed" ]; then
echo "::error::code or build changed, VTESSE_VERSION 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 code 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Patch releases cannot upgrade android apps 🐞 Bug ≡ Correctness

check-version.sh accepts a greater three-part version such as 1.12.1, but Android's
versionCode calculation reads only the major and minor components. If a patch bump is merged
before the planned Android formula change, the published APK has the same version code as 1.12 and
cannot upgrade an existing installation.
Agent Prompt
## Issue description
The checker approves patch releases while Android still calculates the same version code for every patch of a minor version.

## Fix Focus Areas
- .github/check-version.sh[55-69]
- android/app/build.gradle.kts[29-31]

## Recommended Fix
Ensure the first three-part version bump also updates Android's versionCode formula, or make the checker reject patch bumps until that migration is present. Verify that an APK for 1.12.1 has a higher versionCode than the APK for 1.12.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

echo "::error::VTESSE_VERSION \"$new\" is not MAJOR.MINOR.PATCH"
exit 1
fi

# A MAJOR.MM version from before MAJOR.MINOR.PATCH is MAJOR.MM.0: 1.12.0 is 1.12.
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::VTESSE_VERSION $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"
39 changes: 31 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
# (ci/build-musl.sh).
#
# Release: one release only, "latest", replaced by every push to main. Its title
# carries the version from include/vtesse/version.h (VTESSE_VERSION "MAJOR.MM")
# and its notes are one short line; the change history lives in CHANGELOG.md.
# No versioned releases are kept.
# carries the version from include/vtesse/version.h (VTESSE_VERSION,
# MAJOR.MINOR.PATCH) and its notes are one short line; the change history lives
# in CHANGELOG.md. No versioned releases are kept.
# On pull requests, .github/check-version.sh checks that a change to the code or
# the build comes with a new VTESSE_VERSION and its CHANGELOG.md section.
#

name: VTesse CI
Expand All @@ -28,13 +30,32 @@ on:
branches: [main]
workflow_dispatch:

# One run per branch and event: a newer push cancels the older run, so
# "latest" always carries the build of the newest commit.
# One run per branch: on pull requests a newer push cancels the older run; on
# main it waits instead (only the newest waits), so "latest" still ends with the
# build of the newest commit and the release job is never stopped between
# deleting the old "latest" and creating the new one. A manual run shares the
# push group.
concurrency:
group: build-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true
group: build-${{ github.event_name == 'pull_request' && 'pull_request' || 'push' }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.

jobs:
# ---------------------------------------------------------------- version
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

# 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: Code changes come with a new version
run: .github/check-version.sh HEAD^1

# ------------------------------------------------------------------ tests
tests:
name: Unit tests (native, sanitizers)
Expand Down Expand Up @@ -185,7 +206,9 @@ jobs:
release:
name: Release
needs: [tests, build, bench, android]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
# a manual run of main publishes too: it shares the push group and may take the
# place of a waiting push, so it must not skip the release
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

The version lives in `include/vtesse/version.h`. Binaries are published only as the
[`latest`](https://github.com/OpenIPC/vtesse/releases/tag/latest) release, rebuilt
from every push to `main`; this file is the change history.
from every push to `main`; this file is the change history. Versions after 1.12 are
`MAJOR.MINOR.PATCH` (1.12 is followed by 1.12.1 or 1.13.0); the headings below keep the
numbers as released.

## 1.12 — 2026-10-15

Expand Down
15 changes: 11 additions & 4 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,23 @@ and pull request:
### Versions and releases

The version lives in one place, `include/vtesse/version.h`:
`#define VTESSE_VERSION "MAJOR.MM"` (two-digit minor: `1.00`, `1.01`, …; shown by
`vtesse-cli --version`).
`#define VTESSE_VERSION "MAJOR.MINOR.PATCH"` (shown by `vtesse-cli --version`). Up to 1.12
it was `MAJOR.MM` (`1.00`, `1.01`, …); 1.12 is followed by 1.12.1 or 1.13.0.

- There is one release, `latest`: every push to `main` replaces it (tag moved to that
commit). No versioned releases are kept.
- Its title is `VTesse MAJOR.MM`; the notes are one short line. The change history is
- Its title is `VTesse <version>`; the notes are one short line. The change history is
[CHANGELOG.md](../CHANGELOG.md), the patch list [server/README.md](../server/README.md).
- File names are stable: `vtesse-<arch>`, `vtesse-tap-<arch>`, and
`vtund-<VTun version>-x86_64` (e.g. `vtund-3.0.2-x86_64`) for the VTun server, PCs only.
- A new version: bump `VTESSE_VERSION` and add a `CHANGELOG.md` entry in the same commit.
- 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. A pull request that changes
the code or the build (the sources, `android/` except its unit tests, the `Makefile`,
`ci/`, `scripts/`) bumps `VTESSE_VERSION` as its last commit before the merge, together
with its `CHANGELOG.md` section (`## <version> — YYYY-MM-DD`). Docs, `tests/`, `bench/`
and `.github/` changes do not. 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 section.

## Test bench

Expand Down
Loading