Skip to content

ci: add scripts/deploy.sh — publish to npm without GitHub Actions - #15

Merged
zanjonke merged 2 commits into
mainfrom
ci/deploy-script
Aug 6, 2026
Merged

ci: add scripts/deploy.sh — publish to npm without GitHub Actions#15
zanjonke merged 2 commits into
mainfrom
ci/deploy-script

Conversation

@zanjonke

@zanjonke zanjonke commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

A shell equivalent of the publish workflow, for releasing when Actions is unavailable, broken, or simply not wanted.

./scripts/deploy.sh                 # publish the latest GitHub release
./scripts/deploy.sh --tag v1.0.21   # publish a specific tag
./scripts/deploy.sh --dry-run       # rehearse: test + pack, publish nothing
./scripts/deploy.sh --otp 123456    # npm account with 2FA on publish

What it does

Same sequence as the workflow: fetch the latest release tag (or the one you pass), validate it as semver, refuse if that version is already on npm, check the tag out into a temporary git worktree, npm ci, npm test, set the version from the tag, publish, and post to Slack. Pre-releases go out under the next dist-tag.

Building from a worktree rather than the working tree means your local edits, branch and dirty files are irrelevant to what ships — and untouched afterwards. The worktree is removed on exit, including on failure.

Deployments

It records a GitHub Deployment against the npm environment — in_progresssuccess/failure — so a local release shows up in the repo's Deployments list exactly like a workflow release does. Verified against the live API (created, transitioned, deleted; the repo has no leftover records).

Slack

Reads SLACK_WEBHOOK_URL from the environment or from a gitignored .env.release at the repo root. Start / success / failure messages match the workflow's, tagged as a local deploy. Without a webhook the script runs silently rather than failing.

One real difference from CI

The workflow authenticates with OIDC trusted publishing, which only works from a CI runner. Locally you publish as yourself, so the script requires npm login and supports --otp for 2FA. That's checked in preflight, along with git/gh/npm/node/jq/curl and gh auth status.

Safety

  • Confirmation prompt before publishing (skip with -y).
  • --dry-run runs everything up to and including npm pack --dry-run, publishing nothing — exercised end-to-end while writing this.
  • Refuses non-semver tags and already-published versions.
  • On any failure: deployment marked failure, Slack notified, worktree removed.
  • shellcheck clean.

@zanjonke
zanjonke merged commit 2f3a6f1 into main Aug 6, 2026
2 of 3 checks passed
@zanjonke
zanjonke deleted the ci/deploy-script branch August 6, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant