From: Daniel Bevenius Date: Thu, 25 Sep 2025 10:38:50 +0000 (+0200) Subject: scripts : refactor release script into prepare and finalize stages (#1352) X-Git-Tag: v0.9.3~1 X-Git-Url: https://git.djapps.eu/?a=commitdiff_plain;h=f880357699eff040ca3e232372a151e317b92e63;p=pkg%2Fggml%2Fsources%2Fggml scripts : refactor release script into prepare and finalize stages (#1352) This commit splits the release process into two distinct stages: * prepare_release: This stage handles all updating the version and creating a new branch with the version change. This should then be use to open a PR for review. Once the PR has been merged the finalize_release stage can be run. * finalize_release: This stage must be run on master and master must have the version bump commit (this is checked for). This stage handles tagging, and also creates a new branch for the update of the new development version. The tag should then be pushed to the remote which will trigger the release process on GitHub. The branch should be used to open a new PR for the development version update. --- diff --git a/scripts/release.sh b/scripts/release.sh index 188fcc06..ed1b54ba 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -6,19 +6,31 @@ # prior to running this script. # # Usage: -# ./scripts/release.sh [major|minor|patch] [--dry-run] +# ./scripts/release.sh prepare [major|minor|patch] [--dry-run] +# ./scripts/release.sh finalize [--dry-run] # -# Example usage: -# $ ./scripts/release.sh minor --dry-run +# Two-stage release process: # -# This will show what the actions that would be taken to increment the minor -# version of the project. +# Stage 1 - Prepare: +# $ ./scripts/release.sh prepare minor +# This creates a release candidate branch with version bump and removes -dev suffix. +# The branch should then be manually pushed and a PR created, reviewed, and merged. # -# This script: -# 1. Updates version and removes -dev suffix -# 2. Commits the version bump -# 3. Creates a git tag -# 4. Prepares for next development cycle +# Stage 2 - Finalize: +# $ ./scripts/release.sh finalize +# After the RC PR is merged, this reads the current version from CMakeLists.txt, +# creates the release tag, and prepares the next development cycle. +# +# Prepare stage: +# 1. Creates release candidate branch +# 2. Updates version and removes -dev suffix +# 3. Commits the version bump +# +# Finalize stage: +# 1. Reads current release version from CMakeLists.txt +# 2. Creates signed git tag on master +# 3. Adds -dev suffix back for next development cycle +# 4. Creates branch and commit for development version # set -e @@ -29,216 +41,300 @@ if [ ! -f "CMakeLists.txt" ] || [ ! -d "scripts" ]; then fi # Parse command line arguments +COMMAND="" VERSION_TYPE="" DRY_RUN=false +# First argument should be the command +if [ $# -eq 0 ]; then + echo "Error: Missing command" + echo "Usage: $0 prepare [major|minor|patch] [--dry-run]" + echo " $0 finalize [--dry-run]" + exit 1 +fi + +COMMAND="$1" +shift + +# Parse remaining arguments for arg in "$@"; do case $arg in --dry-run) DRY_RUN=true - shift ;; major|minor|patch) - VERSION_TYPE="$arg" - shift + if [ "$COMMAND" = "prepare" ]; then + VERSION_TYPE="$arg" + else + echo "Error: Version type only valid for 'prepare' command" + exit 1 + fi ;; *) echo "Error: Unknown argument '$arg'" - echo "Usage: $0 [major|minor|patch] [--dry-run]" + echo "Usage: $0 prepare [major|minor|patch] [--dry-run]" + echo " $0 finalize [--dry-run]" exit 1 ;; esac done -# Default to patch if no version type specified -VERSION_TYPE="${VERSION_TYPE:-patch}" - -if [[ ! "$VERSION_TYPE" =~ ^(major|minor|patch)$ ]]; then - echo "Error: Version type must be 'major', 'minor', or 'patch'" - echo "Usage: $0 [major|minor|patch] [--dry-run]" +# Validate command +if [[ ! "$COMMAND" =~ ^(prepare|finalize)$ ]]; then + echo "Error: Command must be 'prepare' or 'finalize'" + echo "Usage: $0 prepare [major|minor|patch] [--dry-run]" + echo " $0 finalize [--dry-run]" exit 1 fi -if [ "$DRY_RUN" = true ]; then - echo "[dry-run] - No changes will be made" - echo "" -else - echo "Starting automated release process..." +# For prepare command, default to patch if no version type specified +if [ "$COMMAND" = "prepare" ]; then + VERSION_TYPE="${VERSION_TYPE:-patch}" + if [[ ! "$VERSION_TYPE" =~ ^(major|minor|patch)$ ]]; then + echo "Error: Version type must be 'major', 'minor', or 'patch'" + echo "Usage: $0 prepare [major|minor|patch] [--dry-run]" + exit 1 + fi fi -# Check for uncommitted changes (skip in dry-run) -if [ "$DRY_RUN" = false ] && ! git diff-index --quiet HEAD --; then - echo "Error: You have uncommitted changes. Please commit or stash them first." - exit 1 -fi +# Common validation functions +check_git_status() { + # Check for uncommitted changes (skip in dry-run) + if [ "$DRY_RUN" = false ] && ! git diff-index --quiet HEAD --; then + echo "Error: You have uncommitted changes. Please commit or stash them first." + exit 1 + fi +} + +check_master_branch() { + # Ensure we're on master branch + CURRENT_BRANCH=$(git branch --show-current) + if [ "$CURRENT_BRANCH" != "master" ]; then + if [ "$DRY_RUN" = true ]; then + echo "[dry run] Warning: Not on master branch (currently on: $CURRENT_BRANCH). Continuing with dry-run..." + echo "" + else + echo "Error: Must be on master branch. Currently on: $CURRENT_BRANCH" + exit 1 + fi + fi +} + +check_master_up_to_date() { + # Check if we have the latest from master (skip in dry-run) + if [ "$DRY_RUN" = false ]; then + echo "Checking if local master is up-to-date with remote..." + git fetch origin master + LOCAL=$(git rev-parse HEAD) + REMOTE=$(git rev-parse origin/master) + + if [ "$LOCAL" != "$REMOTE" ]; then + echo "Error: Your local master branch is not up-to-date with origin/master." + echo "Please run 'git pull origin master' first." + exit 1 + fi + echo "✓ Local master is up-to-date with remote" + echo "" + elif [ "$(git branch --show-current)" = "master" ]; then + echo "[dry run] Warning: Dry-run mode - not checking if master is up-to-date with remote" + echo "" + fi +} + +prepare_release() { + if [ "$DRY_RUN" = true ]; then + echo "[dry-run] Preparing release (no changes will be made)" + else + echo "Starting release preparation..." + fi + echo "" + + check_git_status + check_master_branch + check_master_up_to_date + + # Extract current version from CMakeLists.txt + echo "Step 1: Reading current version..." + MAJOR=$(grep "set(GGML_VERSION_MAJOR" CMakeLists.txt | sed 's/.*MAJOR \([0-9]*\).*/\1/') + MINOR=$(grep "set(GGML_VERSION_MINOR" CMakeLists.txt | sed 's/.*MINOR \([0-9]*\).*/\1/') + PATCH=$(grep "set(GGML_VERSION_PATCH" CMakeLists.txt | sed 's/.*PATCH \([0-9]*\).*/\1/') + + echo "Current version: $MAJOR.$MINOR.$PATCH-dev" + + # Calculate new version + case $VERSION_TYPE in + major) + NEW_MAJOR=$((MAJOR + 1)) + NEW_MINOR=0 + NEW_PATCH=0 + ;; + minor) + NEW_MAJOR=$MAJOR + NEW_MINOR=$((MINOR + 1)) + NEW_PATCH=0 + ;; + patch) + NEW_MAJOR=$MAJOR + NEW_MINOR=$MINOR + NEW_PATCH=$((PATCH + 1)) + ;; + esac + + NEW_VERSION="$NEW_MAJOR.$NEW_MINOR.$NEW_PATCH" + RC_BRANCH="ggml-rc-v$NEW_VERSION" + echo "New release version: $NEW_VERSION" + echo "Release candidate branch: $RC_BRANCH" + echo "" -# Ensure we're on master branch -CURRENT_BRANCH=$(git branch --show-current) -if [ "$CURRENT_BRANCH" != "master" ]; then + # Create release candidate branch + echo "Step 2: Creating release candidate branch..." if [ "$DRY_RUN" = true ]; then - echo "[dry run] Warning: Not on master branch (currently on: $CURRENT_BRANCH). Continuing with dry-run..." + echo " [dry-run] Would create branch: $RC_BRANCH" + else + git checkout -b "$RC_BRANCH" + echo "✓ Created and switched to branch: $RC_BRANCH" + fi + echo "" + + # Update CMakeLists.txt for release + echo "Step 3: Updating version in CMakeLists.txt..." + if [ "$DRY_RUN" = true ]; then + echo " [dry-run] Would update GGML_VERSION_MAJOR to $NEW_MAJOR" + echo " [dry-run] Would update GGML_VERSION_MINOR to $NEW_MINOR" + echo " [dry-run] Would update GGML_VERSION_PATCH to $NEW_PATCH" + echo " [dry-run] Would remove -dev suffix" + else + sed -i'' -e "s/set(GGML_VERSION_MAJOR [0-9]*)/set(GGML_VERSION_MAJOR $NEW_MAJOR)/" CMakeLists.txt + sed -i'' -e "s/set(GGML_VERSION_MINOR [0-9]*)/set(GGML_VERSION_MINOR $NEW_MINOR)/" CMakeLists.txt + sed -i'' -e "s/set(GGML_VERSION_PATCH [0-9]*)/set(GGML_VERSION_PATCH $NEW_PATCH)/" CMakeLists.txt + sed -i'' -e 's/set(GGML_VERSION_DEV "-dev")/set(GGML_VERSION_DEV "")/' CMakeLists.txt + fi + echo "" + + # Commit version bump + echo "Step 4: Committing version bump..." + if [ "$DRY_RUN" = true ]; then + echo " [dry-run] Would commit: 'ggml : bump version to $NEW_VERSION'" + else + git add CMakeLists.txt + git commit -m "ggml : bump version to $NEW_VERSION" + fi + echo "" + + echo "" + if [ "$DRY_RUN" = true ]; then + echo "[dry-run] Summary (no changes were made):" + echo " • Would have created branch: $RC_BRANCH" + echo " • Would have updated version to: $NEW_VERSION" + else + echo "Release preparation completed!" + echo "Summary:" + echo " • Created branch: $RC_BRANCH" + echo " • Updated version to: $NEW_VERSION" echo "" + echo "Next steps:" + echo " • Push branch to remote: git push origin $RC_BRANCH" + echo " • Create a Pull Request from $RC_BRANCH to master" + echo " • After PR is merged, run: ./scripts/release.sh finalize" + fi +} + +finalize_release() { + if [ "$DRY_RUN" = true ]; then + echo "[dry-run] Finalizing release (no changes will be made)" else - echo "Error: Must be on master branch to create release. Currently on: $CURRENT_BRANCH" - exit 1 + echo "Starting release finalization..." fi -fi + echo "" -# Check if we have the latest from master (skip in dry-run) -if [ "$DRY_RUN" = false ]; then - echo "Checking if local master is up-to-date with remote..." - git fetch origin master - LOCAL=$(git rev-parse HEAD) - REMOTE=$(git rev-parse origin/master) + check_git_status + check_master_branch + check_master_up_to_date - if [ "$LOCAL" != "$REMOTE" ]; then - echo "Error: Your local master branch is not up-to-date with origin/master." - echo "Please run 'git pull origin master' first." + # Read current version from CMakeLists.txt (should not have -dev suffix) + echo "Step 1: Reading current release version..." + MAJOR=$(grep "set(GGML_VERSION_MAJOR" CMakeLists.txt | sed 's/.*MAJOR \([0-9]*\).*/\1/') + MINOR=$(grep "set(GGML_VERSION_MINOR" CMakeLists.txt | sed 's/.*MINOR \([0-9]*\).*/\1/') + PATCH=$(grep "set(GGML_VERSION_PATCH" CMakeLists.txt | sed 's/.*PATCH \([0-9]*\).*/\1/') + DEV_SUFFIX=$(grep "set(GGML_VERSION_DEV" CMakeLists.txt | sed 's/.*DEV "\([^"]*\)".*/\1/') + + if [ "$DEV_SUFFIX" = "-dev" ]; then + echo "Error: Current version still has -dev suffix. Make sure the release candidate PR has been merged." exit 1 fi - echo "✓ Local master is up-to-date with remote" + + RELEASE_VERSION="$MAJOR.$MINOR.$PATCH" + echo "Release version: $RELEASE_VERSION" echo "" -elif [ "$CURRENT_BRANCH" = "master" ]; then - echo "[dry run] Warning: Dry-run mode - not checking if master is up-to-date with remote" + + # Create git tag + echo "Step 2: Creating signed git tag..." + if [ "$DRY_RUN" = true ]; then + echo " [dry-run] Would create signed tag: v$RELEASE_VERSION with message 'Release version $RELEASE_VERSION'" + else + git tag -s "v$RELEASE_VERSION" -m "Release version $RELEASE_VERSION" + echo "✓ Created signed tag: v$RELEASE_VERSION" + fi echo "" -fi -# Extract current version from CMakeLists.txt -echo "Step 1: Reading current version..." -MAJOR=$(grep "set(GGML_VERSION_MAJOR" CMakeLists.txt | sed 's/.*MAJOR \([0-9]*\).*/\1/') -MINOR=$(grep "set(GGML_VERSION_MINOR" CMakeLists.txt | sed 's/.*MINOR \([0-9]*\).*/\1/') -PATCH=$(grep "set(GGML_VERSION_PATCH" CMakeLists.txt | sed 's/.*PATCH \([0-9]*\).*/\1/') + # Create branch for next development version + DEV_BRANCH="ggml-dev-v$RELEASE_VERSION" + echo "Step 3: Creating development branch..." + if [ "$DRY_RUN" = true ]; then + echo " [dry-run] Would create branch: $DEV_BRANCH" + else + git checkout -b "$DEV_BRANCH" + echo "✓ Created and switched to branch: $DEV_BRANCH" + fi + echo "" -echo "Current version: $MAJOR.$MINOR.$PATCH-dev" + # Add -dev suffix back (no version increment) + NEXT_DEV_VERSION="$RELEASE_VERSION-dev" + echo "Step 4: Adding -dev suffix for next development cycle ($NEXT_DEV_VERSION)..." + if [ "$DRY_RUN" = true ]; then + echo " [dry-run] Would add -dev suffix" + else + sed -i'' -e 's/set(GGML_VERSION_DEV "")/set(GGML_VERSION_DEV "-dev")/' CMakeLists.txt + fi + echo "" -# Calculate new version -case $VERSION_TYPE in - major) - NEW_MAJOR=$((MAJOR + 1)) - NEW_MINOR=0 - NEW_PATCH=0 - ;; - minor) - NEW_MAJOR=$MAJOR - NEW_MINOR=$((MINOR + 1)) - NEW_PATCH=0 - ;; - patch) - NEW_MAJOR=$MAJOR - NEW_MINOR=$MINOR - NEW_PATCH=$((PATCH + 1)) - ;; -esac + # Commit development version + echo "Step 5: Committing development version..." + if [ "$DRY_RUN" = true ]; then + echo " [dry-run] Would commit: 'ggml : prepare for development of $NEXT_DEV_VERSION'" + else + git add CMakeLists.txt + git commit -m "ggml : prepare for development of $NEXT_DEV_VERSION" + fi + echo "" -NEW_VERSION="$NEW_MAJOR.$NEW_MINOR.$NEW_PATCH" -RC_BRANCH="ggml-rc-v$NEW_VERSION" -echo "New release version: $NEW_VERSION" -echo "Release candidate branch: $RC_BRANCH" -echo "" - -# Create release candidate branch -echo "Step 2: Creating release candidate branch..." -if [ "$DRY_RUN" = true ]; then - echo " [dry-run] Would create branch: $RC_BRANCH" -else - git checkout -b "$RC_BRANCH" - echo "✓ Created and switched to branch: $RC_BRANCH" -fi -echo "" - -# Update CMakeLists.txt for release -echo "Step 3: Updating version in CMakeLists.txt..." -if [ "$DRY_RUN" = true ]; then - echo " [dry-run] Would update GGML_VERSION_MAJOR to $NEW_MAJOR" - echo " [dry-run] Would update GGML_VERSION_MINOR to $NEW_MINOR" - echo " [dry-run] Would update GGML_VERSION_PATCH to $NEW_PATCH" - echo " [dry-run] Would remove -dev suffix" -else - sed -i'' -e "s/set(GGML_VERSION_MAJOR [0-9]*)/set(GGML_VERSION_MAJOR $NEW_MAJOR)/" CMakeLists.txt - sed -i'' -e "s/set(GGML_VERSION_MINOR [0-9]*)/set(GGML_VERSION_MINOR $NEW_MINOR)/" CMakeLists.txt - sed -i'' -e "s/set(GGML_VERSION_PATCH [0-9]*)/set(GGML_VERSION_PATCH $NEW_PATCH)/" CMakeLists.txt - sed -i'' -e 's/set(GGML_VERSION_DEV "-dev")/set(GGML_VERSION_DEV "")/' CMakeLists.txt -fi -echo "" - -# Commit version bump -echo "Step 4: Committing version bump..." -if [ "$DRY_RUN" = true ]; then - echo " [dry-run] Would commit: 'ggml : bump version to $NEW_VERSION'" -else - git add CMakeLists.txt - git commit -m "ggml : bump version to $NEW_VERSION" -fi -echo "" - -# Create git tag -echo "Step 5: Creating signed git tag..." -if [ "$DRY_RUN" = true ]; then - echo " [dry-run] Would create signed tag: v$NEW_VERSION with message 'Release version $NEW_VERSION'" -else - git tag -s "v$NEW_VERSION" -m "Release version $NEW_VERSION" - echo "✓ Created signed tag: v$NEW_VERSION" -fi -echo "" - -# Prepare for next development cycle -echo "Step 6: Preparing for next development cycle..." -case $VERSION_TYPE in - major|minor) - NEXT_DEV_MINOR=$((NEW_MINOR)) - NEXT_DEV_VERSION="$NEW_MAJOR.$NEXT_DEV_MINOR.0-dev" - if [ "$DRY_RUN" = true ]; then - echo " [dry-run] Would update GGML_VERSION_MINOR to $NEXT_DEV_MINOR" - else - sed -i'' -e "s/set(GGML_VERSION_MINOR [0-9]*)/set(GGML_VERSION_MINOR $NEXT_DEV_MINOR)/" CMakeLists.txt - fi + echo "" + if [ "$DRY_RUN" = true ]; then + echo "[dry-run] Summary (no changes were made):" + echo " • Would have created tag: v$RELEASE_VERSION" + echo " • Would have created branch: $DEV_BRANCH" + echo " • Would have prepared next development version: $NEXT_DEV_VERSION" + else + echo "Release finalization completed!" + echo "Summary:" + echo " • Created signed tag: v$RELEASE_VERSION" + echo " • Created branch: $DEV_BRANCH" + echo " • Prepared next development version: $NEXT_DEV_VERSION" + echo "" + echo "Next steps:" + echo " • Push tag to remote: git push origin v$RELEASE_VERSION" + echo " • Push development branch: git push origin $DEV_BRANCH" + echo " • Create PR for development version manually" + echo " • The release is now complete!" + fi +} + +# Execute the appropriate command +case $COMMAND in + prepare) + prepare_release ;; - patch) - NEXT_DEV_PATCH=$((NEW_PATCH)) - NEXT_DEV_VERSION="$NEW_MAJOR.$NEW_MINOR.$NEXT_DEV_PATCH-dev" - if [ "$DRY_RUN" = true ]; then - echo " [dry-run] Would update GGML_VERSION_PATCH to $NEXT_DEV_PATCH" - else - sed -i'' -e "s/set(GGML_VERSION_PATCH [0-9]*)/set(GGML_VERSION_PATCH $NEXT_DEV_PATCH)/" CMakeLists.txt - fi + finalize) + finalize_release ;; esac - -if [ "$DRY_RUN" = true ]; then - echo " [dry-run] Would add -dev suffix back" -else - sed -i'' -e 's/set(GGML_VERSION_DEV "")/set(GGML_VERSION_DEV "-dev")/' CMakeLists.txt -fi -echo "" - -# Commit development version -echo "Step 7: Committing development version..." -if [ "$DRY_RUN" = true ]; then - echo " [dry-run] Would commit: 'ggml : prepare for development of $NEXT_DEV_VERSION'" -else - git add CMakeLists.txt - git commit -m "ggml : prepare for development of $NEXT_DEV_VERSION" -fi - -echo "" -if [ "$DRY_RUN" = true ]; then - echo "[dry-run] Summary (no changes were made):" - echo " • Would have created branch: $RC_BRANCH" - echo " • Would have created tag: v$NEW_VERSION" - echo " • Would have set next development version: $NEXT_DEV_VERSION" -else - echo "Release process completed!" - echo "Summary:" - echo " • Created branch: $RC_BRANCH" - echo " • Created tag: v$NEW_VERSION" - echo " • Next development version: $NEXT_DEV_VERSION" -fi -if [ "$DRY_RUN" = false ]; then - echo "Next steps:" - echo " • Review the commits and tag on branch $RC_BRANCH" - echo " • Push branch to remote: git push origin $RC_BRANCH" - echo " • Create a Pull Request from $RC_BRANCH to master" - echo " • After PR is merged, push the tag: git push origin v$NEW_VERSION" - echo " • The release will be completed once the tag is pushed" - echo "" -fi