- Fix GitHub Actions expression in shell script by using env variable - Prevents YAML parsing error on line 452 - Ensures workflow can execute properly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
513 lines
18 KiB
YAML
513 lines
18 KiB
YAML
name: Automated Release
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
paths:
|
||
- 'package.json'
|
||
- 'package.runtime.json'
|
||
|
||
permissions:
|
||
contents: write
|
||
packages: write
|
||
issues: write
|
||
pull-requests: write
|
||
|
||
# Prevent concurrent releases
|
||
concurrency:
|
||
group: release
|
||
cancel-in-progress: false
|
||
|
||
env:
|
||
REGISTRY: ghcr.io
|
||
IMAGE_NAME: ${{ github.repository }}
|
||
|
||
jobs:
|
||
detect-version-change:
|
||
name: Detect Version Change
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
version-changed: ${{ steps.check.outputs.changed }}
|
||
new-version: ${{ steps.check.outputs.version }}
|
||
previous-version: ${{ steps.check.outputs.previous-version }}
|
||
is-prerelease: ${{ steps.check.outputs.is-prerelease }}
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 2
|
||
|
||
- name: Check for version change
|
||
id: check
|
||
run: |
|
||
# Get current version from package.json
|
||
CURRENT_VERSION=$(node -e "console.log(require('./package.json').version)")
|
||
|
||
# Get previous version from git history safely
|
||
PREVIOUS_VERSION=$(git show HEAD~1:package.json 2>/dev/null | node -e "
|
||
try {
|
||
const data = require('fs').readFileSync(0, 'utf8');
|
||
const pkg = JSON.parse(data);
|
||
console.log(pkg.version || '0.0.0');
|
||
} catch (e) {
|
||
console.log('0.0.0');
|
||
}
|
||
" || echo "0.0.0")
|
||
|
||
echo "Previous version: $PREVIOUS_VERSION"
|
||
echo "Current version: $CURRENT_VERSION"
|
||
|
||
# Check if version changed
|
||
if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then
|
||
echo "changed=true" >> $GITHUB_OUTPUT
|
||
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||
echo "previous-version=$PREVIOUS_VERSION" >> $GITHUB_OUTPUT
|
||
|
||
# Check if it's a prerelease (contains alpha, beta, rc, dev)
|
||
if echo "$CURRENT_VERSION" | grep -E "(alpha|beta|rc|dev)" > /dev/null; then
|
||
echo "is-prerelease=true" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "is-prerelease=false" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
echo "🎉 Version changed from $PREVIOUS_VERSION to $CURRENT_VERSION"
|
||
else
|
||
echo "changed=false" >> $GITHUB_OUTPUT
|
||
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||
echo "previous-version=$PREVIOUS_VERSION" >> $GITHUB_OUTPUT
|
||
echo "is-prerelease=false" >> $GITHUB_OUTPUT
|
||
echo "ℹ️ No version change detected"
|
||
fi
|
||
|
||
extract-changelog:
|
||
name: Extract Changelog
|
||
runs-on: ubuntu-latest
|
||
needs: detect-version-change
|
||
if: needs.detect-version-change.outputs.version-changed == 'true'
|
||
outputs:
|
||
release-notes: ${{ steps.extract.outputs.notes }}
|
||
has-notes: ${{ steps.extract.outputs.has-notes }}
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Extract changelog for version
|
||
id: extract
|
||
run: |
|
||
VERSION="${{ needs.detect-version-change.outputs.new-version }}"
|
||
CHANGELOG_FILE="docs/CHANGELOG.md"
|
||
|
||
if [ ! -f "$CHANGELOG_FILE" ]; then
|
||
echo "Changelog file not found at $CHANGELOG_FILE"
|
||
echo "has-notes=false" >> $GITHUB_OUTPUT
|
||
echo "notes=No changelog entries found for version $VERSION" >> $GITHUB_OUTPUT
|
||
exit 0
|
||
fi
|
||
|
||
# Use the extracted changelog script
|
||
if NOTES=$(node scripts/extract-changelog.js "$VERSION" "$CHANGELOG_FILE" 2>/dev/null); then
|
||
echo "has-notes=true" >> $GITHUB_OUTPUT
|
||
|
||
# Use heredoc to properly handle multiline content
|
||
{
|
||
echo "notes<<EOF"
|
||
echo "$NOTES"
|
||
echo "EOF"
|
||
} >> $GITHUB_OUTPUT
|
||
|
||
echo "✅ Successfully extracted changelog for version $VERSION"
|
||
else
|
||
echo "has-notes=false" >> $GITHUB_OUTPUT
|
||
echo "notes=No changelog entries found for version $VERSION" >> $GITHUB_OUTPUT
|
||
echo "⚠️ Could not extract changelog for version $VERSION"
|
||
fi
|
||
|
||
create-release:
|
||
name: Create GitHub Release
|
||
runs-on: ubuntu-latest
|
||
needs: [detect-version-change, extract-changelog]
|
||
if: needs.detect-version-change.outputs.version-changed == 'true'
|
||
outputs:
|
||
release-id: ${{ steps.create.outputs.id }}
|
||
upload-url: ${{ steps.create.outputs.upload_url }}
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Create Git Tag
|
||
run: |
|
||
VERSION="${{ needs.detect-version-change.outputs.new-version }}"
|
||
git config user.name "github-actions[bot]"
|
||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||
|
||
# Create annotated tag
|
||
git tag -a "v$VERSION" -m "Release v$VERSION"
|
||
git push origin "v$VERSION"
|
||
|
||
- name: Create GitHub Release
|
||
id: create
|
||
env:
|
||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
VERSION="${{ needs.detect-version-change.outputs.new-version }}"
|
||
IS_PRERELEASE="${{ needs.detect-version-change.outputs.is-prerelease }}"
|
||
|
||
# Create release body
|
||
cat > release_body.md << 'EOF'
|
||
# Release v${{ needs.detect-version-change.outputs.new-version }}
|
||
|
||
${{ needs.extract-changelog.outputs.release-notes }}
|
||
|
||
---
|
||
|
||
## Installation
|
||
|
||
### NPM Package
|
||
```bash
|
||
# Install globally
|
||
npm install -g n8n-mcp
|
||
|
||
# Or run directly
|
||
npx n8n-mcp
|
||
```
|
||
|
||
### Docker
|
||
```bash
|
||
# Standard image
|
||
docker run -p 3000:3000 ghcr.io/czlonkowski/n8n-mcp:v${{ needs.detect-version-change.outputs.new-version }}
|
||
|
||
# Railway optimized
|
||
docker run -p 3000:3000 ghcr.io/czlonkowski/n8n-mcp-railway:v${{ needs.detect-version-change.outputs.new-version }}
|
||
```
|
||
|
||
## Documentation
|
||
- [Installation Guide](https://github.com/czlonkowski/n8n-mcp#installation)
|
||
- [Docker Deployment](https://github.com/czlonkowski/n8n-mcp/blob/main/docs/DOCKER_README.md)
|
||
- [n8n Integration](https://github.com/czlonkowski/n8n-mcp/blob/main/docs/N8N_DEPLOYMENT.md)
|
||
- [Complete Changelog](https://github.com/czlonkowski/n8n-mcp/blob/main/docs/CHANGELOG.md)
|
||
|
||
🤖 *Generated with [Claude Code](https://claude.ai/code)*
|
||
EOF
|
||
|
||
# Create release using gh CLI
|
||
if [ "$IS_PRERELEASE" = "true" ]; then
|
||
PRERELEASE_FLAG="--prerelease"
|
||
else
|
||
PRERELEASE_FLAG=""
|
||
fi
|
||
|
||
gh release create "v$VERSION" \
|
||
--title "Release v$VERSION" \
|
||
--notes-file release_body.md \
|
||
$PRERELEASE_FLAG
|
||
|
||
# Output release info for next jobs
|
||
RELEASE_ID=$(gh release view "v$VERSION" --json id --jq '.id')
|
||
echo "id=$RELEASE_ID" >> $GITHUB_OUTPUT
|
||
echo "upload_url=https://uploads.github.com/repos/${{ github.repository }}/releases/$RELEASE_ID/assets{?name,label}" >> $GITHUB_OUTPUT
|
||
|
||
build-and-test:
|
||
name: Build and Test
|
||
runs-on: ubuntu-latest
|
||
needs: detect-version-change
|
||
if: needs.detect-version-change.outputs.version-changed == 'true'
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 20
|
||
cache: 'npm'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Build project
|
||
run: npm run build
|
||
|
||
- name: Rebuild database
|
||
run: npm run rebuild
|
||
|
||
- name: Run tests
|
||
run: npm test
|
||
env:
|
||
CI: true
|
||
|
||
- name: Run type checking
|
||
run: npm run typecheck
|
||
|
||
publish-npm:
|
||
name: Publish to NPM
|
||
runs-on: ubuntu-latest
|
||
needs: [detect-version-change, build-and-test, create-release]
|
||
if: needs.detect-version-change.outputs.version-changed == 'true'
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- 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 project
|
||
run: npm run build
|
||
|
||
- name: Rebuild database
|
||
run: npm run rebuild
|
||
|
||
- name: Sync runtime version
|
||
run: npm run sync:runtime-version
|
||
|
||
- name: Prepare package for publishing
|
||
run: |
|
||
# Create publish directory
|
||
PUBLISH_DIR="npm-publish-temp"
|
||
rm -rf $PUBLISH_DIR
|
||
mkdir -p $PUBLISH_DIR
|
||
|
||
# Copy necessary files
|
||
cp -r dist $PUBLISH_DIR/
|
||
cp -r data $PUBLISH_DIR/
|
||
cp README.md $PUBLISH_DIR/
|
||
cp LICENSE $PUBLISH_DIR/
|
||
cp .env.example $PUBLISH_DIR/
|
||
|
||
# Use runtime package.json as base
|
||
cp package.runtime.json $PUBLISH_DIR/package.json
|
||
|
||
cd $PUBLISH_DIR
|
||
|
||
# Update package.json with complete metadata
|
||
node -e "
|
||
const pkg = require('./package.json');
|
||
pkg.name = 'n8n-mcp';
|
||
pkg.description = 'Integration between n8n workflow automation and Model Context Protocol (MCP)';
|
||
pkg.bin = { 'n8n-mcp': './dist/mcp/index.js' };
|
||
pkg.repository = { type: 'git', url: 'git+https://github.com/czlonkowski/n8n-mcp.git' };
|
||
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
|
||
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';
|
||
pkg.license = 'MIT';
|
||
pkg.bugs = { url: 'https://github.com/czlonkowski/n8n-mcp/issues' };
|
||
pkg.homepage = 'https://github.com/czlonkowski/n8n-mcp#readme';
|
||
pkg.files = ['dist/**/*', 'data/nodes.db', '.env.example', 'README.md', 'LICENSE'];
|
||
delete pkg.private;
|
||
require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2));
|
||
"
|
||
|
||
echo "Package prepared for publishing:"
|
||
echo "Name: $(node -e "console.log(require('./package.json').name)")"
|
||
echo "Version: $(node -e "console.log(require('./package.json').version)")"
|
||
|
||
- name: Publish to NPM with retry
|
||
uses: nick-invision/retry@v2
|
||
with:
|
||
timeout_minutes: 5
|
||
max_attempts: 3
|
||
command: |
|
||
cd npm-publish-temp
|
||
npm publish --access public
|
||
env:
|
||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||
|
||
- name: Clean up
|
||
if: always()
|
||
run: rm -rf npm-publish-temp
|
||
|
||
build-docker:
|
||
name: Build and Push Docker Images
|
||
runs-on: ubuntu-latest
|
||
needs: [detect-version-change, build-and-test]
|
||
if: needs.detect-version-change.outputs.version-changed == 'true'
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
with:
|
||
lfs: true
|
||
|
||
- name: Check disk space
|
||
run: |
|
||
echo "Disk usage before Docker build:"
|
||
df -h
|
||
|
||
# Check available space (require at least 2GB)
|
||
AVAILABLE_GB=$(df / --output=avail --block-size=1G | tail -1)
|
||
if [ "$AVAILABLE_GB" -lt 2 ]; then
|
||
echo "❌ Insufficient disk space: ${AVAILABLE_GB}GB available, 2GB required"
|
||
exit 1
|
||
fi
|
||
echo "✅ Sufficient disk space: ${AVAILABLE_GB}GB available"
|
||
|
||
- name: Set up QEMU
|
||
uses: docker/setup-qemu-action@v3
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
|
||
- name: Log in to GitHub Container Registry
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ${{ env.REGISTRY }}
|
||
username: ${{ github.actor }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Extract metadata for standard image
|
||
id: meta
|
||
uses: docker/metadata-action@v5
|
||
with:
|
||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||
tags: |
|
||
type=semver,pattern={{version}},value=v${{ needs.detect-version-change.outputs.new-version }}
|
||
type=semver,pattern={{major}}.{{minor}},value=v${{ needs.detect-version-change.outputs.new-version }}
|
||
type=semver,pattern={{major}},value=v${{ needs.detect-version-change.outputs.new-version }}
|
||
type=raw,value=latest,enable={{is_default_branch}}
|
||
|
||
- name: Build and push standard Docker image
|
||
uses: docker/build-push-action@v5
|
||
with:
|
||
context: .
|
||
platforms: linux/amd64,linux/arm64
|
||
push: true
|
||
tags: ${{ steps.meta.outputs.tags }}
|
||
labels: ${{ steps.meta.outputs.labels }}
|
||
cache-from: type=gha
|
||
cache-to: type=gha,mode=max
|
||
|
||
- name: Extract metadata for Railway image
|
||
id: meta-railway
|
||
uses: docker/metadata-action@v5
|
||
with:
|
||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
|
||
tags: |
|
||
type=semver,pattern={{version}},value=v${{ needs.detect-version-change.outputs.new-version }}
|
||
type=semver,pattern={{major}}.{{minor}},value=v${{ needs.detect-version-change.outputs.new-version }}
|
||
type=semver,pattern={{major}},value=v${{ needs.detect-version-change.outputs.new-version }}
|
||
type=raw,value=latest,enable={{is_default_branch}}
|
||
|
||
- name: Build and push Railway Docker image
|
||
uses: docker/build-push-action@v5
|
||
with:
|
||
context: .
|
||
file: ./Dockerfile.railway
|
||
platforms: linux/amd64
|
||
push: true
|
||
tags: ${{ steps.meta-railway.outputs.tags }}
|
||
labels: ${{ steps.meta-railway.outputs.labels }}
|
||
cache-from: type=gha
|
||
cache-to: type=gha,mode=max
|
||
|
||
update-documentation:
|
||
name: Update Documentation
|
||
runs-on: ubuntu-latest
|
||
needs: [detect-version-change, create-release, publish-npm, build-docker]
|
||
if: needs.detect-version-change.outputs.version-changed == 'true' && !failure()
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
with:
|
||
token: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 20
|
||
|
||
- name: Update version badges in README
|
||
run: |
|
||
VERSION="${{ needs.detect-version-change.outputs.new-version }}"
|
||
|
||
# Update README version badges
|
||
if [ -f "README.md" ]; then
|
||
# Update npm version badge
|
||
sed -i.bak "s|npm/v/n8n-mcp/[^)]*|npm/v/n8n-mcp/$VERSION|g" README.md
|
||
|
||
# Update any other version references
|
||
sed -i.bak "s|version-[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*|version-$VERSION|g" README.md
|
||
|
||
# Clean up backup file
|
||
rm -f README.md.bak
|
||
|
||
echo "✅ Updated version badges in README.md to $VERSION"
|
||
fi
|
||
|
||
- name: Commit documentation updates
|
||
env:
|
||
VERSION: ${{ needs.detect-version-change.outputs.new-version }}
|
||
run: |
|
||
git config user.name "github-actions[bot]"
|
||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||
|
||
if git diff --quiet; then
|
||
echo "No documentation changes to commit"
|
||
else
|
||
git add README.md
|
||
git commit -m "docs: update version badges to v${VERSION}"
|
||
git push
|
||
echo "✅ Committed documentation updates"
|
||
fi
|
||
|
||
notify-completion:
|
||
name: Notify Release Completion
|
||
runs-on: ubuntu-latest
|
||
needs: [detect-version-change, create-release, publish-npm, build-docker, update-documentation]
|
||
if: always() && needs.detect-version-change.outputs.version-changed == 'true'
|
||
steps:
|
||
- name: Create release summary
|
||
run: |
|
||
VERSION="${{ needs.detect-version-change.outputs.new-version }}"
|
||
RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/v$VERSION"
|
||
|
||
echo "## 🎉 Release v$VERSION Published Successfully!" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "### ✅ Completed Tasks:" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
|
||
# Check job statuses
|
||
if [ "${{ needs.create-release.result }}" = "success" ]; then
|
||
echo "- ✅ GitHub Release created: [$RELEASE_URL]($RELEASE_URL)" >> $GITHUB_STEP_SUMMARY
|
||
else
|
||
echo "- ❌ GitHub Release creation failed" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
|
||
if [ "${{ needs.publish-npm.result }}" = "success" ]; then
|
||
echo "- ✅ NPM package published: [npmjs.com/package/n8n-mcp](https://www.npmjs.com/package/n8n-mcp)" >> $GITHUB_STEP_SUMMARY
|
||
else
|
||
echo "- ❌ NPM publishing failed" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
|
||
if [ "${{ needs.build-docker.result }}" = "success" ]; then
|
||
echo "- ✅ Docker images built and pushed" >> $GITHUB_STEP_SUMMARY
|
||
echo " - Standard: \`ghcr.io/czlonkowski/n8n-mcp:v$VERSION\`" >> $GITHUB_STEP_SUMMARY
|
||
echo " - Railway: \`ghcr.io/czlonkowski/n8n-mcp-railway:v$VERSION\`" >> $GITHUB_STEP_SUMMARY
|
||
else
|
||
echo "- ❌ Docker image building failed" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
|
||
if [ "${{ needs.update-documentation.result }}" = "success" ]; then
|
||
echo "- ✅ Documentation updated" >> $GITHUB_STEP_SUMMARY
|
||
else
|
||
echo "- ⚠️ Documentation update skipped or failed" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "### 📦 Installation:" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
|
||
echo "# NPM" >> $GITHUB_STEP_SUMMARY
|
||
echo "npx n8n-mcp" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "# Docker" >> $GITHUB_STEP_SUMMARY
|
||
echo "docker run -p 3000:3000 ghcr.io/czlonkowski/n8n-mcp:v$VERSION" >> $GITHUB_STEP_SUMMARY
|
||
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||
|
||
echo "🎉 Release automation completed for v$VERSION!" |