From 08dab4ca6b97b9bee2d7fd656d08b0b74f61f497 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 27 Oct 2025 10:56:33 +1100 Subject: [PATCH] refactor: consolidate version extraction logic and update workflow validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extracted version extraction logic from workflows into a centralized script for better reusability and consistency. Updated validation output naming for clarity. Changes: - Add extract_version.sh for centralized version extraction - Remove update_version.sh (functionality integrated into workflows) - Update validate_semver.sh output: release_type → is_prerelease - Refactor docker-release.yml to use extract_version.sh - Refactor github-release.yml to use centralized scripts - Add version duplication check in version-release.yml 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/scripts/extract_version.sh | 59 +++++++++ .github/scripts/update_version.sh | 174 -------------------------- .github/scripts/validate_semver.sh | 4 +- .github/workflows/docker-release.yml | 30 +---- .github/workflows/github-release.yml | 31 +---- .github/workflows/version-release.yml | 18 ++- 6 files changed, 87 insertions(+), 229 deletions(-) create mode 100755 .github/scripts/extract_version.sh delete mode 100755 .github/scripts/update_version.sh diff --git a/.github/scripts/extract_version.sh b/.github/scripts/extract_version.sh new file mode 100755 index 0000000..98285a6 --- /dev/null +++ b/.github/scripts/extract_version.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Script: extract_version.sh +# Description: Extracts version from branch name and validates against version.py +# Usage: extract_version.sh + +# Color codes for output +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color + +# Display usage information +usage() { + echo "Usage: $0 " + echo "" + echo "Extracts version from release branch name and validates it matches version.py." + echo "" + echo "Examples:" + echo " $0 release/1.2.3" + echo " $0 release/2.0.0-rc.1" + exit 1 +} + +# Check if branch name argument is provided +if [ $# -eq 0 ]; then + echo -e "${RED}Error: No branch name specified${NC}" + usage +fi + +BRANCH_NAME="$1" + +# Extract version from branch name (release/1.2.3 -> 1.2.3) +VERSION="${BRANCH_NAME#release/}" +echo "Branch version: $VERSION" + +# Read version from version.py +if [ ! -f "src/version.py" ]; then + echo -e "${RED}Error: src/version.py not found${NC}" + exit 1 +fi + +FILE_VERSION=$(grep -oP '__version__ = "\K[^"]+' src/version.py) +echo "File version: $FILE_VERSION" + +# Verify they match +if [ "$VERSION" != "$FILE_VERSION" ]; then + echo -e "${RED}Error: Branch version ($VERSION) does not match version.py ($FILE_VERSION)${NC}" + exit 1 +fi + +echo -e "${GREEN}✓ Version match validated: $VERSION${NC}" + +# Output to GITHUB_OUTPUT if available +if [ -n "${GITHUB_OUTPUT:-}" ]; then + echo "version=$VERSION" >> "$GITHUB_OUTPUT" +fi + +exit 0 diff --git a/.github/scripts/update_version.sh b/.github/scripts/update_version.sh deleted file mode 100755 index 0cc9730..0000000 --- a/.github/scripts/update_version.sh +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script: update_version.sh -# Description: Updates project version, creates release branch and tag -# Usage: update_version.sh [--skip-push] - -# Color codes for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Script directory -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" - -# Display usage information -usage() { - echo "Usage: $0 [--skip-push]" - echo "" - echo "Updates the project version, creates a release branch, and creates a git tag." - echo "" - echo "Arguments:" - echo " Version string in SemVer format (e.g., 1.2.3, 2.0.0-rc.1)" - echo "" - echo "Options:" - echo " --skip-push Skip pushing changes to remote (useful for local testing)" - echo "" - echo "Examples:" - echo " $0 1.2.3" - echo " $0 2.0.0-rc.1" - echo " $0 1.0.0-beta --skip-push" - exit 1 -} - -# Check if version argument is provided -if [ $# -eq 0 ]; then - echo -e "${RED}Error: No version specified${NC}" - usage -fi - -VERSION="$1" -SKIP_PUSH=false - -# Parse optional flags -shift -while [ $# -gt 0 ]; do - case "$1" in - --skip-push) - SKIP_PUSH=true - shift - ;; - *) - echo -e "${RED}Error: Unknown option: $1${NC}" - usage - ;; - esac -done - -# Validate version format using validate_semver.sh -echo -e "${BLUE}Validating version format...${NC}" -if ! "$SCRIPT_DIR/validate_semver.sh" "$VERSION" > /dev/null; then - echo -e "${RED}Version validation failed${NC}" - exit 1 -fi - -# Determine current branch -CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) -RELEASE_BRANCH="release/$VERSION" - -echo -e "${BLUE}Current branch: $CURRENT_BRANCH${NC}" -echo -e "${BLUE}Target release branch: $RELEASE_BRANCH${NC}" - -# Check if release branch already exists -if git show-ref --verify --quiet "refs/heads/$RELEASE_BRANCH"; then - echo -e "${RED}Error: Branch '$RELEASE_BRANCH' already exists locally${NC}" - exit 1 -fi - -# Check if remote branch exists (if we're not skipping push) -if [ "$SKIP_PUSH" = false ]; then - if git ls-remote --heads origin "$RELEASE_BRANCH" | grep -q "$RELEASE_BRANCH"; then - echo -e "${RED}Error: Branch '$RELEASE_BRANCH' already exists on remote${NC}" - exit 1 - fi -fi - -# Check if tag already exists -if git rev-parse "v$VERSION" >/dev/null 2>&1; then - echo -e "${RED}Error: Tag 'v$VERSION' already exists${NC}" - exit 1 -fi - -# Update version.py -echo -e "${BLUE}Updating version.py...${NC}" -VERSION_FILE="$PROJECT_ROOT/src/version.py" - -if [ ! -f "$VERSION_FILE" ]; then - echo -e "${RED}Error: Version file not found: $VERSION_FILE${NC}" - exit 1 -fi - -# Backup old version -BACKUP_FILE="$PROJECT_ROOT/src/last_version.py" -mv -f "$VERSION_FILE" "$BACKUP_FILE" - -# Write new version -echo "__version__ = \"$VERSION\"" > "$VERSION_FILE" - -echo -e "${GREEN}✓ Updated version to $VERSION${NC}" - -# Commit version change -echo -e "${BLUE}Committing version change...${NC}" -git add "$VERSION_FILE" -git commit -m "chore: bump version to $VERSION" - -if [ "$SKIP_PUSH" = false ]; then - echo -e "${BLUE}Pushing to current branch ($CURRENT_BRANCH)...${NC}" - git push origin "$CURRENT_BRANCH" - echo -e "${GREEN}✓ Pushed version update to $CURRENT_BRANCH${NC}" -else - echo -e "${YELLOW}⊘ Skipping push to current branch${NC}" -fi - -# Create release branch -echo -e "${BLUE}Creating release branch '$RELEASE_BRANCH'...${NC}" -git checkout -b "$RELEASE_BRANCH" -echo -e "${GREEN}✓ Created branch '$RELEASE_BRANCH'${NC}" - -# Push release branch -if [ "$SKIP_PUSH" = false ]; then - echo -e "${BLUE}Pushing release branch...${NC}" - git push origin "$RELEASE_BRANCH" - echo -e "${GREEN}✓ Pushed branch '$RELEASE_BRANCH'${NC}" -else - echo -e "${YELLOW}⊘ Skipping push of release branch${NC}" -fi - -# Create tag -echo -e "${BLUE}Creating tag 'v$VERSION'...${NC}" -git tag "v$VERSION" -echo -e "${GREEN}✓ Created tag 'v$VERSION'${NC}" - -# Push tag -if [ "$SKIP_PUSH" = false ]; then - echo -e "${BLUE}Pushing tag...${NC}" - git push origin "v$VERSION" - echo -e "${GREEN}✓ Pushed tag 'v$VERSION'${NC}" -else - echo -e "${YELLOW}⊘ Skipping push of tag${NC}" -fi - -# Summary -echo "" -echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" -echo -e "${GREEN}✅ Version update completed successfully!${NC}" -echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" -echo -e "${GREEN} Version: $VERSION${NC}" -echo -e "${GREEN} Branch: $RELEASE_BRANCH${NC}" -echo -e "${GREEN} Tag: v$VERSION${NC}" - -if [ "$SKIP_PUSH" = false ]; then - echo -e "${GREEN} Remote status: Pushed${NC}" - echo "" - echo -e "${BLUE}The publish workflow should now build Docker images and create the GitHub release.${NC}" -else - echo -e "${YELLOW} Remote status: Not pushed (--skip-push)${NC}" - echo "" - echo -e "${YELLOW}Note: Changes are only local. Push manually when ready.${NC}" -fi - -exit 0 diff --git a/.github/scripts/validate_semver.sh b/.github/scripts/validate_semver.sh index 0dfa67f..35f9d6d 100755 --- a/.github/scripts/validate_semver.sh +++ b/.github/scripts/validate_semver.sh @@ -62,9 +62,9 @@ if [ -n "${GITHUB_OUTPUT:-}" ]; then echo "version=$VERSION" >> "$GITHUB_OUTPUT" if echo "$VERSION" | grep -q '-'; then - echo "release_type=prerelease" >> "$GITHUB_OUTPUT" + echo "is_prerelease=true" >> "$GITHUB_OUTPUT" else - echo "release_type=stable" >> "$GITHUB_OUTPUT" + echo "is_prerelease=false" >> "$GITHUB_OUTPUT" fi fi diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index 7f179a1..8f0b7ef 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -24,31 +24,13 @@ jobs: - name: Extract version from branch and version.py id: extract run: | - # Extract version from branch name (release/1.2.3 -> 1.2.3) - BRANCH_VERSION="${GITHUB_REF#refs/heads/release/}" - echo "Branch version: $BRANCH_VERSION" + # Extract version from branch name and validate against version.py + .github/scripts/extract_version.sh "${{ github.ref }}" - # Read version from version.py - FILE_VERSION=$(grep -oP '__version__ = "\K[^"]+' src/version.py) - echo "File version: $FILE_VERSION" - - # Verify they match - if [ "$BRANCH_VERSION" != "$FILE_VERSION" ]; then - echo "Error: Branch version ($BRANCH_VERSION) does not match version.py ($FILE_VERSION)" - exit 1 - fi - - VERSION="$BRANCH_VERSION" - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - - # Check if pre-release (contains hyphen) - if echo "$VERSION" | grep -q '-'; then - echo "is_prerelease=true" >> "$GITHUB_OUTPUT" - echo "Detected pre-release version: $VERSION" - else - echo "is_prerelease=false" >> "$GITHUB_OUTPUT" - echo "Detected stable release version: $VERSION" - fi + - name: Validate version format + run: | + # Validate version is proper SemVer and set prerelease flag + .github/scripts/validate_semver.sh "${{ steps.extract.outputs.version }}" docker-build: name: Build & Push Docker Images diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 2b00230..3f218ac 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -29,32 +29,11 @@ jobs: - name: Extract version from branch id: extract - run: | - # Extract version from branch name (release/1.2.3 -> 1.2.3) - BRANCH_NAME="${{ github.event.workflow_run.head_branch }}" - VERSION="${BRANCH_NAME#release/}" - echo "Branch version: $VERSION" + run: .github/scripts/extract_version.sh "${{ github.event.workflow_run.head_branch }}" - # Read version from version.py - FILE_VERSION=$(grep -oP '__version__ = "\K[^"]+' src/version.py) - echo "File version: $FILE_VERSION" - - # Verify they match - if [ "$VERSION" != "$FILE_VERSION" ]; then - echo "Error: Branch version ($VERSION) does not match version.py ($FILE_VERSION)" - exit 1 - fi - - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - - # Check if pre-release (contains hyphen) - if echo "$VERSION" | grep -q '-'; then - echo "is_prerelease=true" >> "$GITHUB_OUTPUT" - echo "Detected pre-release version: $VERSION" - else - echo "is_prerelease=false" >> "$GITHUB_OUTPUT" - echo "Detected stable release version: $VERSION" - fi + - name: Validate version format + id: validate + run: .github/scripts/validate_semver.sh "${{ steps.extract.outputs.version }}" - name: Extract release notes id: release-notes @@ -66,5 +45,5 @@ jobs: tag_name: v${{ steps.extract.outputs.version }} name: Release ${{ steps.extract.outputs.version }} body_path: release_notes.md - prerelease: ${{ steps.extract.outputs.is_prerelease }} + prerelease: ${{ steps.validate.outputs.is_prerelease }} draft: false diff --git a/.github/workflows/version-release.yml b/.github/workflows/version-release.yml index b15911e..082bf38 100644 --- a/.github/workflows/version-release.yml +++ b/.github/workflows/version-release.yml @@ -26,10 +26,18 @@ jobs: with: token: ${{ secrets.PUBLISHER_TOKEN }} - - name: Configure Git + - name: Validate version format + id: validate + run: .github/scripts/validate_semver.sh "${{ github.event.inputs.version }}" + + - name: Check if input version run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" + CURRENT_VERSION=$(grep -oP '(?<=__version__ = ")[^"]+' src/version.py) + INPUT_VERSION="${{ github.event.inputs.version }}" + if [ "$CURRENT_VERSION" = "$INPUT_VERSION" ]; then + echo "Error: Input version '$INPUT_VERSION' is the same as the current version" + exit 1 + fi - name: Check if branch exists run: | @@ -45,7 +53,11 @@ jobs: - name: Create release branch and update version run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + VERSION="${{ steps.validate.outputs.version }}" + # Update version.py mv -f src/version.py src/last_version.py echo "__version__ = \"$VERSION\"" > src/version.py