Prepare Release #8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 |