1212# 5. Publishes both packages to npm (tries OIDC first, falls back to NPM_TOKEN)
1313# 6. Creates GitHub Release with changelog notes
1414#
15- # **Trigger:**
16- # Push a version tag:
17- # ```bash
18- # git tag v1.0.0
19- # git push origin main --tags
20- # ```
15+ # **Triggers:**
16+ # 1. Push a version tag (automatic):
17+ # ```bash
18+ # git tag v1.0.0
19+ # git push origin v1.0.0
20+ # ```
21+ # 2. Manual workflow_dispatch (button in GitHub Actions dashboard):
22+ # - Go to Actions → Release → Run workflow
23+ # - Enter version (e.g., "0.1.0") or leave empty to use package.json version
24+ # - Click "Run workflow"
25+ # - Workflow will: create tag → generate changelogs → commit → push tag → publish to npm
2126#
2227# **Prerequisites:**
2328# - package.json version must match tag version (e.g., 1.0.0)
5257 required : false
5358 type : string
5459
60+ # YAML anchors for reusable configurations
61+ x-common-setup : &common-setup
62+ - name : Checkout repository
63+ uses : actions/checkout@v6
64+ with :
65+ fetch-depth : 0 # Full history for changelog generation
66+ - name : Setup pnpm
67+ uses : pnpm/action-setup@v4
68+ - name : Setup Node.js
69+ uses : actions/setup-node@v4
70+ with :
71+ node-version : ' 22'
72+ cache : ' pnpm'
73+ - name : Install dependencies
74+ run : pnpm install --frozen-lockfile
75+
5576jobs :
5677 release :
5778 runs-on : ubuntu-latest
@@ -99,14 +120,22 @@ jobs:
99120 # Read from CLI package.json
100121 VERSION=$(node -p "require('./packages/opennextjs-cli/package.json').version")
101122 fi
123+ # Remove 'v' prefix if present
124+ VERSION="${VERSION#v}"
125+ TAG="v$VERSION"
126+ echo "TAG=$TAG" >> $GITHUB_OUTPUT
127+ echo "IS_MANUAL=true" >> $GITHUB_OUTPUT
102128 else
103129 # Extract version from tag (e.g., v1.0.0 → 1.0.0)
104130 TAG_NAME="${{ github.ref_name }}"
105131 VERSION="${TAG_NAME#v}"
132+ TAG="$TAG_NAME"
133+ echo "IS_MANUAL=false" >> $GITHUB_OUTPUT
106134 fi
107135
108136 echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
109137 echo "Version: $VERSION"
138+ echo "Tag: $TAG"
110139
111140 - name : Verify CLI package.json version matches tag
112141 working-directory : packages/opennextjs-cli
@@ -130,111 +159,136 @@ jobs:
130159 fi
131160 echo "✅ MCP version match: $PACKAGE_VERSION"
132161
133- - name : Check if git-cliff is installed
134- id : git-cliff-check
162+ - name : Setup git-cliff
163+ uses : kenji-miyake/setup-git-cliff@v1
164+ with :
165+ version : latest
166+
167+ - name : Check if tag exists (for manual trigger)
168+ if : steps.version.outputs.IS_MANUAL == 'true'
169+ id : tag_check
135170 run : |
136- if command -v git-cliff &> /dev/null; then
137- echo "installed=true" >> $GITHUB_OUTPUT
171+ TAG="${{ steps.version.outputs.TAG }}"
172+ if git rev-parse "$TAG" >/dev/null 2>&1; then
173+ echo "EXISTS=true" >> $GITHUB_OUTPUT
174+ echo "⚠️ Tag $TAG already exists - will use existing tag"
138175 else
139- echo "installed=false" >> $GITHUB_OUTPUT
176+ echo "EXISTS=false" >> $GITHUB_OUTPUT
177+ echo "✅ Tag $TAG does not exist - will create it and generate changelogs first"
140178 fi
141179
142- - name : Install git-cliff (if needed)
143- if : steps.git-cliff-check.outputs.installed == 'false'
180+ - name : Generate changelogs and create tag (manual trigger, tag doesn't exist)
181+ if : steps.version.outputs.IS_MANUAL == 'true' && steps.tag_check.outputs.EXISTS == 'false'
182+ env :
183+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
144184 run : |
145- # Install git-cliff on Ubuntu
146- sudo apt-get update && sudo apt-get install -y git-cliff || \
147- echo "⚠️ git-cliff installation failed, will skip changelog generation" >&2
185+ set -e
186+
187+ TAG="${{ steps.version.outputs.TAG }}"
188+
189+ echo "📝 Generating CLI changelog..."
190+ pnpm changelog:package opennextjs-cli --tag "$TAG" || {
191+ echo "⚠️ CLI changelog generation failed" >&2
192+ exit 1
193+ }
194+
195+ echo "📝 Generating MCP changelog..."
196+ pnpm changelog:package opennextjs-mcp --tag "$TAG" || {
197+ echo "⚠️ MCP changelog generation failed" >&2
198+ exit 1
199+ }
200+
201+ echo "✅ Changelogs generated successfully"
202+
203+ # Commit changelogs
204+ git config user.name "github-actions[bot]"
205+ git config user.email "github-actions[bot]@users.noreply.github.com"
206+
207+ git add packages/opennextjs-cli/CHANGELOG.md packages/opennextjs-mcp/CHANGELOG.md
208+
209+ if git diff --staged --quiet; then
210+ echo "No changelog changes to commit"
211+ else
212+ git commit -m "chore: update changelogs for $TAG release"
213+ git push origin main
214+ echo "✅ Changelogs committed and pushed"
215+ fi
216+
217+ # Create and push tag (this will trigger this workflow again with tag push event)
218+ git tag -a "$TAG" -m "Release $TAG"
219+ git push origin "$TAG"
220+ echo "✅ Tag $TAG created and pushed"
221+ echo "ℹ️ This workflow will run again automatically when the tag is pushed"
148222
149- - name : Generate package-specific changelog sections
223+ - name : Generate package-specific changelogs (when tag already exists)
224+ if : |
225+ (steps.version.outputs.IS_MANUAL == 'true' && steps.tag_check.outputs.EXISTS == 'true') ||
226+ steps.version.outputs.IS_MANUAL == 'false'
150227 env :
151228 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
152229 run : |
153230 set -e
154231
155- TAG_VERSION="${{ steps.version.outputs.VERSION }}"
156- TAG="v$TAG_VERSION"
232+ TAG="${{ steps.version.outputs.TAG }}"
157233
158- # Generate CLI changelog section (only commits affecting packages/opennextjs-cli/**)
159- echo "📝 Generating CLI changelog section..."
160- git-cliff \
161- --config cliff.toml \
162- --include-path "packages/opennextjs-cli/**" \
163- --tag "$TAG" \
164- --latest \
165- --unreleased \
166- --output /tmp/cli-changelog.md \
167- --verbose || \
234+ # Generate CLI changelog (writes directly to packages/opennextjs-cli/CHANGELOG.md)
235+ echo "📝 Generating CLI changelog..."
236+ pnpm changelog:package opennextjs-cli --tag "$TAG" || \
168237 echo "⚠️ CLI changelog generation failed" >&2
169238
170- # Generate MCP changelog section (only commits affecting packages/opennextjs-mcp/**)
171- echo "📝 Generating MCP changelog section..."
172- git-cliff \
173- --config cliff.toml \
174- --include-path "packages/opennextjs-mcp/**" \
175- --tag "$TAG" \
176- --latest \
177- --unreleased \
178- --output /tmp/mcp-changelog.md \
179- --verbose || \
239+ # Generate MCP changelog (writes directly to packages/opennextjs-mcp/CHANGELOG.md)
240+ echo "📝 Generating MCP changelog..."
241+ pnpm changelog:package opennextjs-mcp --tag "$TAG" || \
180242 echo "⚠️ MCP changelog generation failed" >&2
181243
182- # Combine changelog sections
183- echo "📝 Combining changelog sections..."
244+ # Extract changelog sections for GitHub Release notes
245+ # Read from package-specific CHANGELOG.md files
246+ echo "📝 Extracting changelog sections for release notes..."
184247
185248 # Start with version header
186249 echo "## [$TAG_VERSION] - $(date +%Y-%m-%d)" > /tmp/changelog-section.md
187250 echo "" >> /tmp/changelog-section.md
188251
189- # Extract CLI section (skip header, get body)
190- if [ -f /tmp/cli-changelog.md ] && [ -s /tmp/cli-changelog.md ]; then
191- echo "### @jsonbored/opennextjs-cli" >> /tmp/changelog-section.md
192- echo "" >> /tmp/changelog-section.md
193- # Skip the header and version line, get the body
194- tail -n +2 /tmp/cli-changelog.md | sed '/^## \[/,$d' >> /tmp/changelog-section.md || true
195- echo "" >> /tmp/changelog-section.md
252+ # Extract CLI section from packages/opennextjs-cli/CHANGELOG.md
253+ if [ -f "packages/opennextjs-cli/CHANGELOG.md" ]; then
254+ # Find the version section in CLI changelog
255+ CLI_SECTION=$(awk "/^## \[$TAG_VERSION\]/,/^## \[|^<!-- generated/" "packages/opennextjs-cli/CHANGELOG.md" | head -n -1 || true)
256+ if [ -n "$CLI_SECTION" ]; then
257+ echo "### @jsonbored/opennextjs-cli" >> /tmp/changelog-section.md
258+ echo "" >> /tmp/changelog-section.md
259+ # Remove the version header line, keep the rest
260+ echo "$CLI_SECTION" | sed '/^## \[/d' >> /tmp/changelog-section.md || true
261+ echo "" >> /tmp/changelog-section.md
262+ fi
196263 fi
197264
198- # Extract MCP section (skip header, get body)
199- if [ -f /tmp/mcp-changelog.md ] && [ -s /tmp/mcp-changelog.md ]; then
200- echo "### @jsonbored/opennextjs-mcp" >> /tmp/changelog-section.md
201- echo "" >> /tmp/changelog-section.md
202- # Skip the header and version line, get the body
203- tail -n +2 /tmp/mcp-changelog.md | sed '/^## \[/,$d' >> /tmp/changelog-section.md || true
204- echo "" >> /tmp/changelog-section.md
265+ # Extract MCP section from packages/opennextjs-mcp/CHANGELOG.md
266+ if [ -f "packages/opennextjs-mcp/CHANGELOG.md" ]; then
267+ # Find the version section in MCP changelog
268+ MCP_SECTION=$(awk "/^## \[$TAG_VERSION\]/,/^## \[|^<!-- generated/" "packages/opennextjs-mcp/CHANGELOG.md" | head -n -1 || true)
269+ if [ -n "$MCP_SECTION" ]; then
270+ echo "### @jsonbored/opennextjs-mcp" >> /tmp/changelog-section.md
271+ echo "" >> /tmp/changelog-section.md
272+ # Remove the version header line, keep the rest
273+ echo "$MCP_SECTION" | sed '/^## \[/d' >> /tmp/changelog-section.md || true
274+ echo "" >> /tmp/changelog-section.md
275+ fi
205276 fi
206277
207278 # If no package-specific sections, create a generic one
208- if [ ! -s /tmp/cli- changelog.md ] && [ ! -s /tmp/mcp- changelog.md ]; then
279+ if [ ! -s /tmp/changelog-section .md ] || [ "$(wc -l < /tmp/changelog-section .md)" -lt 5 ]; then
209280 echo "Initial release of OpenNext.js CLI and MCP server packages." >> /tmp/changelog-section.md
210281 echo "" >> /tmp/changelog-section.md
211282 fi
212283
213- # Update main CHANGELOG.md (prepend new section)
214- if [ -f CHANGELOG.md ]; then
215- # Prepend new section to existing changelog
216- cat /tmp/changelog-section.md CHANGELOG.md > /tmp/combined-changelog.md
217- mv /tmp/combined-changelog.md CHANGELOG.md
218- else
219- # Create new changelog with header
220- cat > CHANGELOG.md << 'EOF'
221- # Changelog
222-
223- All notable changes to this project will be documented in this file.
224-
225- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
226- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
227-
228- EOF
229- cat /tmp/changelog-section.md >> CHANGELOG.md
230- fi
231-
232284 # Set changelog section for GitHub release
233285 echo "CHANGELOG_SECTION<<EOF" >> $GITHUB_ENV
234286 cat /tmp/changelog-section.md >> $GITHUB_ENV
235287 echo "EOF" >> $GITHUB_ENV
236288
237- echo "✅ Changelog generated successfully"
289+ echo "✅ Changelogs generated successfully"
290+ echo " - packages/opennextjs-cli/CHANGELOG.md"
291+ echo " - packages/opennextjs-mcp/CHANGELOG.md"
238292
239293 - name : Publish CLI to npm (try OIDC first)
240294 id : publish-cli-oidc
0 commit comments