Skip to content

Commit ac14948

Browse files
authored
Release Process Update (#101)
1 parent e4da4a0 commit ac14948

File tree

2 files changed

+266
-3
lines changed

2 files changed

+266
-3
lines changed
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
# Prepare Release Workflow
2+
# This workflow automates the release preparation process:
3+
# 1. Updates package versions in all package.json files
4+
# 2. Generates changelog from git diff between main and last release tag
5+
# 3. Creates a release branch and tag
6+
# 4. Opens a pull request for review
7+
8+
name: Prepare Release
9+
10+
on:
11+
workflow_dispatch:
12+
inputs:
13+
version:
14+
description: 'Release version (e.g., 0.2.0-beta.1). Leave empty to auto-increment patch version.'
15+
required: false
16+
type: string
17+
18+
permissions:
19+
contents: write
20+
pull-requests: write
21+
22+
jobs:
23+
prepare-release:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Checkout repository
27+
uses: actions/checkout@v4
28+
with:
29+
fetch-depth: 0 # Full history needed for git diff and tags
30+
31+
- name: Setup Node.js
32+
uses: actions/setup-node@v4
33+
with:
34+
node-version: '22'
35+
36+
- name: Get latest release tag
37+
id: get-latest-tag
38+
run: |
39+
# Get the latest tag that looks like a version (v*)
40+
LATEST_TAG=$(git tag -l 'v*' --sort=-v:refname | head -n 1)
41+
if [ -z "$LATEST_TAG" ]; then
42+
echo "No previous release tag found, using initial commit"
43+
LATEST_TAG=$(git rev-list --max-parents=0 HEAD)
44+
fi
45+
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
46+
echo "Latest tag: $LATEST_TAG"
47+
48+
- name: Get current version
49+
id: get-current-version
50+
run: |
51+
CURRENT_VERSION=$(node -p "require('./packages/durabletask-js/package.json').version")
52+
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
53+
echo "Current version: $CURRENT_VERSION"
54+
55+
- name: Calculate next version
56+
id: calc-version
57+
run: |
58+
INPUT_VERSION="${{ github.event.inputs.version }}"
59+
CURRENT_VERSION="${{ steps.get-current-version.outputs.current_version }}"
60+
61+
if [ -n "$INPUT_VERSION" ]; then
62+
# Use the specified version
63+
NEW_VERSION="$INPUT_VERSION"
64+
else
65+
# Auto-increment: parse current version and bump appropriately
66+
# Handle pre-release versions like 0.1.0-alpha.2 -> 0.1.0-alpha.3
67+
# Handle stable versions like 0.1.0 -> 0.1.1
68+
NEW_VERSION=$(node -e "
69+
const v = '$CURRENT_VERSION';
70+
const match = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-([a-z]+)\.(\d+))?$/);
71+
if (!match) {
72+
console.log(v);
73+
process.exit(0);
74+
}
75+
const [, major, minor, patch, preType, preNum] = match;
76+
if (preType && preNum) {
77+
// Increment pre-release number
78+
console.log(\`\${major}.\${minor}.\${patch}-\${preType}.\${parseInt(preNum) + 1}\`);
79+
} else {
80+
// Increment patch version
81+
console.log(\`\${major}.\${minor}.\${parseInt(patch) + 1}\`);
82+
}
83+
")
84+
fi
85+
86+
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
87+
echo "New version: $NEW_VERSION"
88+
89+
- name: Generate changelog diff
90+
id: changelog-diff
91+
run: |
92+
LATEST_TAG="${{ steps.get-latest-tag.outputs.latest_tag }}"
93+
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
94+
95+
echo "Generating changelog for changes between $LATEST_TAG and HEAD..."
96+
97+
# Get merge commits (PRs) between last tag and HEAD
98+
CHANGELOG_CONTENT=$(git log "$LATEST_TAG"..HEAD --merges --pretty=format:"- %s" | \
99+
sed 's/Merge pull request #\([0-9]*\) from [^:]*:/\[#\1\](https:\/\/github.com\/microsoft\/durabletask-js\/pull\/\1):/' | \
100+
sed 's/Merge branch .*//' | \
101+
grep -v '^$' || echo "")
102+
103+
# If no merge commits, get regular commits
104+
if [ -z "$CHANGELOG_CONTENT" ]; then
105+
CHANGELOG_CONTENT=$(git log "$LATEST_TAG"..HEAD --pretty=format:"- %s" --no-merges | head -20)
106+
fi
107+
108+
# Save to file for multi-line output
109+
echo "$CHANGELOG_CONTENT" > /tmp/changelog_content.txt
110+
echo "changelog_file=/tmp/changelog_content.txt" >> $GITHUB_OUTPUT
111+
112+
echo "Generated changelog:"
113+
cat /tmp/changelog_content.txt
114+
115+
- name: Update package versions
116+
run: |
117+
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
118+
119+
echo "Updating packages to version $NEW_VERSION..."
120+
121+
# Update durabletask-js package.json
122+
node -e "
123+
const fs = require('fs');
124+
const pkg = JSON.parse(fs.readFileSync('packages/durabletask-js/package.json', 'utf8'));
125+
pkg.version = '$NEW_VERSION';
126+
fs.writeFileSync('packages/durabletask-js/package.json', JSON.stringify(pkg, null, 2) + '\n');
127+
"
128+
129+
# Update durabletask-js-azuremanaged package.json
130+
node -e "
131+
const fs = require('fs');
132+
const pkg = JSON.parse(fs.readFileSync('packages/durabletask-js-azuremanaged/package.json', 'utf8'));
133+
pkg.version = '$NEW_VERSION';
134+
// Also update peer dependency to the new version
135+
if (pkg.peerDependencies && pkg.peerDependencies['@microsoft/durabletask-js']) {
136+
pkg.peerDependencies['@microsoft/durabletask-js'] = '>=$NEW_VERSION';
137+
}
138+
fs.writeFileSync('packages/durabletask-js-azuremanaged/package.json', JSON.stringify(pkg, null, 2) + '\n');
139+
"
140+
141+
echo "Updated package.json files:"
142+
grep '"version"' packages/durabletask-js/package.json
143+
grep '"version"' packages/durabletask-js-azuremanaged/package.json
144+
145+
- name: Update CHANGELOG.md
146+
run: |
147+
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
148+
CHANGELOG_FILE="${{ steps.changelog-diff.outputs.changelog_file }}"
149+
RELEASE_DATE=$(date +%Y-%m-%d)
150+
151+
# Read the changelog content
152+
CHANGELOG_CONTENT=$(cat "$CHANGELOG_FILE")
153+
154+
# Create new changelog section
155+
NEW_SECTION="## v${NEW_VERSION} (${RELEASE_DATE})
156+
157+
### Changes
158+
159+
${CHANGELOG_CONTENT}
160+
"
161+
162+
# Insert new section after "## Upcoming" section
163+
node -e "
164+
const fs = require('fs');
165+
let content = fs.readFileSync('CHANGELOG.md', 'utf8');
166+
167+
const newSection = \`$NEW_SECTION\`;
168+
169+
// Find the Upcoming section and insert after it
170+
const upcomingMatch = content.match(/## Upcoming[\s\S]*?(?=\n## v|$)/);
171+
if (upcomingMatch) {
172+
const upcomingEnd = content.indexOf(upcomingMatch[0]) + upcomingMatch[0].length;
173+
content = content.slice(0, upcomingEnd) + '\n' + newSection + content.slice(upcomingEnd);
174+
} else {
175+
// No Upcoming section, prepend
176+
content = '## Upcoming\n\n' + newSection + content;
177+
}
178+
179+
// Reset the Upcoming section to empty
180+
content = content.replace(/## Upcoming[\s\S]*?(?=\n## v)/, '## Upcoming\n\n### New\n\n### Fixes\n\n');
181+
182+
fs.writeFileSync('CHANGELOG.md', content);
183+
"
184+
185+
echo "Updated CHANGELOG.md"
186+
187+
- name: Create release branch and commit
188+
id: create-branch
189+
run: |
190+
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
191+
BRANCH_NAME="release/v${NEW_VERSION}"
192+
193+
git config user.name "github-actions[bot]"
194+
git config user.email "github-actions[bot]@users.noreply.github.com"
195+
196+
# Create and checkout release branch
197+
git checkout -b "$BRANCH_NAME"
198+
199+
# Stage and commit changes
200+
git add packages/durabletask-js/package.json
201+
git add packages/durabletask-js-azuremanaged/package.json
202+
git add CHANGELOG.md
203+
git commit -m "Release v${NEW_VERSION}"
204+
205+
# Create release tag
206+
git tag "v${NEW_VERSION}"
207+
208+
# Push branch and tag
209+
git push origin "$BRANCH_NAME"
210+
git push origin "v${NEW_VERSION}"
211+
212+
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
213+
echo "Created branch $BRANCH_NAME and tag v${NEW_VERSION}"
214+
215+
- name: Create Pull Request
216+
env:
217+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
218+
run: |
219+
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
220+
BRANCH_NAME="${{ steps.create-branch.outputs.branch_name }}"
221+
CHANGELOG_FILE="${{ steps.changelog-diff.outputs.changelog_file }}"
222+
223+
CHANGELOG_CONTENT=$(cat "$CHANGELOG_FILE")
224+
225+
PR_BODY="## Release v${NEW_VERSION}
226+
227+
This PR prepares the release of version **${NEW_VERSION}** for all packages.
228+
229+
### Packages Updated
230+
- \`@microsoft/durabletask-js@${NEW_VERSION}\`
231+
- \`@microsoft/durabletask-js-azuremanaged@${NEW_VERSION}\`
232+
233+
### Changes Since Last Release
234+
${CHANGELOG_CONTENT}
235+
236+
### Release Checklist
237+
- [ ] Review version bumps in package.json files
238+
- [ ] Review CHANGELOG.md updates
239+
- [ ] Verify CI passes
240+
- [ ] Merge this PR
241+
- [ ] After merge, the official build pipeline will produce signed artifacts
242+
- [ ] Download artifacts and publish to npm with appropriate tag
243+
"
244+
245+
gh pr create \
246+
--title "Release v${NEW_VERSION}" \
247+
--body "$PR_BODY" \
248+
--base main \
249+
--head "$BRANCH_NAME" \
250+
--label "release"
251+
252+
- name: Summary
253+
run: |
254+
NEW_VERSION="${{ steps.calc-version.outputs.new_version }}"
255+
BRANCH_NAME="${{ steps.create-branch.outputs.branch_name }}"
256+
257+
echo "## Release Preparation Complete! :rocket:" >> $GITHUB_STEP_SUMMARY
258+
echo "" >> $GITHUB_STEP_SUMMARY
259+
echo "- **Version**: v${NEW_VERSION}" >> $GITHUB_STEP_SUMMARY
260+
echo "- **Branch**: ${BRANCH_NAME}" >> $GITHUB_STEP_SUMMARY
261+
echo "- **Tag**: v${NEW_VERSION}" >> $GITHUB_STEP_SUMMARY
262+
echo "" >> $GITHUB_STEP_SUMMARY
263+
echo "A pull request has been created. Review and merge to complete the release." >> $GITHUB_STEP_SUMMARY

eng/templates/build.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ jobs:
3030

3131
# Build azure-managed extension package
3232
- script: |
33-
cd extensions/durabletask-js-azuremanaged
33+
cd packages/durabletask-js-azuremanaged
3434
npm ci
3535
npm run build
3636
npm run test
3737
npm prune --production
3838
displayName: "Build azure-managed extension"
3939
- script: |
40-
cd extensions/durabletask-js-azuremanaged
40+
cd packages/durabletask-js-azuremanaged
4141
npm pack
4242
displayName: "pack azure-managed extension"
4343
@@ -50,6 +50,6 @@ jobs:
5050
- task: CopyFiles@2
5151
displayName: "Copy azure-managed extension to staging"
5252
inputs:
53-
SourceFolder: $(System.DefaultWorkingDirectory)/extensions/durabletask-js-azuremanaged
53+
SourceFolder: $(System.DefaultWorkingDirectory)/packages/durabletask-js-azuremanaged
5454
Contents: "*.tgz"
5555
TargetFolder: $(Build.ArtifactStagingDirectory)/buildoutputs

0 commit comments

Comments
 (0)