release.ymlβ’7.91 kB
name: Release Pipeline
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., v1.0.0)'
required: true
type: string
permissions:
contents: write
packages: write
pull-requests: read
jobs:
# Job 1: Validate Release
validate-release:
name: Validate Release
runs-on: ubuntu-latest
timeout-minutes: 20
outputs:
version: ${{ steps.version.outputs.version }}
is-prerelease: ${{ steps.version.outputs.is-prerelease }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Extract version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${GITHUB_REF#refs/tags/}"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
if [[ "$VERSION" =~ -[a-zA-Z] ]]; then
echo "is-prerelease=true" >> $GITHUB_OUTPUT
else
echo "is-prerelease=false" >> $GITHUB_OUTPUT
fi
echo "Release version: $VERSION"
echo "Is prerelease: $(echo $VERSION | grep -E '-[a-zA-Z]' && echo true || echo false)"
- name: Validate version format
run: |
VERSION="${{ steps.version.outputs.version }}"
if ! [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "Invalid version format: $VERSION"
echo "Expected format: vX.Y.Z or vX.Y.Z-prerelease"
exit 1
fi
- name: Build project
run: npm run build
- name: Run full test suite
run: npm run test:offline
- name: Run linting and type checking
run: |
npm run lint:check
npm run check
- name: Verify no uncommitted changes
run: |
if ! git diff --exit-code; then
echo "There are uncommitted changes"
exit 1
fi
# Job 2: Create Release Build
create-release-build:
name: Create Release Build
runs-on: ubuntu-latest
needs: validate-release
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Create build artifacts
run: |
mkdir -p release-artifacts
cp -r dist release-artifacts/
cp package.json release-artifacts/
cp package-lock.json release-artifacts/
cp README.md release-artifacts/
cp LICENSE release-artifacts/
- name: Create tarball
run: |
cd release-artifacts
tar -czf ../attio-mcp-server-${{ needs.validate-release.outputs.version }}.tar.gz .
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: release-build-${{ needs.validate-release.outputs.version }}
retention-days: 90
path: |
attio-mcp-server-${{ needs.validate-release.outputs.version }}.tar.gz
release-artifacts/
# Job 3: Create GitHub Release
create-github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [validate-release, create-release-build]
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: release-build-${{ needs.validate-release.outputs.version }}
- name: Generate changelog
id: changelog
run: |
VERSION="${{ needs.validate-release.outputs.version }}"
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
echo "Generating changelog for $VERSION..."
if [ -n "$PREV_TAG" ]; then
echo "Changes since $PREV_TAG:" > changelog.md
echo "" >> changelog.md
git log --pretty=format:"- %s (%h)" $PREV_TAG..HEAD >> changelog.md
else
echo "Initial release" > changelog.md
fi
cat changelog.md
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ needs.validate-release.outputs.version }}
name: Release ${{ needs.validate-release.outputs.version }}
body_path: changelog.md
prerelease: ${{ needs.validate-release.outputs.is-prerelease }}
files: |
attio-mcp-server-${{ needs.validate-release.outputs.version }}.tar.gz
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Job 4: Post-Release Tasks
post-release:
name: Post-Release Tasks
runs-on: ubuntu-latest
needs: [validate-release, create-github-release]
if: always() && needs.create-github-release.result == 'success'
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Update documentation
run: |
echo "Release ${{ needs.validate-release.outputs.version }} completed successfully!"
echo "Release artifacts are available at: https://github.com/${{ github.repository }}/releases/tag/${{ needs.validate-release.outputs.version }}"
- name: Notify success
uses: actions/github-script@v7
with:
script: |
const version = '${{ needs.validate-release.outputs.version }}';
const isPrerelease = '${{ needs.validate-release.outputs.is-prerelease }}' === 'true';
console.log(`π Release ${version} has been created successfully!`);
if (isPrerelease) {
console.log('β οΈ This is a pre-release version');
} else {
console.log('β
This is a stable release');
}
console.log(`π¦ Release assets are available at: https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/${version}`);
# Job 5: Release Failure Cleanup
release-failure-cleanup:
name: Release Failure Cleanup
runs-on: ubuntu-latest
needs: [validate-release, create-release-build, create-github-release]
if: failure()
timeout-minutes: 5
steps:
- name: Cleanup on failure
uses: actions/github-script@v7
with:
script: |
console.log('β Release process failed');
console.log('Please check the failed jobs and resolve any issues before retrying the release');
const failedJobs = [];
if ('${{ needs.validate-release.result }}' === 'failure') failedJobs.push('validate-release');
if ('${{ needs.create-release-build.result }}' === 'failure') failedJobs.push('create-release-build');
if ('${{ needs.create-github-release.result }}' === 'failure') failedJobs.push('create-github-release');
if (failedJobs.length > 0) {
console.log(`Failed jobs: ${failedJobs.join(', ')}`);
}
core.setFailed('Release process failed. Check the logs for details.');