Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions .github/workflows/npm-publish.yml

This file was deleted.

123 changes: 26 additions & 97 deletions .github/workflows/release-on-merge.yml
Original file line number Diff line number Diff line change
@@ -1,107 +1,32 @@
# Auto-release when a PR with version bump is merged to main
# Creates GitHub Release with changelog and publishes to npm
# Semantic Release: Auto-version and publish on merge to main
# Analyzes conventional commits to determine version bump:
# feat: → minor (0.x.0)
# fix:/perf:/refactor: → patch (0.0.x)
# BREAKING CHANGE: → major (x.0.0)

name: Release on PR Merge
name: Release

on:
pull_request:
types: [closed]
push:
branches: [main]

jobs:
check-version:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
outputs:
version_changed: ${{ steps.version-check.outputs.changed }}
new_version: ${{ steps.version-check.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Check if version changed
id: version-check
run: |
# Get version from current commit
NEW_VERSION=$(node -p "require('./package.json').version")

# Get version from previous commit
git checkout HEAD~1 -- package.json 2>/dev/null || true
OLD_VERSION=$(node -p "require('./package.json').version" 2>/dev/null || echo "0.0.0")

# Restore current package.json
git checkout HEAD -- package.json

echo "Old version: $OLD_VERSION"
echo "New version: $NEW_VERSION"

if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
echo "Version changed from $OLD_VERSION to $NEW_VERSION"
echo "changed=true" >> $GITHUB_OUTPUT
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
else
echo "Version unchanged"
echo "changed=false" >> $GITHUB_OUTPUT
fi

release:
needs: check-version
if: needs.check-version.outputs.version_changed == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history needed for changelog and tags

- name: Generate changelog
id: changelog
run: |
# Get commits since last tag
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")

if [ -n "$LAST_TAG" ]; then
echo "Generating changelog since $LAST_TAG"
CHANGELOG=$(git log ${LAST_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges | head -50)
else
echo "No previous tag found, using recent commits"
CHANGELOG=$(git log -20 --pretty=format:"- %s (%h)" --no-merges)
fi

# Write to file for multi-line output
echo "$CHANGELOG" > changelog.txt

# Also create a summary
FEAT_COUNT=$(echo "$CHANGELOG" | grep -c "^- feat" || true)
FIX_COUNT=$(echo "$CHANGELOG" | grep -c "^- fix" || true)

echo "features=$FEAT_COUNT" >> $GITHUB_OUTPUT
echo "fixes=$FIX_COUNT" >> $GITHUB_OUTPUT

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.check-version.outputs.new_version }}
name: v${{ needs.check-version.outputs.new_version }}
body_path: changelog.txt
generate_release_notes: true
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

publish-npm:
needs: [check-version, release]
if: needs.check-version.outputs.version_changed == 'true'
runs-on: ubuntu-latest
contents: write # Push commits, create releases
issues: write # Comment on issues
pull-requests: write # Comment on PRs
id-token: write # npm provenance
steps:
- uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history needed for GitClient tests
fetch-depth: 0
persist-credentials: false

- uses: actions/setup-node@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org/
Expand All @@ -115,15 +40,19 @@ jobs:
- name: Run tests
run: npm test

- name: Publish to npm
run: npm publish --access public
- name: Semantic Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.npm_token }}
NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
run: npx semantic-release

- name: Summary
if: success()
run: |
echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
echo "## Release Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Semantic release analyzed commits and published if changes warranted a release." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Version:** v${{ needs.check-version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY
echo "- **npm:** https://www.npmjs.com/package/git-mem" >> $GITHUB_STEP_SUMMARY
echo "- **GitHub Release:** https://github.com/${{ github.repository }}/releases/tag/v${{ needs.check-version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Releases:** https://github.com/${{ github.repository }}/releases" >> $GITHUB_STEP_SUMMARY
43 changes: 43 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"branches": ["main"],
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "conventionalcommits",
"releaseRules": [
{ "type": "feat", "release": "minor" },
{ "type": "fix", "release": "patch" },
{ "type": "perf", "release": "patch" },
{ "type": "refactor", "release": "patch" },
{ "type": "docs", "release": false },
{ "type": "style", "release": false },
{ "type": "chore", "release": false },
{ "type": "test", "release": false },
{ "type": "ci", "release": false }
]
}],
["@semantic-release/release-notes-generator", {
"preset": "conventionalcommits",
"presetConfig": {
"types": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance" },
{ "type": "refactor", "section": "Refactoring" },
{ "type": "docs", "section": "Documentation", "hidden": true },
{ "type": "chore", "section": "Maintenance", "hidden": true },
{ "type": "test", "section": "Tests", "hidden": true }
]
}
}],
["@semantic-release/changelog", {
"changelogFile": "CHANGELOG.md",
"changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)."
}],
"@semantic-release/npm",
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding explicit npm publish configuration to ensure public access. While unscoped packages default to public access, it's safer to be explicit. You can either:

  1. Add to package.json: "publishConfig": { "access": "public" }
  2. Or configure the semantic-release npm plugin in .releaserc.json: ["@semantic-release/npm", { "npmPublish": true, "pkgRoot": "." }]

Option 1 is generally preferred as it's more visible and matches the previous workflow's --access public flag.

Suggested change
"@semantic-release/npm",
["@semantic-release/npm", { "npmPublish": true, "pkgRoot": "." }],

Copilot uses AI. Check for mistakes.
"@semantic-release/github",
["@semantic-release/git", {
"assets": ["CHANGELOG.md", "package.json", "package-lock.json"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}]
]
}
Loading