Skip to content

chore: consolidate canary and release publish into single workflow (#… #1

chore: consolidate canary and release publish into single workflow (#…

chore: consolidate canary and release publish into single workflow (#… #1

name: Publish TypeScript Packages
on:
push:
branches:
- main
workflow_dispatch:
inputs:
publish-to-npm:
description: 'Publish to npm registry'
required: true
default: true
type: boolean
create-github-release:
description: 'Create GitHub release'
required: true
default: true
type: boolean
permissions:
contents: write # Push tags, create releases
id-token: write # npm provenance (OIDC)
pull-requests: write # Comment on PRs
# Prevent concurrent publishes
concurrency:
group: typescript-publish
cancel-in-progress: false
jobs:
typescript-build:
uses: ./.github/workflows/typescript-build.yml
typescript-test:
uses: ./.github/workflows/typescript-test.yml
publish:
name: Publish create-solana-dapp
runs-on: ubuntu-latest
needs: [typescript-build, typescript-test]
env:
NPM_CONFIG_PROVENANCE: true
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Git user
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Install Dependencies
uses: ./.github/workflows/actions/install-dependencies
- name: Setup npm registry auth
uses: actions/setup-node@v4
with:
registry-url: 'https://registry.npmjs.org'
- name: Determine publish type
id: publish-type
run: |
if [ "${{ github.event_name }}" == "push" ]; then
echo "type=canary" >> $GITHUB_OUTPUT
echo "Publish type: canary (push to main)"
else
echo "type=release" >> $GITHUB_OUTPUT
echo "Publish type: release (manual dispatch)"
fi
# --- Canary: snapshot version via changesets ---
- name: Version as canary snapshot
if: steps.publish-type.outputs.type == 'canary'
run: pnpm changeset version --snapshot canary
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build
run: pnpm build
- name: Run type check
run: pnpm test:types
- name: Get version
id: version
run: |
VERSION=$(node -p "require('./package.json').version")
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Publishing version: $VERSION"
- name: Determine npm tag
id: npm-tag
run: |
TYPE="${{ steps.publish-type.outputs.type }}"
VERSION="${{ steps.version.outputs.version }}"
if [ "$TYPE" == "canary" ]; then
echo "npm_tag=canary" >> $GITHUB_OUTPUT
echo "is_prerelease=true" >> $GITHUB_OUTPUT
elif [[ "$VERSION" == *"-"* ]]; then
echo "npm_tag=beta" >> $GITHUB_OUTPUT
echo "is_prerelease=true" >> $GITHUB_OUTPUT
else
echo "npm_tag=latest" >> $GITHUB_OUTPUT
echo "is_prerelease=false" >> $GITHUB_OUTPUT
fi
echo "npm tag: $(grep npm_tag $GITHUB_OUTPUT | tail -1)"
- name: Pack tarball
run: |
mkdir -p .npm-pack
pnpm pack --pack-destination .npm-pack
echo ""
echo "Packed tarball:"
ls -la .npm-pack/
- name: 'Guard - Fail if tarball missing dist/ artifacts'
run: |
echo "Checking tarball for dist/ artifacts..."
for tarball in .npm-pack/*.tgz; do
CONTENTS=$(tar -tzf "$tarball")
if ! echo "$CONTENTS" | grep -q "package/dist/index.mjs"; then
echo "FAIL: ${tarball} is missing dist/index.mjs!"
exit 1
fi
if ! echo "$CONTENTS" | grep -q "package/dist/index.cjs"; then
echo "FAIL: ${tarball} is missing dist/index.cjs!"
exit 1
fi
if ! echo "$CONTENTS" | grep -q "package/dist/index.d.ts"; then
echo "FAIL: ${tarball} is missing dist/index.d.ts!"
exit 1
fi
if ! echo "$CONTENTS" | grep -q "package/dist/bin/index.cjs"; then
echo "FAIL: ${tarball} is missing dist/bin/index.cjs (CLI entrypoint)!"
exit 1
fi
echo "All required dist/ artifacts present"
done
# --- Release only: tag + GitHub release ---
- name: Create and push tag
if: steps.publish-type.outputs.type == 'release'
run: |
TAG="v${{ steps.version.outputs.version }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG already exists, skipping"
else
git tag "$TAG"
echo "Created tag $TAG"
fi
git push origin "$TAG" 2>/dev/null || echo "Tag already pushed"
- name: Publish to npm
if: steps.publish-type.outputs.type == 'canary' || github.event.inputs.publish-to-npm == 'true'
run: |
VERSION="${{ steps.version.outputs.version }}"
NPM_TAG="${{ steps.npm-tag.outputs.npm_tag }}"
TARBALL=$(ls .npm-pack/*.tgz | head -1)
if [ -f "$TARBALL" ]; then
echo "Publishing ${TARBALL} with tag '${NPM_TAG}'..."
npm publish "$TARBALL" --access public --tag "$NPM_TAG"
echo "Published successfully"
else
echo "Tarball not found. Available:"
ls -la .npm-pack/ || true
exit 1
fi
- name: Create GitHub Release
if: steps.publish-type.outputs.type == 'release' && github.event.inputs.create-github-release == 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const tagName = `v${{ steps.version.outputs.version }}`;
const version = `${{ steps.version.outputs.version }}`;
const releaseName = `create-solana-dapp v${version}`;
const isPrerelease = '${{ steps.npm-tag.outputs.is_prerelease }}' === 'true';
const body = `## create-solana-dapp v${version}
### Installation
\`\`\`bash
npx create-solana-dapp@${version}
\`\`\`
`;
// Check if release already exists
try {
await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: tagName,
});
console.log(`Release ${tagName} already exists, skipping`);
return;
} catch (e) {
if (e.status !== 404) throw e;
}
await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: tagName,
name: releaseName,
body: body.trim(),
draft: false,
prerelease: isPrerelease,
});
console.log(`Created release: ${releaseName}`);
- name: Publish summary
run: |
TYPE="${{ steps.publish-type.outputs.type }}"
VERSION="${{ steps.version.outputs.version }}"
NPM_TAG="${{ steps.npm-tag.outputs.npm_tag }}"
cat >> $GITHUB_STEP_SUMMARY << EOF
## TypeScript Package Published
**Type**: \`${TYPE}\`
**Version**: \`${VERSION}\`
**Package**: \`create-solana-dapp\`
**npm tag**: \`${NPM_TAG}\`
EOF
if [ "$TYPE" == "canary" ]; then
echo "Canary published to npm: \`create-solana-dapp@${NPM_TAG}\`" >> $GITHUB_STEP_SUMMARY
else
if [ "${{ github.event.inputs.publish-to-npm }}" == "true" ]; then
echo "Published to npm: https://www.npmjs.com/package/create-solana-dapp/v/${VERSION}" >> $GITHUB_STEP_SUMMARY
else
echo "Skipped npm publish (dry run)" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ github.event.inputs.create-github-release }}" == "true" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "GitHub release created: https://github.com/${{ github.repository }}/releases/tag/v${VERSION}" >> $GITHUB_STEP_SUMMARY
else
echo "" >> $GITHUB_STEP_SUMMARY
echo "Skipped GitHub release creation" >> $GITHUB_STEP_SUMMARY
fi
fi