Bootstrap Publish #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Bootstrap Publish | |
| # Bare-bones manual publish workflow for the initial @shopify/shop-cli | |
| # release(s). This is intentionally minimal: no version bumping, no | |
| # changelog generation, no git tagging. Bump `version` in package.json on | |
| # `main`, then dispatch this workflow. | |
| # | |
| # This will be replaced by Changesets once we are past the first few | |
| # publishes and want automated version/tag/changelog management. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| dry-run: | |
| description: "Run the full pipeline + pack but skip the actual publish. Defaults to true; flip to false to actually publish." | |
| required: true | |
| type: boolean | |
| default: true | |
| tag: | |
| description: "Dist-tag for this publish. 'next' for prereleases (e.g. 0.3.0-alpha.1), 'latest' only for stable versions." | |
| required: true | |
| type: choice | |
| default: next | |
| options: | |
| - next | |
| - latest | |
| permissions: | |
| contents: read | |
| id-token: write | |
| concurrency: | |
| group: shop-cli-publish | |
| cancel-in-progress: false | |
| jobs: | |
| publish: | |
| name: Bootstrap publish @shopify/shop-cli to npm | |
| # Refuse to run from anywhere but `main`. | |
| if: github.ref == 'refs/heads/main' | |
| environment: | |
| name: npm-shop-cli | |
| url: https://www.npmjs.com/package/@shopify/shop-cli | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| fetch-depth: 0 | |
| - uses: shop/setup-javascript-action@main | |
| with: | |
| node-version-file: package.json | |
| pnpm-version: 10.28.0 | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Typecheck | |
| run: pnpm typecheck | |
| - name: Test | |
| run: pnpm test | |
| - name: Build | |
| run: pnpm build | |
| - name: Pack and inspect contents | |
| run: | | |
| pnpm pack --pack-destination /tmp/shop-cli-bootstrap | |
| echo "Tarball contents:" | |
| tar -tzf /tmp/shop-cli-bootstrap/*.tgz | sort | |
| - name: Print publish plan | |
| env: | |
| DIST_TAG: ${{ inputs.tag }} | |
| DRY_RUN: ${{ inputs.dry-run }} | |
| run: | | |
| VERSION=$(node -p "require('./package.json').version") | |
| echo "::notice::Plan: publish @shopify/shop-cli@${VERSION} with --tag ${DIST_TAG} (dry-run=${DRY_RUN})" | |
| # Fail fast with a clear error if the NPM_TOKEN secret is missing or | |
| # empty. Nothing about the token value is logged — only its presence | |
| # as a boolean. | |
| - name: Verify NPM_TOKEN is present | |
| if: ${{ !inputs.dry-run }} | |
| env: | |
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: | | |
| if [ -z "${NPM_TOKEN}" ]; then | |
| echo "::error::NPM_TOKEN secret is missing or empty. Add it in repo Settings → Secrets and variables → Actions before re-running." | |
| exit 1 | |
| fi | |
| echo "::notice::NPM_TOKEN is present." | |
| - name: Configure npm auth | |
| if: ${{ !inputs.dry-run }} | |
| run: | | |
| echo "registry=https://registry.npmjs.org/" > ~/.npmrc | |
| echo "//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}" >> ~/.npmrc | |
| echo "@shopify:registry=https://registry.npmjs.org/" >> ~/.npmrc | |
| - name: Resolve unwrapped npm (bypass package-manager wrappers) | |
| run: | | |
| # Shopify's npm wrapper enforces install-time policy (minimum_dependency_age) that doesn't apply to `npm version` or `npm publish`; point at the npm bundled with node directly. OIDC auth is driven by ~/.npmrc and `id-token: write`, not by which binary runs. | |
| echo "UNWRAPPED_NPM=$(dirname "$(command -v node)")/npm" >> "$GITHUB_ENV" | |
| - name: Set up .npmrc for publishing | |
| run: | | |
| # Override project-level .npmrc that points to internal registry | |
| if [ -f .npmrc ]; then | |
| cp .npmrc .npmrc.backup | |
| sed -i.bak 's|@shopify:registry=.*|@shopify:registry=https://registry.npmjs.org/|' .npmrc | |
| echo "✅ Updated project .npmrc to use public npm for @shopify packages" | |
| # Remove backup files created by sed and cp | |
| rm -f .npmrc.bak .npmrc.backup | |
| echo "✅ Cleaned up backup files" | |
| fi | |
| # Configure git for package tag creation. | |
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | |
| git config --global user.name "github-actions[bot]" | |
| # Hide the local .npmrc registry override from git so npm version/publish | |
| # see a clean source checkout without creating a synthetic commit. | |
| if git diff --quiet .npmrc; then | |
| echo "ℹ️ No .npmrc changes to hide" | |
| else | |
| git update-index --assume-unchanged .npmrc | |
| echo "✅ Hid local .npmrc publishing override from git status" | |
| fi | |
| - name: Publish to npm | |
| if: ${{ !inputs.dry-run }} | |
| run: | | |
| PACKAGE_NAME=$(node -p "require('./package.json').name") | |
| VERSION=$(node -p "require('./package.json').version") | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| if [ "${{ inputs.dry_run }}" = "true" ]; then | |
| echo "🧪 DRY RUN: Would publish $PACKAGE_NAME@$VERSION with tag $DIST_TAG" | |
| exit 0 | |
| fi | |
| if "$UNWRAPPED_NPM" view "$PACKAGE_NAME@$VERSION" version --registry=https://registry.npmjs.org/ >/dev/null 2>&1; then | |
| echo "ℹ️ $PACKAGE_NAME@$VERSION already exists on npm; skipping publish" | |
| exit 0 | |
| fi | |
| "$UNWRAPPED_NPM" publish --tag "$DIST_TAG" --access public --verbose | |
| echo "✅ Published $PACKAGE_NAME@$VERSION with tag $DIST_TAG" | |
| env: | |
| DIST_TAG: ${{ inputs.tag }} | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Dry-run summary | |
| if: ${{ inputs.dry-run }} | |
| env: | |
| DIST_TAG: ${{ inputs.tag }} | |
| run: | | |
| echo "::notice::Dry-run requested — skipped npm publish." | |
| echo "Would have published with: --tag $DIST_TAG --access public" |