Update version_branch.yml
This commit is contained in:
304
.github/workflows/version_branch.yml
vendored
304
.github/workflows/version_branch.yml
vendored
@@ -4,224 +4,154 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
new_version:
|
||||
description: "New version (for example: 01.02.00). Leave blank to auto-increment from highest version/* branch."
|
||||
required: false
|
||||
default: ""
|
||||
description: "New version in format NN.NN.NN (example 01.03.00)"
|
||||
required: true
|
||||
base_branch:
|
||||
description: "Base branch to create version branch from"
|
||||
description: "Base branch to branch from"
|
||||
required: false
|
||||
default: "main"
|
||||
branch_prefix:
|
||||
description: "Prefix for the new version branch"
|
||||
required: false
|
||||
default: "version/"
|
||||
commit_changes:
|
||||
description: "Commit and push changes"
|
||||
required: false
|
||||
default: "true"
|
||||
type: choice
|
||||
options:
|
||||
- "true"
|
||||
- "false"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
create-version-branch:
|
||||
name: Create version branch and update versions
|
||||
version-bump:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
NEW_VERSION: ${{ github.event.inputs.new_version }}
|
||||
BASE_BRANCH: ${{ github.event.inputs.base_branch }}
|
||||
BRANCH_PREFIX: ${{ github.event.inputs.branch_prefix }}
|
||||
COMMIT_CHANGES: ${{ github.event.inputs.commit_changes }}
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ env.BASE_BRANCH }}
|
||||
|
||||
- name: Determine new version (input or auto-increment)
|
||||
id: version
|
||||
env:
|
||||
INPUT_VERSION: ${{ github.event.inputs.new_version }}
|
||||
- name: Validate inputs
|
||||
shell: bash
|
||||
run: |
|
||||
python << 'PY'
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
set -Eeuo pipefail
|
||||
trap 'echo "[FATAL] Validation error at line $LINENO" >&2' ERR
|
||||
|
||||
input_version = os.environ.get("INPUT_VERSION", "").strip()
|
||||
echo "[INFO] Inputs received:"
|
||||
echo " NEW_VERSION=${NEW_VERSION}"
|
||||
echo " BASE_BRANCH=${BASE_BRANCH}"
|
||||
echo " BRANCH_PREFIX=${BRANCH_PREFIX}"
|
||||
|
||||
if input_version:
|
||||
new_version = input_version
|
||||
else:
|
||||
completed = subprocess.run(
|
||||
["git", "ls-remote", "--heads", "origin"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
[[ -n "${NEW_VERSION}" ]] || { echo "[ERROR] new_version missing"; exit 2; }
|
||||
[[ "${NEW_VERSION}" =~ ^[0-9]{2}\.[0-9]{2}\.[0-9]{2}$ ]] || {
|
||||
echo "[ERROR] Invalid version format: ${NEW_VERSION}"
|
||||
exit 2
|
||||
}
|
||||
|
||||
pattern = re.compile(r"refs/heads/version/([0-9]+\.[0-9]+\.[0-9]+)$")
|
||||
versions = []
|
||||
git show-ref --verify --quiet "refs/remotes/origin/${BASE_BRANCH}" || {
|
||||
echo "[ERROR] Base branch does not exist on origin: ${BASE_BRANCH}"
|
||||
git branch -a
|
||||
exit 2
|
||||
}
|
||||
|
||||
for line in completed.stdout.splitlines():
|
||||
parts = line.split()
|
||||
if len(parts) != 2:
|
||||
continue
|
||||
ref = parts[1]
|
||||
m = pattern.search(ref)
|
||||
if not m:
|
||||
continue
|
||||
echo "[INFO] Input validation passed"
|
||||
|
||||
v_str = m.group(1)
|
||||
try:
|
||||
major, minor, patch = map(int, v_str.split("."))
|
||||
except ValueError:
|
||||
continue
|
||||
versions.append((major, minor, patch))
|
||||
|
||||
if versions:
|
||||
major, minor, patch = max(versions)
|
||||
patch += 1
|
||||
else:
|
||||
major, minor, patch = 1, 0, 0
|
||||
|
||||
new_version = f"{major:02d}.{minor:02d}.{patch:02d}"
|
||||
|
||||
print(f"Using version {new_version}")
|
||||
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
|
||||
fh.write(f"new_version={new_version}\n")
|
||||
PY
|
||||
|
||||
- name: Compute branch name
|
||||
id: branch
|
||||
env:
|
||||
NEW_VERSION: ${{ steps.version.outputs.new_version }}
|
||||
run: |
|
||||
SAFE_VERSION="${NEW_VERSION// /-}"
|
||||
BRANCH_NAME="version/${SAFE_VERSION}"
|
||||
echo "Using branch name: $BRANCH_NAME"
|
||||
echo "branch_name=$BRANCH_NAME" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create version branch from base
|
||||
run: |
|
||||
git checkout -b "${{ steps.branch.outputs.branch_name }}"
|
||||
|
||||
- name: Bump version strings across repo
|
||||
env:
|
||||
NEW_VERSION: ${{ steps.version.outputs.new_version }}
|
||||
run: |
|
||||
echo "Updating version strings to ${NEW_VERSION} across repository"
|
||||
|
||||
python << 'PY'
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
new_version = os.environ["NEW_VERSION"]
|
||||
|
||||
targets = [
|
||||
Path("src"),
|
||||
Path("docs"),
|
||||
]
|
||||
|
||||
patterns = [
|
||||
(re.compile(r"\(VERSION\s+[0-9]+\.[0-9]+\.[0-9]+\)"), lambda v: f"(VERSION {v})"),
|
||||
(re.compile(r"(VERSION[:\s]+)([0-9]+\.[0-9]+\.[0-9]+)"), lambda v: r"\1" + v),
|
||||
(re.compile(r"(<version>)([0-9]+\.[0-9]+\.[0-9]+)(</version>)"), lambda v: r"\1" + v + r"\3"),
|
||||
(re.compile(r'(<extension\\b[^>]*\\bversion=")([0-9]+\.[0-9]+\.[0-9]+)(")'), lambda v: r"\1" + v + r"\3"),
|
||||
(re.compile(r'(\"version\"\s*:\s*\")(\d+\.\d+\.\d+)(\")'), lambda v: r"\1" + v + r"\3"),
|
||||
]
|
||||
|
||||
def update_file(path: Path) -> bool:
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
except UnicodeDecodeError:
|
||||
return False
|
||||
|
||||
original = text
|
||||
for regex, repl in patterns:
|
||||
text = regex.sub(lambda m, r=repl: r(m), text)
|
||||
|
||||
if text != original:
|
||||
path.write_text(text, encoding="utf-8")
|
||||
print(f"Updated version in {path}")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
for root in targets:
|
||||
if not root.exists():
|
||||
continue
|
||||
|
||||
for path in root.rglob("*"):
|
||||
if not path.is_file():
|
||||
continue
|
||||
|
||||
if path.suffix.lower() in {
|
||||
".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico",
|
||||
".zip", ".pdf", ".tar", ".gz",
|
||||
}:
|
||||
continue
|
||||
|
||||
update_file(path)
|
||||
|
||||
repo_root = Path(".").resolve()
|
||||
|
||||
def is_under_any_target(p: Path) -> bool:
|
||||
for t in targets:
|
||||
if not t.exists():
|
||||
continue
|
||||
try:
|
||||
p.resolve().relative_to(t.resolve())
|
||||
return True
|
||||
except ValueError:
|
||||
continue
|
||||
return False
|
||||
|
||||
# Explicitly update README.md and CHANGELOG.md
|
||||
for fname in ["README.md", "CHANGELOG.md"]:
|
||||
p = Path(fname)
|
||||
if p.exists() and p.is_file():
|
||||
update_file(p)
|
||||
|
||||
# Update remaining markdown files outside src/docs
|
||||
for path in repo_root.rglob("*.md"):
|
||||
if not path.is_file():
|
||||
continue
|
||||
|
||||
if path.name.lower() in {"readme.md", "changelog.md"}:
|
||||
continue
|
||||
|
||||
if is_under_any_target(path):
|
||||
continue
|
||||
|
||||
update_file(path)
|
||||
PY
|
||||
|
||||
- name: Update CHANGELOG using script
|
||||
env:
|
||||
NEW_VERSION: ${{ steps.version.outputs.new_version }}
|
||||
run: |
|
||||
if [ ! -f "scripts/update_changelog.sh" ]; then
|
||||
echo "scripts/update_changelog.sh not found. Failing version branch creation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod +x scripts/update_changelog.sh
|
||||
./scripts/update_changelog.sh "${NEW_VERSION}"
|
||||
|
||||
- name: Configure git user
|
||||
- name: Configure git identity
|
||||
shell: bash
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
echo "[INFO] Git identity configured"
|
||||
|
||||
- name: Commit version bump
|
||||
env:
|
||||
NEW_VERSION: ${{ steps.version.outputs.new_version }}
|
||||
- name: Create version branch
|
||||
shell: bash
|
||||
run: |
|
||||
git status
|
||||
if git diff --quiet; then
|
||||
echo "No changes detected after version bump. Skipping commit."
|
||||
exit 0
|
||||
set -Eeuo pipefail
|
||||
trap 'echo "[FATAL] Branch creation failed at line $LINENO" >&2' ERR
|
||||
|
||||
BRANCH_NAME="${BRANCH_PREFIX}${NEW_VERSION}"
|
||||
echo "[INFO] Creating branch ${BRANCH_NAME}"
|
||||
|
||||
git fetch --all --tags --prune
|
||||
|
||||
if git ls-remote --exit-code --heads origin "${BRANCH_NAME}" >/dev/null 2>&1; then
|
||||
echo "[ERROR] Branch already exists on origin: ${BRANCH_NAME}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
git add -A
|
||||
git checkout -B "${BRANCH_NAME}" "origin/${BASE_BRANCH}"
|
||||
|
||||
git commit -m "chore: bump version to ${NEW_VERSION}"
|
||||
|
||||
- name: Push version branch
|
||||
- name: Bump versions in headers and XML
|
||||
shell: bash
|
||||
run: |
|
||||
git push -u origin "${{ steps.branch.outputs.branch_name }}"
|
||||
set -Eeuo pipefail
|
||||
trap 'echo "[FATAL] Version bump failed at line $LINENO" >&2' ERR
|
||||
|
||||
python3 - <<'PY'
|
||||
import re
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
new_version = os.environ["NEW_VERSION"]
|
||||
root = Path(".").resolve()
|
||||
|
||||
header_re = re.compile(r"(?m)^(\\s*VERSION\\s*:\\s*)(\\d{2}\\.\\d{2}\\.\\d{2})(\\s*)$")
|
||||
xml_re = re.compile(r"(?is)(<version\\s*>)(\\s*\\d{2}\\.\\d{2}\\.\\d{2}\\s*)(</version\\s*>)")
|
||||
|
||||
updated = []
|
||||
|
||||
for p in root.rglob("*"):
|
||||
if not p.is_file():
|
||||
continue
|
||||
if p.suffix.lower() == ".json":
|
||||
continue
|
||||
try:
|
||||
text = p.read_text(encoding="utf-8")
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
original = text
|
||||
text = header_re.sub(r"\\1" + new_version + r"\\3", text)
|
||||
if p.suffix.lower() == ".xml":
|
||||
text = xml_re.sub(r"\\1" + new_version + r"\\3", text)
|
||||
|
||||
if text != original:
|
||||
p.write_text(text, encoding="utf-8")
|
||||
updated.append(str(p))
|
||||
|
||||
if not updated:
|
||||
raise SystemExit("[ERROR] No files updated. Check headers and XML manifests.")
|
||||
|
||||
print(f"[INFO] Updated {len(updated)} files")
|
||||
for f in updated:
|
||||
print(f" - {f}")
|
||||
PY
|
||||
|
||||
- name: Commit changes
|
||||
if: ${{ env.COMMIT_CHANGES == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
git status --porcelain
|
||||
git add -A
|
||||
git commit -m "chore(release): bump version to ${NEW_VERSION}"
|
||||
|
||||
- name: Push branch
|
||||
if: ${{ env.COMMIT_CHANGES == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
git push --set-upstream origin "${BRANCH_PREFIX}${NEW_VERSION}"
|
||||
|
||||
Reference in New Issue
Block a user