Skip to content
Open
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
137 changes: 137 additions & 0 deletions .github/skills/prepare-release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
name: prepare-release
description: Prepare a release for the Azure App Configuration JavaScript Provider. Use when user mentions release preparation, version bump, creating merge PRs, preview release, or stable release for this project.
---

# Prepare Release

This skill automates the release preparation workflow for the [Azure App Configuration JavaScript Provider](https://github.com/Azure/AppConfiguration-JavaScriptProvider) project.

## When to Use This Skill

Use this skill when you need to:
- Bump the package version for a new stable or preview release
- Create merge PRs to sync branches (test-main → test-preview, test-main → test-release/stable, test-preview → test-release)
- Prepare all the PRs needed before publishing a new release
- Resolve merge conflicts between test-main and test-preview branches

## Background

### Repository Information
- **GitHub Repo**: https://github.com/Azure/AppConfiguration-JavaScriptProvider
- **Package Name**: `@azure/app-configuration-provider`

### Branch Structure
- `test-main` – primary development branch for stable releases
- `test-preview` – development branch for preview releases
- `test-release/stable/v{major}` – release branch for stable versions (e.g., `test-release/stable/v2`)
- `test-release/v{major}` – release branch for preview versions (e.g., `test-release/v2`)

### Version Files
The version must be updated in **all four locations** simultaneously:
1. `src/version.ts` – line 4: `export const VERSION = "<version>";`
2. `package.json` – line 3: `"version": "<version>",`
3. `package-lock.json` – line 3: `"version": "<version>",`
4. `package-lock.json` – line 9: `"version": "<version>",`

### Version Format
- **Stable**: `{major}.{minor}.{patch}` (e.g., `2.4.0`)
- **Preview**: `{major}.{minor}.{patch}-preview` (e.g., `2.4.1-preview`)

## Quick Start

Ask the user whether this is a **stable** or **preview** release, and what the **new version number** should be. Then follow the appropriate workflow below.

---

### Workflow A: Stable Release

#### Step 1: Version Bump PR

Create a version bump PR targeting `test-main` by running the version bump script:

```bash
./scripts/version-bump.sh <new_version>
```

For example: `./scripts/version-bump.sh 2.5.0`

The script will automatically:
1. Read the current version from `src/version.ts`.
2. Create a new branch from `test-main` named `<username>/version-<new_version>` (e.g., `linglingye/version-2.5.0`).
3. Update the version in all four files (`src/version.ts`, `package.json`, `package-lock.json` lines 3 and 9).
4. Commit, push, and create a PR to `test-main` with title: `Version bump <new_version>`.

When the script prompts `Proceed? [y/N]`, confirm by entering `y`.

**Sample PR**: https://github.com/Azure/AppConfiguration-JavaScriptProvider/pull/277

#### Step 2: Merge Main to Release Branch

After the version bump PR is merged, create a PR to merge `test-main` into the stable release branch.

1. Determine the major version from the new version string (e.g., `2` from `2.4.0`).
2. Create a PR from `test-main` → `test-release/stable/v{major}` (e.g., `test-release/stable/v2`).
3. Title the PR: `Merge test-main to test-release/stable/v{major}`.

> **Important**: Use "Merge commit" (not squash) when merging this PR to preserve commit history.

**Sample PR**: https://github.com/Azure/AppConfiguration-JavaScriptProvider/pull/268

---

### Workflow B: Preview Release

#### Step 1: Merge Main to Preview (Conflict Resolution)

Create a PR to merge `test-main` into `test-preview`. This will likely have conflicts.

1. Fetch the latest `test-main` and `test-preview` branches.
2. Create a new branch from `test-preview` named `<username>/resolve-conflict` (or similar).
3. Merge `test-main` into this branch. If there are conflicts, inform the user and let them resolve manually.
4. Push the branch and create a PR targeting `test-preview` with title: `Merge test-main to test-preview`.

> **Important**: Use "Merge commit" (not squash) when merging this PR.

**Sample PR**: https://github.com/Azure/AppConfiguration-JavaScriptProvider/pull/272

#### Step 2: Version Bump PR

After the merge-to-preview PR is merged, create a version bump PR targeting `test-preview` by running the version bump script with the `--preview` flag:

```bash
./scripts/version-bump.sh <new_version> --preview
```

For example: `./scripts/version-bump.sh 2.5.1-preview --preview`

The script will automatically:
1. Read the current version from `src/version.ts` on the `test-preview` branch.
2. Create a new branch from `test-preview` named `<username>/version-<new_version>` (e.g., `linglingye/version-2.5.1-preview`).
3. Update the version in all four files (`src/version.ts`, `package.json`, `package-lock.json` lines 3 and 9).
4. Commit, push, and create a PR to `test-preview` with title: `Version bump <new_version>`.

When the script prompts `Proceed? [y/N]`, confirm by entering `y`.

#### Step 3: Merge Preview to Release Branch

After the version bump PR is merged, create a PR to merge `test-preview` into the preview release branch.

1. Determine the major version from the new version string (e.g., `2` from `2.4.1-preview`).
2. Create a PR from `test-preview` → `test-release/v{major}` (e.g., `test-release/v2`).
3. Title the PR: `Merge test-preview to test-release/v{major}`.

> **Important**: Use "Merge commit" (not squash) when merging this PR.

**Sample PR**: https://github.com/Azure/AppConfiguration-JavaScriptProvider/pull/274

---

## Review Checklist

Each PR should be reviewed with the following checks:
- [ ] Version is updated consistently across all 3 files
- [ ] No unintended file changes are included
- [ ] Merge PRs use **merge commit** strategy (not squash)
- [ ] Branch names follow the naming conventions
- [ ] All CI checks pass
211 changes: 211 additions & 0 deletions scripts/version-bump.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#!/bin/bash

# ============================================================================
# version-bump.sh
#
# Automates the version bump workflow for @azure/app-configuration-provider.
# Updates version in all required files, creates a branch, commits, pushes,
# and opens a PR via the GitHub CLI (gh).
#
# Usage:
# ./scripts/version-bump.sh <new_version> [--preview]
#
# Examples:
# ./scripts/version-bump.sh 2.5.0 # stable release → PR to test-main
# ./scripts/version-bump.sh 2.5.1-preview --preview # preview release → PR to test-preview
#
# Prerequisites:
# - git, sed, and gh (GitHub CLI) must be installed and authenticated
# ============================================================================

set -euo pipefail

# ── Helpers ──────────────────────────────────────────────────────────────────

usage() {
cat <<EOF
Usage: $(basename "$0") <new_version> [--preview]

Arguments:
new_version The version to bump to (e.g. 2.5.0 or 2.5.1-preview)
--preview Target the test-preview branch instead of test-main

Examples:
$(basename "$0") 2.5.0 # stable → PR to test-main
$(basename "$0") 2.5.1-preview --preview # preview → PR to test-preview
EOF
exit 1
}

error() {
echo "ERROR: $1" >&2
exit 1
}

info() {
echo "── $1"
}

# ── Parse arguments ──────────────────────────────────────────────────────────

NEW_VERSION=""
IS_PREVIEW=false

while [[ $# -gt 0 ]]; do
case "$1" in
--preview)
IS_PREVIEW=true
shift
;;
-h|--help)
usage
;;
*)
if [[ -z "$NEW_VERSION" ]]; then
NEW_VERSION="$1"
else
error "Unexpected argument: $1"
fi
shift
;;
esac
done

[[ -z "$NEW_VERSION" ]] && usage

# Validate version format: major.minor.patch or major.minor.patch-preview
if ! echo "$NEW_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-preview)?$'; then
error "Invalid version format '$NEW_VERSION'. Expected: X.Y.Z or X.Y.Z-preview"
fi

# If version ends with -preview, ensure --preview flag is set
if echo "$NEW_VERSION" | grep -qE '\-preview$'; then
if [[ "$IS_PREVIEW" == false ]]; then
error "Version '$NEW_VERSION' looks like a preview version. Did you forget --preview?"
fi
fi

# ── Resolve paths & context ─────────────────────────────────────────────────

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"

VERSION_TS="$PROJECT_DIR/src/version.ts"
PACKAGE_JSON="$PROJECT_DIR/package.json"
PACKAGE_LOCK="$PROJECT_DIR/package-lock.json"

# Determine target branch and branch prefix
if [[ "$IS_PREVIEW" == true ]]; then
TARGET_BRANCH="test-preview"
else
TARGET_BRANCH="test-main"
fi

# Get git username for branch naming (e.g. "linglingye" from "linglingye/version-2.4.0")
GIT_USERNAME=$(git config user.name 2>/dev/null || echo "")
if [[ -z "$GIT_USERNAME" ]]; then
error "Could not determine git user.name. Please set it with: git config user.name <name>"
fi
# Use the first token (lowercase, no spaces) as the branch prefix
BRANCH_PREFIX=$(echo "$GIT_USERNAME" | awk '{print $1}' | tr '[:upper:]' '[:lower:]')

BRANCH_NAME="${BRANCH_PREFIX}/version-${NEW_VERSION}"

# ── Read current version ─────────────────────────────────────────────────────

CURRENT_VERSION=$(grep -oP 'VERSION = "\K[^"]+' "$VERSION_TS")
info "Current version : $CURRENT_VERSION"
info "New version : $NEW_VERSION"
info "Target branch : $TARGET_BRANCH"
info "New branch : $BRANCH_NAME"
echo ""

if [[ "$CURRENT_VERSION" == "$NEW_VERSION" ]]; then
error "Current version is already $NEW_VERSION. Nothing to do."
fi

# ── Confirm with user ────────────────────────────────────────────────────────

read -rp "Proceed? [y/N] " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 0
fi

echo ""

# ── Create branch from target ────────────────────────────────────────────────

cd "$PROJECT_DIR"

info "Fetching latest $TARGET_BRANCH..."
git fetch origin "$TARGET_BRANCH"

info "Creating branch '$BRANCH_NAME' from origin/$TARGET_BRANCH..."
git checkout -b "$BRANCH_NAME" "origin/$TARGET_BRANCH"

# ── Update version in all files ──────────────────────────────────────────────

info "Updating src/version.ts..."
sed -i "s/export const VERSION = \"$CURRENT_VERSION\"/export const VERSION = \"$NEW_VERSION\"/" "$VERSION_TS"

info "Updating package.json..."
sed -i "0,/\"version\": \"$CURRENT_VERSION\"/s//\"version\": \"$NEW_VERSION\"/" "$PACKAGE_JSON"

info "Updating package-lock.json (line 3)..."
# package-lock.json has the version on line 3 and line 9 — update both
sed -i "0,/\"version\": \"$CURRENT_VERSION\"/s//\"version\": \"$NEW_VERSION\"/" "$PACKAGE_LOCK"

info "Updating package-lock.json (line 9)..."
sed -i "0,/\"version\": \"$CURRENT_VERSION\"/s//\"version\": \"$NEW_VERSION\"/" "$PACKAGE_LOCK"

# ── Verify changes ──────────────────────────────────────────────────────────

info "Verifying updates..."

verify_version() {
local file="$1"
local expected="$2"
if ! grep -q "\"$expected\"" "$file" 2>/dev/null && ! grep -q "\"$expected\"" "$file" 2>/dev/null; then
error "Version not found in $file after update. Please check manually."
fi
}

# Check src/version.ts specifically
if ! grep -q "export const VERSION = \"$NEW_VERSION\"" "$VERSION_TS"; then
error "Version not updated in src/version.ts"
fi
verify_version "$PACKAGE_JSON" "$NEW_VERSION"
verify_version "$PACKAGE_LOCK" "$NEW_VERSION"

info "All version files updated ✓"
echo ""

# ── Commit, push, and create PR ─────────────────────────────────────────────

COMMIT_MSG="version bump $NEW_VERSION"

info "Committing changes..."
git add "$VERSION_TS" "$PACKAGE_JSON" "$PACKAGE_LOCK"
git commit -m "$COMMIT_MSG"

info "Pushing branch '$BRANCH_NAME'..."
git push origin "$BRANCH_NAME"

info "Creating pull request..."
PR_URL=$(gh pr create \
--base "$TARGET_BRANCH" \
--head "$BRANCH_NAME" \
--title "Version bump $NEW_VERSION" \
--body "Bump version from \`$CURRENT_VERSION\` to \`$NEW_VERSION\`.

### Changes
- \`src/version.ts\` – updated VERSION constant
- \`package.json\` – updated version field
- \`package-lock.json\` – updated version fields (lines 3 and 9)

---
*This PR was created automatically by \`scripts/version-bump.sh\`.*")

echo ""
info "Done! PR created: $PR_URL"
Loading