diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ded1def4..124b9763 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: cache: maven - name: Auto-tag - if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.repository == 'nbclaudecodegui/NetbeansClaudeCodeGui' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -60,9 +60,21 @@ jobs: fi UPLOAD_URL=$(gh release view "$REL_TAG" --json uploadUrl -q .uploadUrl) else - BASE_TAG=$(git tag | grep -E '^[0-9]+\.[0-9]+$' | sort -V | tail -1 || echo "0.0") - N=$(git rev-list "${BASE_TAG}..HEAD" --count 2>/dev/null || echo "0") - VER="${BASE_TAG}.${N}" + POM_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout | sed 's/-.*//') + MM=$(echo "$POM_VERSION" | cut -d. -f1-2) + MM_ESC="${MM//./\\.}" + LAST_REL=$(git tag | grep -E "^${MM_ESC}\.[0-9]+$" | sort -V | tail -1) + BASE_TAG=$(git tag | grep -E "^${MM_ESC}$" | sort -V | tail -1 || echo "") + if [[ -n "$LAST_REL" ]]; then + START=$(echo "$LAST_REL" | cut -d. -f3) + N=$(git rev-list "${LAST_REL}..HEAD" --count 2>/dev/null || echo "0") + VER="${MM}.$((START + N))" + elif [[ -n "$BASE_TAG" ]]; then + N=$(git rev-list "${BASE_TAG}..HEAD" --count 2>/dev/null || echo "0") + VER="${MM}.${N}" + else + VER="${MM}.0" + fi RELEASE=OFF UPLOAD_URL="" REL_TAG="" diff --git a/CLAUDE.md b/CLAUDE.md index c3c122bf..20baa974 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,10 +35,32 @@ A release has an explicit **start** and **finish**: **Finishing a release** (only this, nothing else): - Update `CHANGELOG.md` heading to `# MAJOR.MINOR` (matching current `pom.xml`) → CI sees this as the release signal, creates release tag `MAJOR.MINOR.N`, and publishes a GitHub Release -**After a published release** — any push without bumping `pom.xml` → **build error**. Start a new release first. +**After a published release** — CI auto-edits `CHANGELOG.md`: the release heading `# MAJOR.MINOR (date)` is replaced with `# MAJOR.MINOR.N (date)`. Development can continue immediately; patch versions increment from the last released N. Implemented in `build-scripts/autotag.sh` and `.github/workflows/build.yml`. +### Side releases (patch releases on an old branch) + +Use when a critical fix must be shipped for an older version while `main` has already moved to a newer `MAJOR.MINOR`. + +**Setup (once per side branch):** +```bash +git checkout -b release/0.17 0.18^ # commit just before the next base tag (0.18, 0.19, etc.) +git push origin release/0.17 +``` +`pom.xml` on this branch already has `0.17.0-SNAPSHOT` — no change needed. + +**Development:** push fixes to `release/0.17`; CI builds snapshot versions automatically. +Version numbers continue from the last released patch: if `0.17.3` was the last release, the next builds are `0.17.4`, `0.17.5`, etc. + +**Releasing a patch:** +- Add `# 0.17 (YYYY-MM-DD)` at the top of `CHANGELOG.md` (together with the fix's bullet) +- Push → CI creates tag `0.17.N`, publishes GitHub Release, and auto-edits `CHANGELOG.md` to `# 0.17.N (YYYY-MM-DD)` + +**Next patch:** add `# 0.17 (YYYY-MM-DD)` again and repeat. + +`main` is fully unaffected throughout. + ### CHANGELOG.md rules The heading `# MAJOR.MINOR (YYYY-MM-DD)` is the CI release signal — **only add it when finishing a release**. Always include the release date in parentheses (e.g. `# 0.18 (2026-04-04)`). diff --git a/build-scripts/autotag.sh b/build-scripts/autotag.sh index bee5cc7b..d12d6f14 100755 --- a/build-scripts/autotag.sh +++ b/build-scripts/autotag.sh @@ -22,16 +22,15 @@ echo "POM MM=$MM BASE_TAG=$BASE_TAG RELEASE_TAG=$RELEASE_TAG" # If release tag exists — check its status if [[ -n "$RELEASE_TAG" ]]; then IS_DRAFT=$(gh release view "$RELEASE_TAG" --json isDraft -q .isDraft 2>/dev/null || echo "notfound") - if [[ "$IS_DRAFT" == "false" ]]; then - echo "ERROR: Release $RELEASE_TAG already published. Bump MAJOR.MINOR in pom.xml." - exit 1 + if [[ "$IS_DRAFT" == "true" ]]; then + # Tag exists but release not published — delete tag and draft, recalculate + echo "Removing unpublished release tag $RELEASE_TAG" + git tag -d "$RELEASE_TAG" || true + git push origin ":refs/tags/$RELEASE_TAG" || true + gh release delete "$RELEASE_TAG" --yes 2>/dev/null || true + RELEASE_TAG= fi - # Tag exists but release not published — delete tag and draft, recalculate N - echo "Removing unpublished release tag $RELEASE_TAG" - git tag -d "$RELEASE_TAG" || true - git push origin ":refs/tags/$RELEASE_TAG" || true - gh release delete "$RELEASE_TAG" --yes 2>/dev/null || true - RELEASE_TAG= + # If published: continue — CHANGELOG no longer has the release signal (auto-edited after release) fi # Create base tag if missing @@ -42,12 +41,18 @@ if [[ -z "$BASE_TAG" ]]; then BASE_TAG="$MM" fi -# N = number of commits since base tag -N=$(git rev-list "${BASE_TAG}..HEAD" --count) -FULL_VER="${MM}.${N}" +# Version: count from last release tag (3-comp) if available, else from base tag (2-comp) +if [[ -n "$RELEASE_TAG" ]]; then + START_PATCH=$(echo "$RELEASE_TAG" | cut -d. -f3) + N=$(git rev-list "${RELEASE_TAG}..HEAD" --count) + FULL_VER="${MM}.$((START_PATCH + N))" +else + N=$(git rev-list "${BASE_TAG}..HEAD" --count) + FULL_VER="${MM}.${N}" +fi echo "FULL_VER=$FULL_VER" -# Release signal: CHANGELOG starts with "# MAJOR.MINOR" +# Release signal: CHANGELOG starts with "# MAJOR.MINOR (..." CHANGELOG_MM="" FIRST_LINE=$(head -n 1 "$CHANGELOG" 2>/dev/null || echo "") if [[ "$(echo "$FIRST_LINE" | cut -d' ' -f1)" == "#" ]]; then @@ -59,4 +64,10 @@ if [[ "$CHANGELOG_MM" == "$MM" ]]; then sed '0,/^#/d;/^#/Q' "$CHANGELOG" > "$RELEASE_NOTES" || echo "Release $FULL_VER" > "$RELEASE_NOTES" git tag "$FULL_VER" git push origin "$FULL_VER" + + # Auto-edit CHANGELOG: replace "# MM (date)" with "# FULL_VER (date)" to clear the release signal + sed -i "s|^# ${MM_ESCAPED} |# ${FULL_VER} |" "$CHANGELOG" + git add "$CHANGELOG" + git commit -m "Released ${FULL_VER}" + git push origin HEAD fi