Skip to content

Publish New Package Version #57

Publish New Package Version

Publish New Package Version #57

---
name: Publish New Package Version
on:
workflow_dispatch:
inputs:
package:
type: choice
description: Package name
options:
- offchain-manager
- addresses
- indexer
- mint-manager
version:
type: string
description: "version"
publish:
type: boolean
description: Publish to npm
default: false
changelog:
type: string
description: "Changelog (required if publishing, markdown format, do NOT include version or date header. Use sections like ### Added, ### Changed, etc.)"
default: ""
discord_notify:
type: boolean
description: "If checked, the release will notify on discord"
default: false
jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 24
registry-url: "https://registry.npmjs.org/"
- name: Read previous version from package.json
id: previous-version
working-directory: packages/${{ inputs.package }}
run: |
version=$(jq -r '.version' package.json)
echo "Previous version: $version"
echo "version=$version" >> $GITHUB_OUTPUT
- name: Extract new version from input
id: current-version
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
# Ensure semver format
if [[ ! "$INPUT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "❌ Invalid version format. Must follow semantic versioning (e.g., 1.2.3 or 1.2.3-suffix)"
exit 1
fi
version="${{ inputs.version }}"
echo "Current version: $version"
echo "version=$version" >> $GITHUB_OUTPUT
- name: Check valid version increase
uses: aleoyakas/check-semver-increased-action@v1
id: check-version
with:
current-version: ${{ steps.current-version.outputs.version }}
previous-version: ${{ steps.previous-version.outputs.version }}
- name: Fail if version not increased
if: steps.check-version.outputs.is-version-increased != 'true'
run: |
echo "❌ Version has not increased. Please bump the version above ${{ steps.previous-version.outputs.version }}"
exit 1
- name: Install dependencies
run: npm ci
# Build workspace dependencies first (in dependency order)
- name: Build workspace dependencies
run: |
# Build addresses package first since mint-manager depends on it
if [ "${{ inputs.package }}" = "mint-manager" ]; then
echo "Building @thenamespace/addresses dependency..."
npm run -w @thenamespace/addresses build
fi
# Add other workspace dependencies here as needed
# Example: if a package depends on indexer, add:
# if [ "${{ inputs.package }}" = "some-package" ]; then
# echo "Building @thenamespace/indexer dependency..."
# npm run -w @thenamespace/indexer build
# fi
# Future-proof: Check for any @thenamespace/* dependencies in package.json
# and build them if they exist as workspace packages
echo "Checking for other workspace dependencies..."
WORKSPACE_DEPS=$(jq -r '.dependencies | keys[] | select(startswith("@thenamespace/"))' packages/${{ inputs.package }}/package.json 2>/dev/null || echo "")
for dep in $WORKSPACE_DEPS; do
if [ "$dep" != "@thenamespace/${{ inputs.package }}" ] && [ -d "packages/${dep#@thenamespace/}" ]; then
echo "Building workspace dependency: $dep"
npm run -w "$dep" build
fi
done
- name: Build selected package
working-directory: packages/${{ inputs.package }}
run: npm run build
- name: Update package version in package.json
working-directory: packages/${{ inputs.package }}
run: |
npm version ${{ inputs.version }} --no-git-tag-version
- name: Validate changelog if publishing
if: ${{ inputs.publish == true }}
run: |
if [ -z "${{ inputs.changelog }}" ]; then
echo "❌ Changelog is required when publishing."
exit 1
fi
- name: Publish package to npm registry
if: ${{ inputs.publish == true }}
working-directory: packages/${{ inputs.package }}
run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Commit and push version bump and tag
if: ${{ inputs.publish == true }}
env:
VERSION: ${{ inputs.version }}
CHANGELOG: ${{ inputs.changelog }}
PACKAGE: ${{ inputs.package }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
echo "📝 Inserting changelog for $VERSION"
FILE="changelog/${PACKAGE}-changelog.md"
TEMP_FILE="${FILE}.tmp"
DATE=$(date +'%Y-%m-%d')
HEADER="## [${VERSION}] - ${DATE}"
if [ ! -f "$FILE" ]; then
echo -e "# Changelog\n" > "$FILE"
fi
# Find the line number of the "# Changelog" header
HEADER_LINE=$(grep -n "^# Changelog" "$FILE" | cut -d: -f1)
if [ -z "$HEADER_LINE" ]; then
# If not found, just prepend
HEADER_LINE=0
fi
# Find the line number after the intro section (after the first blank line following '# Changelog')
INTRO_END_LINE=$(awk '/^# Changelog/{flag=1; next} flag && /^$/{print NR; exit}' "$FILE")
if [ -z "$INTRO_END_LINE" ]; then
# Fallback: if not found, use header line
HEADER_LINE=$(grep -n "^# Changelog" "$FILE" | cut -d: -f1)
if [ -z "$HEADER_LINE" ]; then
HEADER_LINE=0
fi
INTRO_END_LINE=$((HEADER_LINE + 1))
fi
# Process the changelog input to ensure proper formatting
# Handle both multi-line and single-line input from GitHub UI
PRETTY_CHANGELOG=$(echo "$CHANGELOG" | sed -E 's/\\n/\n/g' | sed -E 's/\\1/\n/g' | sed -E 's/^[[:space:]]*//' | sed -E 's/[[:space:]]*$//')
# Write up to and including the intro
if [ "$INTRO_END_LINE" -gt 0 ]; then
head -n "$INTRO_END_LINE" "$FILE" > "$TEMP_FILE"
fi
# Add the new entry
echo -e "\n${HEADER}\n\n${PRETTY_CHANGELOG}\n" >> "$TEMP_FILE"
# Add the rest of the file
if [ "$INTRO_END_LINE" -gt 0 ]; then
tail -n "+$((INTRO_END_LINE + 1))" "$FILE" >> "$TEMP_FILE"
fi
mv "$TEMP_FILE" "$FILE"
# Commit the updated package.json with new version
git add packages/$PACKAGE/package.json
git add changelog/*
git commit -m "chore($PACKAGE): bump version to $VERSION"
# Create a tag with the version
TAG="${PACKAGE}-${VERSION}"
git tag -a "$TAG" -m "Release $TAG"
# Push commit and tag
git push origin HEAD
git push origin "$TAG"
- name: Post update to Discord
if: ${{ inputs.discord_notify == true }}
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK }}
VERSION: ${{ inputs.version }}
CHANGELOG: ${{ inputs.changelog }}
PACKAGE: ${{ inputs.package }}
run: |
MESSAGE="Published a new version of *@thenamespace/${PACKAGE}*, version: \`${VERSION}\`!\n\n📝 ${CHANGELOG}"
curl -X POST -H "Content-Type: application/json" \
-d "{\"content\": \"$MESSAGE\"}" \
"$DISCORD_WEBHOOK_URL"