From 4f3371ce2c67aa11d8a95de3f3c36ea2904edb33 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 13 Feb 2026 14:07:39 +0900 Subject: [PATCH] fix(publish): use generate-changelog.ts for contributor thanks - Replace inline bash changelog with script/generate-changelog.ts - Update /publish command with layered release notes structure - Add preview step and clear enhanced summary guidelines --- .github/workflows/publish.yml | 123 +++--------------- .opencode/command/publish.md | 229 ++++++++++++++++++++++------------ 2 files changed, 160 insertions(+), 192 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6128da27e..558eefe37 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -223,118 +223,23 @@ jobs: with: fetch-depth: 0 + - run: git fetch --force --tags + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + env: + BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi" + - name: Generate changelog - id: changelog run: | - VERSION="${{ needs.publish-main.outputs.version }}" - - PREV_TAG="" - if [[ "$VERSION" == *"-beta."* ]]; then - BASE="${VERSION%-beta.*}" - NUM="${VERSION##*-beta.}" - PREV_NUM=$((NUM - 1)) - if [ $PREV_NUM -ge 1 ]; then - PREV_TAG="${BASE}-beta.${PREV_NUM}" - git rev-parse "v${PREV_TAG}" >/dev/null 2>&1 || PREV_TAG="" - fi - fi - - if [ -z "$PREV_TAG" ]; then - PREV_TAG=$(curl -s https://registry.npmjs.org/oh-my-opencode/latest | jq -r '.version // "0.0.0"') - fi - - echo "Comparing v${PREV_TAG}..v${VERSION}" - - # Get all commits between tags - COMMITS=$(git log "v${PREV_TAG}..v${VERSION}" --format="%s" 2>/dev/null || echo "") - - # Initialize sections - FEATURES="" - FIXES="" - REFACTOR="" - DOCS="" - OTHER="" - - # Store regexes in variables for bash 5.2+ compatibility - # (bash 5.2 changed how parentheses are parsed inside [[ =~ ]]) - re_skip='^(chore|ci|release|test|ignore)' - re_feat_scoped='^feat\(([^)]+)\): (.+)$' - re_fix_scoped='^fix\(([^)]+)\): (.+)$' - re_refactor_scoped='^refactor\(([^)]+)\): (.+)$' - re_docs_scoped='^docs\(([^)]+)\): (.+)$' - - while IFS= read -r commit; do - [ -z "$commit" ] && continue - # Skip chore, ci, release, test commits - [[ "$commit" =~ $re_skip ]] && continue - - if [[ "$commit" =~ ^feat ]]; then - # Extract scope and message: feat(scope): message -> **scope**: message - if [[ "$commit" =~ $re_feat_scoped ]]; then - FEATURES="${FEATURES}\n- **${BASH_REMATCH[1]}**: ${BASH_REMATCH[2]}" - else - MSG="${commit#feat: }" - FEATURES="${FEATURES}\n- ${MSG}" - fi - elif [[ "$commit" =~ ^fix ]]; then - if [[ "$commit" =~ $re_fix_scoped ]]; then - FIXES="${FIXES}\n- **${BASH_REMATCH[1]}**: ${BASH_REMATCH[2]}" - else - MSG="${commit#fix: }" - FIXES="${FIXES}\n- ${MSG}" - fi - elif [[ "$commit" =~ ^refactor ]]; then - if [[ "$commit" =~ $re_refactor_scoped ]]; then - REFACTOR="${REFACTOR}\n- **${BASH_REMATCH[1]}**: ${BASH_REMATCH[2]}" - else - MSG="${commit#refactor: }" - REFACTOR="${REFACTOR}\n- ${MSG}" - fi - elif [[ "$commit" =~ ^docs ]]; then - if [[ "$commit" =~ $re_docs_scoped ]]; then - DOCS="${DOCS}\n- **${BASH_REMATCH[1]}**: ${BASH_REMATCH[2]}" - else - MSG="${commit#docs: }" - DOCS="${DOCS}\n- ${MSG}" - fi - else - OTHER="${OTHER}\n- ${commit}" - fi - done <<< "$COMMITS" - - # Build release notes - { - echo "## What's Changed" - echo "" - if [ -n "$FEATURES" ]; then - echo "### Features" - echo -e "$FEATURES" - echo "" - fi - if [ -n "$FIXES" ]; then - echo "### Bug Fixes" - echo -e "$FIXES" - echo "" - fi - if [ -n "$REFACTOR" ]; then - echo "### Refactoring" - echo -e "$REFACTOR" - echo "" - fi - if [ -n "$DOCS" ]; then - echo "### Documentation" - echo -e "$DOCS" - echo "" - fi - if [ -n "$OTHER" ]; then - echo "### Other Changes" - echo -e "$OTHER" - echo "" - fi - echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/v${PREV_TAG}...v${VERSION}" - } > /tmp/changelog.md - + bun run script/generate-changelog.ts > /tmp/changelog.md cat /tmp/changelog.md + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create GitHub release run: | diff --git a/.opencode/command/publish.md b/.opencode/command/publish.md index 945ec539c..718bf246c 100644 --- a/.opencode/command/publish.md +++ b/.opencode/command/publish.md @@ -31,9 +31,9 @@ You are the release manager for oh-my-opencode. Execute the FULL publish workflo { "id": "sync-remote", "content": "Sync with remote (pull --rebase && push if unpushed commits)", "status": "pending", "priority": "high" }, { "id": "run-workflow", "content": "Trigger GitHub Actions publish workflow", "status": "pending", "priority": "high" }, { "id": "wait-workflow", "content": "Wait for workflow completion (poll every 30s)", "status": "pending", "priority": "high" }, - { "id": "verify-release", "content": "Verify GitHub release was created", "status": "pending", "priority": "high" }, - { "id": "draft-release-notes", "content": "Draft enhanced release notes content", "status": "pending", "priority": "high" }, - { "id": "update-release-notes", "content": "Update GitHub release with enhanced notes", "status": "pending", "priority": "high" }, + { "id": "verify-and-preview", "content": "Verify release created + preview auto-generated changelog & contributor thanks", "status": "pending", "priority": "high" }, + { "id": "draft-summary", "content": "Draft enhanced release summary (minor/major only, skip for patch)", "status": "pending", "priority": "high" }, + { "id": "apply-summary", "content": "Prepend enhanced summary to release (minor/major only)", "status": "pending", "priority": "high" }, { "id": "verify-npm", "content": "Verify npm package published successfully", "status": "pending", "priority": "high" }, { "id": "wait-platform-workflow", "content": "Wait for publish-platform workflow completion", "status": "pending", "priority": "high" }, { "id": "verify-platform-binaries", "content": "Verify all 7 platform binary packages published", "status": "pending", "priority": "high" }, @@ -111,102 +111,165 @@ gh run view {run_id} --log-failed --- -## STEP 5: VERIFY GITHUB RELEASE +## STEP 5: VERIFY RELEASE & PREVIEW AUTO-GENERATED CONTENT + +Two goals: confirm the release exists, then show the user what the workflow already generated. -Get the new version and verify release exists: ```bash -# Get new version from package.json (workflow updates it) +# Pull latest (workflow committed version bump) git pull --rebase NEW_VERSION=$(node -p "require('./package.json').version") -gh release view "v${NEW_VERSION}" + +# Verify release exists on GitHub +gh release view "v${NEW_VERSION}" --json tagName,url --jq '{tag: .tagName, url: .url}' ``` ---- - -## STEP 6: DRAFT ENHANCED RELEASE NOTES - -Analyze commits since the previous version and draft release notes following project conventions: - -### For PATCH releases: -Keep simple format - just list commits: -```markdown -- {hash} {conventional commit message} -- ... -``` - -### For MINOR releases: -Use feature-focused format: -```markdown -## New Features - -### Feature Name -- Description of what it does -- Why it matters - -## Bug Fixes -- fix(scope): description - -## Improvements -- refactor(scope): description -``` - -### For MAJOR releases: -Full changelog format: -```markdown -# v{version} - -Brief description of the release. - -## What's New Since v{previous} - -### Breaking Changes -- Description of breaking change - -### Features -- **Feature Name**: Description - -### Bug Fixes -- Description - -### Documentation -- Description - -## Migration Guide (if applicable) -... -``` - -**CRITICAL: The enhanced notes must ADD to existing workflow-generated notes, not replace them.** - ---- - -## STEP 7: UPDATE GITHUB RELEASE - -**ZERO CONTENT LOSS POLICY:** -- First, fetch the existing release body with `gh release view` -- Your enhanced notes must be PREPENDED to the existing content -- **NOT A SINGLE CHARACTER of existing content may be removed or modified** -- The final release body = `{your_enhanced_notes}\n\n---\n\n{existing_body_exactly_as_is}` +**After verifying, generate a local preview of the auto-generated content:** ```bash -# Get existing body -EXISTING_BODY=$(gh release view "v${NEW_VERSION}" --json body --jq '.body') +bun run script/generate-changelog.ts +``` -# Write enhanced notes to temp file (prepend to existing) -cat > /tmp/release-notes-v${NEW_VERSION}.md << 'EOF' -{your_enhanced_notes} + +After running the preview, present the output to the user and say: + +> **The following content is ALREADY included in the release automatically:** +> - Commit changelog (grouped by feat/fix/refactor) +> - Contributor thank-you messages (for non-team contributors) +> +> You do NOT need to write any of this. It's handled. +> +> **For a patch release**, this is sufficient — no additional notes needed. +> **For a minor/major release**, I'll draft a human-readable summary to prepend above this content. + +Wait for the user to acknowledge before proceeding. + --- -EOF +## STEP 6: DRAFT ENHANCED RELEASE SUMMARY -# Append existing body EXACTLY as-is (zero modifications) -echo "$EXISTING_BODY" >> /tmp/release-notes-v${NEW_VERSION}.md + -# Update release -gh release edit "v${NEW_VERSION}" --notes-file /tmp/release-notes-v${NEW_VERSION}.md +| Release Type | Action | +|-------------|--------| +| **patch** | SKIP this step entirely. The auto-generated changelog from Step 5 is sufficient. Proceed to Step 8. | +| **minor** | Draft a concise feature summary. | +| **major** | Draft a full release narrative with migration notes if applicable. | + + + +### What You're Writing (and What You're NOT) + +You are writing the **headline layer** — a product announcement that sits ABOVE the auto-generated commit log. Think "release blog post", not "git log". + + +- NEVER duplicate commit messages. The auto-generated section already lists every commit. +- NEVER write generic filler like "Various bug fixes and improvements" or "Several enhancements". +- ALWAYS focus on USER IMPACT: what can users DO now that they couldn't before? +- ALWAYS group by THEME or CAPABILITY, not by commit type (feat/fix/refactor). +- ALWAYS use concrete language: "You can now do X" not "Added X feature". + + + + +## What's New +- feat(auth): add JWT refresh token rotation +- fix(auth): handle expired token edge case +- refactor(auth): extract middleware + + + +## 🔐 Smarter Authentication + +Token refresh is now automatic and seamless. Sessions no longer expire mid-task — the system silently rotates credentials in the background. If you've been frustrated by random logouts, this release fixes that. + + + +## Improvements +- Various performance improvements +- Bug fixes and stability enhancements + + + +## ⚡ 3x Faster Rule Parsing + +Rules are now cached by file modification time. If your project has 50+ rule files, you'll notice startup is noticeably faster — we measured a 3x improvement in our test suite. + + + +### Drafting Process + +1. **Analyze** the commit list from Step 5's preview. Identify 2-5 themes that matter to users. +2. **Write** the summary to `/tmp/release-summary-v${NEW_VERSION}.md`. +3. **Present** the draft to the user for review and approval before applying. + +```bash +# Write your draft here +cat > /tmp/release-summary-v${NEW_VERSION}.md << 'SUMMARY_EOF' +{your_enhanced_summary} +SUMMARY_EOF + +cat /tmp/release-summary-v${NEW_VERSION}.md ``` -**CRITICAL: This is ADDITIVE ONLY. You are adding your notes on top. The existing content remains 100% intact.** + +After drafting, ask the user: +> "Here's the release summary I drafted. This will appear AT THE TOP of the release notes, above the auto-generated commit changelog and contributor thanks. Want me to adjust anything before applying?" + +Do NOT proceed to Step 7 without user confirmation. + + +--- + +## STEP 7: APPLY ENHANCED SUMMARY TO RELEASE + +**Skip this step if patch release** — proceed directly to Step 8. + + +The final release note structure: + +``` +┌─────────────────────────────────────┐ +│ Enhanced Summary (from Step 6) │ ← You wrote this +│ - Theme-based, user-impact focused │ +├─────────────────────────────────────┤ +│ --- (separator) │ +├─────────────────────────────────────┤ +│ Auto-generated Commit Changelog │ ← Workflow wrote this +│ - feat/fix/refactor grouped │ +│ - Contributor thank-you messages │ +└─────────────────────────────────────┘ +``` + + + +- Fetch the existing release body FIRST +- PREPEND your summary above it +- The existing auto-generated content must remain 100% INTACT +- NOT A SINGLE CHARACTER of existing content may be removed or modified + + +```bash +# 1. Fetch existing auto-generated body +EXISTING_BODY=$(gh release view "v${NEW_VERSION}" --json body --jq '.body') + +# 2. Combine: enhanced summary on top, auto-generated below +{ + cat /tmp/release-summary-v${NEW_VERSION}.md + echo "" + echo "---" + echo "" + echo "$EXISTING_BODY" +} > /tmp/final-release-v${NEW_VERSION}.md + +# 3. Update the release (additive only) +gh release edit "v${NEW_VERSION}" --notes-file /tmp/final-release-v${NEW_VERSION}.md + +# 4. Confirm +echo "✅ Release v${NEW_VERSION} updated with enhanced summary." +gh release view "v${NEW_VERSION}" --json url --jq '.url' +``` ---