Skip to content

Prepare Release

Prepare Release #8

# Prepare Release Workflow
# This workflow automates the release preparation process:
# 1. Updates package versions in all package.json files
# 2. Generates changelog from git diff between main and last release tag
# 3. Creates a release branch and tag
# After the workflow completes, manually create a PR from the release branch to main.
name: Prepare Release
on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., 0.2.0-beta.1). Leave empty to auto-increment patch version.'
required: false
type: string
permissions:
contents: write
jobs:
prepare-release:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history needed for git diff and tags
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Get current version
id: get-current-version
run: |
CURRENT_VERSION=$(node -p "require('./packages/durabletask-js/package.json').version")
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Current version: $CURRENT_VERSION"
- name: Calculate next version
id: calc-version
run: |
INPUT_VERSION="${{ github.event.inputs.version }}"
CURRENT_VERSION="${{ steps.get-current-version.outputs.current_version }}"
if [ -n "$INPUT_VERSION" ]; then
# Use the specified version
NEW_VERSION="$INPUT_VERSION"
else
# Auto-increment: parse current version and bump appropriately
# Handle pre-release versions like 0.1.0-alpha.2 -> 0.1.0-alpha.3
# Handle stable versions like 0.1.0 -> 0.1.1
NEW_VERSION=$(node -e "
const v = '$CURRENT_VERSION';
const match = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-([a-z]+)\.(\d+))?$/);
if (!match) {
console.log(v);
process.exit(0);
}
const [, major, minor, patch, preType, preNum] = match;
if (preType && preNum) {
// Increment pre-release number
console.log(\`\${major}.\${minor}.\${patch}-\${preType}.\${parseInt(preNum) + 1}\`);
} else {
// Increment patch version
console.log(\`\${major}.\${minor}.\${parseInt(patch) + 1}\`);
}
")
fi
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"
- name: Get latest release tag
id: get-latest-tag
run: |
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
# Get the latest tag that looks like a version (v*), excluding the
# tag being created so that re-runs don't use it as the baseline.
LATEST_TAG=$(git tag -l 'v*' --sort=-v:refname | \
grep -v "^v${NEW_VERSION}$" | head -n 1)
if [ -z "$LATEST_TAG" ]; then
echo "No previous release tag found, using initial commit"
LATEST_TAG=$(git rev-list --max-parents=0 HEAD)
fi
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
echo "Latest tag: $LATEST_TAG"
- name: Generate changelog diff
id: changelog-diff
run: |
LATEST_TAG="${{ steps.get-latest-tag.outputs.latest_tag }}"
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
echo "Generating changelog for changes between $LATEST_TAG and HEAD..."
# Get commits between last tag and HEAD.
# GitHub squash-merges put the PR number in parentheses, e.g. "Some change (#123)".
# We convert "(#N)" to a markdown link.
CHANGELOG_CONTENT=$(git log "$LATEST_TAG"..HEAD --pretty=format:"%s" --no-merges | \
sed 's/(#\([0-9]*\))/([#\1](https:\/\/github.com\/microsoft\/durabletask-js\/pull\/\1))/' | \
sed 's/^/- /' | \
grep -v '^- $' || echo "")
# Save to file for multi-line output
echo "$CHANGELOG_CONTENT" > /tmp/changelog_content.txt
echo "changelog_file=/tmp/changelog_content.txt" >> $GITHUB_OUTPUT
echo "Generated changelog:"
cat /tmp/changelog_content.txt
- name: Update package versions
run: |
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
echo "Updating packages to version $NEW_VERSION..."
# Update durabletask-js package.json
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('packages/durabletask-js/package.json', 'utf8'));
pkg.version = '$NEW_VERSION';
fs.writeFileSync('packages/durabletask-js/package.json', JSON.stringify(pkg, null, 2) + '\n');
"
# Update durabletask-js-azuremanaged package.json
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('packages/durabletask-js-azuremanaged/package.json', 'utf8'));
pkg.version = '$NEW_VERSION';
// Also update peer dependency to the new version
if (pkg.peerDependencies && pkg.peerDependencies['@microsoft/durabletask-js']) {
pkg.peerDependencies['@microsoft/durabletask-js'] = '>=$NEW_VERSION';
}
fs.writeFileSync('packages/durabletask-js-azuremanaged/package.json', JSON.stringify(pkg, null, 2) + '\n');
"
echo "Updated package.json files:"
grep '"version"' packages/durabletask-js/package.json
grep '"version"' packages/durabletask-js-azuremanaged/package.json
- name: Update CHANGELOG.md
run: |
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
CHANGELOG_FILE="${{ steps.changelog-diff.outputs.changelog_file }}"
RELEASE_DATE=$(date +%Y-%m-%d)
node scripts/update-changelog.js "$NEW_VERSION" "$RELEASE_DATE" "$CHANGELOG_FILE"
- name: Create release branch and commit
id: create-branch
run: |
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
BRANCH_NAME="release/v${NEW_VERSION}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Create and checkout release branch (idempotent)
git checkout -B "$BRANCH_NAME"
# Stage and commit changes
git add packages/durabletask-js/package.json
git add packages/durabletask-js-azuremanaged/package.json
git add CHANGELOG.md
git commit -m "Release v${NEW_VERSION}"
# Create release tag (idempotent)
git tag -f "v${NEW_VERSION}"
# Push branch and tag (force to handle re-runs)
git push -f origin "$BRANCH_NAME"
git push -f origin "v${NEW_VERSION}"
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "Created branch $BRANCH_NAME and tag v${NEW_VERSION}"
- name: Summary
run: |
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
BRANCH_NAME="${{ steps.create-branch.outputs.branch_name }}"
echo "## Release Preparation Complete! :rocket:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: v${NEW_VERSION}" >> $GITHUB_STEP_SUMMARY
echo "- **Branch**: ${BRANCH_NAME}" >> $GITHUB_STEP_SUMMARY
echo "- **Tag**: v${NEW_VERSION}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Next Step: Create a Pull Request" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Manually create a PR from **${BRANCH_NAME}** → **main** with title: **Release v${NEW_VERSION}**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "[Create PR](https://github.com/microsoft/durabletask-js/compare/main...${BRANCH_NAME}?expand=1&title=Release+v${NEW_VERSION})" >> $GITHUB_STEP_SUMMARY