Skip to content

fix(ci): release trigger regex not matching conventional commit bang … #45

fix(ci): release trigger regex not matching conventional commit bang …

fix(ci): release trigger regex not matching conventional commit bang … #45

Workflow file for this run

name: Release
on:
push:
branches: [main]
workflow_dispatch:
inputs:
release-type:
description: "Type of release"
required: true
default: "auto"
type: choice
options:
- auto
- patch
- minor
- major
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
# Pre-release validation
validate:
name: Pre-release Validation
runs-on: ubuntu-latest
timeout-minutes: 20
outputs:
should-release: ${{ steps.check-changes.outputs.should-release }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Check for release trigger
id: check-changes
run: |
# Always release on manual trigger
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "should-release=true" >> $GITHUB_OUTPUT
echo "✅ Manual release triggered"
else
# For push events, check if there are releasable changes
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$last_tag" ]; then
commits=$(git log $last_tag..HEAD --pretty=format:"%s")
else
commits=$(git log --pretty=format:"%s")
fi
# Check for releasable commits (skip version bump commits and minor changes)
releasable_commits=$(echo "$commits" | grep -v "chore: bump version\|\\[skip ci\\]\|^docs:\|^style:\|^test:" || true)
# Only release if there are significant changes (fixes, features, refactors, etc.)
significant_commits=$(echo "$releasable_commits" | grep -E "^(feat|fix|refactor|perf|chore)(\([^)]+\))?!?:" || true)
if [ -n "$significant_commits" ]; then
echo "should-release=true" >> $GITHUB_OUTPUT
echo "✅ Found significant changes since last release"
echo "📝 Significant changes:"
echo "$significant_commits"
else
echo "should-release=false" >> $GITHUB_OUTPUT
echo "ℹ️ No significant changes found - skipping release"
if [ -n "$releasable_commits" ]; then
echo "📝 Non-significant changes found:"
echo "$releasable_commits"
fi
fi
fi
- name: Build packages
run: npm run build
- name: Run tests
run: npm test
timeout-minutes: 10
- name: Verify package can be packed
run: npm pack --dry-run
# Release job - only runs if validation passes and changes detected
release:
name: Release
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 20
if: needs.validate.outputs.should-release == 'true'
permissions:
contents: write
pull-requests: write
id-token: write
packages: write
actions: write
outputs:
published: ${{ steps.publish.outputs.published }}
version: ${{ steps.get-version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
registry-url: "https://registry.npmjs.org"
- name: Install dependencies
run: npm ci
- name: Build package
run: npm run build
- name: Determine version bump type
id: version-bump
run: |
# Get commits since last tag (or all commits if no tags)
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$last_tag" ]; then
commits=$(git log $last_tag..HEAD --pretty=format:"%s")
echo "📝 Commits since $last_tag:"
else
commits=$(git log --pretty=format:"%s")
echo "📝 All commits (no previous tags):"
fi
echo "$commits"
# Determine bump type based on conventional commits (more conservative)
bump_type="patch" # Default to patch for most changes
if echo "$commits" | grep -q "BREAKING CHANGE\|!:"; then
bump_type="major"
echo "🔥 Found breaking changes → major bump"
elif echo "$commits" | grep -qE "^feat(\([^)]+\))?!:|^feat(\([^)]+\))?: .*(BREAKING|breaking)"; then
bump_type="major"
echo "🔥 Found breaking feature → major bump"
elif echo "$commits" | grep -qE "^feat(\([^)]+\))?: .*\b(new|add|introduce)\b.*\b(API|api|method|function|interface|endpoint)\b"; then
bump_type="minor"
echo "✨ Found new API features → minor bump"
elif echo "$commits" | grep -q "^fix\|^chore\|^docs\|^style\|^refactor\|^perf\|^test\|^feat"; then
bump_type="patch"
echo "🐛 Found fixes/improvements/features → patch bump (conservative)"
else
bump_type="patch"
echo "📦 No conventional commits found → patch bump"
fi
# Override with manual input if provided
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ github.event.inputs.release-type }}" != "auto" ]; then
bump_type="${{ github.event.inputs.release-type }}"
echo "🔧 Manual override: using $bump_type"
fi
echo "bump-type=$bump_type" >> $GITHUB_OUTPUT
echo "📈 Final bump type: $bump_type"
- name: Bump version automatically
id: bump-version
run: |
# Configure git
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Get current version
current_version=$(node -p "require('./package.json').version")
echo "📦 Current version: $current_version"
# Bump version
bump_type="${{ steps.version-bump.outputs.bump-type }}"
npm version $bump_type --no-git-tag-version
# Get new version
new_version=$(node -p "require('./package.json').version")
echo "📦 New version: $new_version"
echo "new-version=$new_version" >> $GITHUB_OUTPUT
# Commit version change
git add package.json package-lock.json
git commit -m "chore: bump version to $new_version [skip ci]"
git push origin main
echo "✅ Version bumped from $current_version to $new_version"
- name: Update CHANGELOG.md
run: |
version="${{ steps.bump-version.outputs.new-version }}"
# Get commits since last tag for changelog
last_tag=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
if [ -n "$last_tag" ]; then
commits=$(git log $last_tag..HEAD~1 --pretty=format:"%s (%h)" --no-merges)
else
commits=$(git log HEAD~1 --pretty=format:"%s (%h)" --no-merges)
fi
# Generate changelog entry
changelog_entry="## [$version](https://github.com/btwld/docling-sdk/compare/$last_tag...v$version) ($(date +%Y-%m-%d))"
# Categorize commits for changelog
features=""
fixes=""
chores=""
others=""
echo "$commits" | while IFS= read -r commit; do
[ -z "$commit" ] && continue
if echo "$commit" | grep -qE "^feat(\([^)]+\))?:"; then
echo "- $commit" >> /tmp/cl_features.txt
elif echo "$commit" | grep -qE "^fix(\([^)]+\))?:"; then
echo "- $commit" >> /tmp/cl_fixes.txt
elif echo "$commit" | grep -qE "^(chore|docs|style|refactor|perf|test)(\([^)]+\))?:"; then
echo "- $commit" >> /tmp/cl_chores.txt
else
echo "- $commit" >> /tmp/cl_others.txt
fi
done
# Build changelog entry
echo "$changelog_entry" > /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
if [ -f /tmp/cl_features.txt ]; then
echo "### ✨ Features" >> /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
cat /tmp/cl_features.txt >> /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
fi
if [ -f /tmp/cl_fixes.txt ]; then
echo "### 🐛 Bug Fixes" >> /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
cat /tmp/cl_fixes.txt >> /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
fi
if [ -f /tmp/cl_chores.txt ]; then
echo "### 🔧 Maintenance" >> /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
cat /tmp/cl_chores.txt >> /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
fi
if [ -f /tmp/cl_others.txt ]; then
echo "### 📦 Other Changes" >> /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
cat /tmp/cl_others.txt >> /tmp/new_changelog.md
echo "" >> /tmp/new_changelog.md
fi
# Insert new entry at the top of CHANGELOG.md (after header)
head -n 4 CHANGELOG.md > /tmp/changelog_header.md
echo "" >> /tmp/changelog_header.md
cat /tmp/new_changelog.md >> /tmp/changelog_header.md
tail -n +5 CHANGELOG.md >> /tmp/changelog_header.md
mv /tmp/changelog_header.md CHANGELOG.md
# Clean up
rm -f /tmp/cl_*.txt /tmp/new_changelog.md
# Commit changelog update
git add CHANGELOG.md
git commit -m "chore: update CHANGELOG.md for v$version [skip ci]"
git push origin main
echo "✅ Updated CHANGELOG.md for version $version"
- name: Get current version
id: get-version
run: |
version="${{ steps.bump-version.outputs.new-version }}"
echo "version=$version" >> $GITHUB_OUTPUT
echo "📦 Using version: $version"
- name: Create git tag
run: |
version="${{ steps.get-version.outputs.version }}"
tag_name="v$version"
# Check if tag already exists
if git tag -l | grep -q "^${tag_name}$"; then
echo "ℹ️ Tag $tag_name already exists, skipping tag creation"
else
git tag "$tag_name"
git push origin "$tag_name"
echo "✅ Created and pushed tag $tag_name"
fi
- name: Publish to npm
id: publish
run: |
# Check if this version is already published
if npm view docling-sdk@${{ steps.get-version.outputs.version }} version >/dev/null 2>&1; then
echo "ℹ️ Version ${{ steps.get-version.outputs.version }} already published to npm"
echo "published=false" >> $GITHUB_OUTPUT
else
npm publish
echo "✅ Published docling-sdk@${{ steps.get-version.outputs.version }} to npm"
echo "published=true" >> $GITHUB_OUTPUT
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Generate Release Notes
id: release-notes
run: |
version="${{ steps.get-version.outputs.version }}"
# Get commits since last tag (excluding the version bump commit we just made)
last_tag=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
if [ -n "$last_tag" ]; then
commits=$(git log $last_tag..HEAD~1 --pretty=format:"%s (%h)" --no-merges)
echo "📝 Changes since $last_tag:"
else
commits=$(git log HEAD~1 --pretty=format:"%s (%h)" --no-merges)
echo "📝 All changes:"
fi
# Skip if no commits (shouldn't happen, but safety check)
if [ -z "$commits" ]; then
echo "## $version ($(date +%Y-%m-%d))" > release_notes.md
echo "release-notes-file=release_notes.md" >> $GITHUB_OUTPUT
echo "⚠️ No commits found for release notes"
exit 0
fi
# Categorize commits
features=""
fixes=""
chores=""
others=""
echo "$commits" | while IFS= read -r commit; do
# Skip empty lines
[ -z "$commit" ] && continue
if echo "$commit" | grep -qE "^feat(\([^)]+\))?:"; then
echo "FEATURE: $commit" >> /tmp/features.txt
elif echo "$commit" | grep -qE "^fix(\([^)]+\))?:"; then
echo "FIX: $commit" >> /tmp/fixes.txt
elif echo "$commit" | grep -qE "^(chore|docs|style|refactor|perf|test)(\([^)]+\))?:"; then
echo "CHORE: $commit" >> /tmp/chores.txt
else
echo "OTHER: $commit" >> /tmp/others.txt
fi
done
# Read categorized commits
features=$(cat /tmp/features.txt 2>/dev/null | sed 's/^FEATURE: /- /' || echo "")
fixes=$(cat /tmp/fixes.txt 2>/dev/null | sed 's/^FIX: /- /' || echo "")
chores=$(cat /tmp/chores.txt 2>/dev/null | sed 's/^CHORE: /- /' || echo "")
others=$(cat /tmp/others.txt 2>/dev/null | sed 's/^OTHER: /- /' || echo "")
# Build release notes
echo "## $version ($(date +%Y-%m-%d))" > release_notes.md
if [ -n "$features" ]; then
echo "" >> release_notes.md
echo "### ✨ Features" >> release_notes.md
echo "$features" >> release_notes.md
fi
if [ -n "$fixes" ]; then
echo "" >> release_notes.md
echo "### 🐛 Bug Fixes" >> release_notes.md
echo "$fixes" >> release_notes.md
fi
if [ -n "$chores" ]; then
echo "" >> release_notes.md
echo "### 🔧 Maintenance" >> release_notes.md
echo "$chores" >> release_notes.md
fi
if [ -n "$others" ]; then
echo "" >> release_notes.md
echo "### 📦 Other Changes" >> release_notes.md
echo "$others" >> release_notes.md
fi
# Clean up temp files
rm -f /tmp/features.txt /tmp/fixes.txt /tmp/chores.txt /tmp/others.txt
echo "release-notes-file=release_notes.md" >> $GITHUB_OUTPUT
echo "✅ Generated release notes:"
cat release_notes.md
- name: Create GitHub Release
if: steps.publish.outputs.published == 'true'
run: |
version="${{ steps.get-version.outputs.version }}"
tag_name="v$version"
# Create GitHub release with generated notes
gh release create "$tag_name" \
--title "Release $version" \
--notes-file "${{ steps.release-notes.outputs.release-notes-file }}" \
--latest
echo "✅ Created GitHub release for $tag_name"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Publish to GitHub Package Registry
github-packages:
name: GitHub Packages
needs: release
runs-on: ubuntu-latest
if: needs.release.outputs.published == 'true'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
registry-url: "https://npm.pkg.github.com"
scope: "@btwld"
- run: npm ci
- run: npm run build
# Create scoped package.json for GitHub Packages
- name: Setup GitHub Package
run: |
cp package.json package.json.backup
npm pkg set name="@btwld/docling-sdk"
npm pkg set publishConfig.registry="https://npm.pkg.github.com"
- name: Publish to GitHub Packages
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Restore original package.json
- name: Restore package.json
run: mv package.json.backup package.json
# Notify on successful release
notify:
name: Notify Success
needs: [release, github-packages]
runs-on: ubuntu-latest
if: needs.release.outputs.published == 'true'
steps:
- name: Notify Release
run: |
echo "🎉 Successfully released docling-sdk@${{ needs.release.outputs.version }}"
echo "📦 npm: https://www.npmjs.com/package/docling-sdk"
echo "📦 GitHub Packages: https://github.com/btwld/docling-sdk/packages"
echo "🏷️ GitHub Release: https://github.com/btwld/docling-sdk/releases/tag/v${{ needs.release.outputs.version }}"