Skip to content

Bump & Publish

Bump & Publish #7

name: Bump & Publish
on:
workflow_dispatch:
inputs:
release:
description: "Version bump type (major | minor | patch)"
required: true
default: patch
type: choice
options:
- patch
- minor
- major
jobs:
bump-and-publish:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
if: github.ref == 'refs/heads/dev'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22"
registry-url: "https://registry.npmjs.org"
scope: "@impulselab"
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.15.0
- name: Verify npm auth
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [ -z "${NODE_AUTH_TOKEN}" ]; then
echo "NPM token is missing. Set repository secret NPM_TOKEN with publish permissions." >&2
exit 1
fi
npm whoami --registry=https://registry.npmjs.org || { echo "npm auth failed. Check token scope." >&2; exit 1; }
- name: Install
run: pnpm install --frozen-lockfile
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Bump version in package.json
id: bump
env:
RELEASE: ${{ github.event.inputs.release }}
run: |
bump() {
local file=$1
local release=$2
current=$(jq -r '.version' "$file")
IFS='.' read -r major minor patch <<< "$current"
case "$release" in
major)
major=$((major+1)); minor=0; patch=0;;
minor)
minor=$((minor+1)); patch=0;;
patch)
patch=$((patch+1));;
*) echo "Invalid release type: $release"; exit 1;;
esac
new="${major}.${minor}.${patch}"
tmp=$(mktemp)
jq --arg v "$new" '.version = $v' "$file" > "$tmp" && mv "$tmp" "$file"
echo "$new"
}
NEW_VER=$(bump package.json "$RELEASE")
echo "version=$NEW_VER" >> $GITHUB_OUTPUT
- name: Commit version bumps
run: |
git add package.json
git commit -m "chore(release): bump versions (version: ${{ steps.bump.outputs.version }})"
git push
- name: Build workspace
run: pnpm build
- name: Publish @impulselab/testing
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
npm config set //registry.npmjs.org/:_authToken "$NODE_AUTH_TOKEN"
npm config set @impulselab:registry https://registry.npmjs.org/
pnpm publish --access public --no-git-checks
# Deploy to production by creating tag and updating main branch
- name: Create and push Git tag
run: |
git tag v${{ steps.bump.outputs.version }}
git push origin v${{ steps.bump.outputs.version }}
- name: Update main to tag commit
run: |
git fetch origin main --prune
git checkout -B main
git push origin main --force-with-lease
- name: Send Discord deployment notification
if: success()
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
run: |
# Extract metadata
TAG_NAME="v${{ steps.bump.outputs.version }}"
TAG_SHA="${{ github.sha }}"
SHORT_SHA=$(echo "$TAG_SHA" | cut -c1-7)
REPO_URL="https://github.com/${{ github.repository }}"
COMMIT_URL="${REPO_URL}/commit/${TAG_SHA}"
WORKFLOW_URL="${REPO_URL}/actions/runs/${{ github.run_id }}"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
PROJECT_NAME=$(jq -r '.name' package.json)
# Build Discord embed payload
PAYLOAD=$(cat <<EOF
{
"embeds": [{
"title": "✅ Production Deployment Successful",
"color": 3066993,
"fields": [
{
"name": "Project",
"value": "${PROJECT_NAME}",
"inline": true
},
{
"name": "Environment",
"value": "production",
"inline": true
},
{
"name": "Tag Version",
"value": "${TAG_NAME}",
"inline": true
},
{
"name": "Commit",
"value": "[${SHORT_SHA}](${COMMIT_URL})",
"inline": true
},
{
"name": "Deployed At",
"value": "${TIMESTAMP}",
"inline": true
},
{
"name": "Workflow Run",
"value": "[View Run](${WORKFLOW_URL})",
"inline": true
}
],
"timestamp": "${TIMESTAMP}"
}]
}
EOF
)
# Send to Discord webhook
if [ -z "$DISCORD_WEBHOOK_URL" ]; then
echo "⚠️ DISCORD_WEBHOOK_URL secret is not set. Skipping notification."
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"$DISCORD_WEBHOOK_URL")
if [ "$HTTP_STATUS" -eq 204 ] || [ "$HTTP_STATUS" -eq 200 ]; then
echo "✅ Discord notification sent successfully (HTTP $HTTP_STATUS)"
else
echo "⚠️ Failed to send Discord notification (HTTP $HTTP_STATUS)"
exit 1
fi
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.bump.outputs.version }}
name: Release v${{ steps.bump.outputs.version }}
body: |
Release v${{ steps.bump.outputs.version }}
**Package Versions:**
- @impulselab/testing: v${{ steps.bump.outputs.version }}
generate_release_notes: true
token: ${{ secrets.GITHUB_TOKEN }}