Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0
- run: bun install --frozen-lockfile
# npm publish drops a `bin` whose file is missing before prepublishOnly runs, so dist/
# must exist up front or the tarball ships without the `changeset` command.
- run: bun run build
# With changesets pending, opens or updates the "Version Packages" PR; once it is
# merged, publishes. npm authenticates through trusted publishing (OIDC).
- uses: changesets/action@ae32849d5ba541f9ae29e40e22a623bc13562f51 # v2.1.2
Expand Down
37 changes: 25 additions & 12 deletions scripts/publish.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* The `publish-script` of `.github/workflows/release.yml`: publishes the current version when npm
* does not have it yet, tags it, and reports the tag through `CHANGESETS_OUTPUT` so
* changesets/action pushes it and cuts the GitHub release.
* does not have it yet, tags it when the tag is missing (also for a version published by hand), and
* reports the tag through `CHANGESETS_OUTPUT` so changesets/action pushes it and cuts the GitHub release.
*/
import { NodeRuntime, NodeServices } from "@effect/platform-node"
import { Config, Console, Effect, FileSystem, Option, Schema } from "effect"
Expand All @@ -18,19 +18,32 @@ const program = Effect.gen(function* () {
const { name, version } = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Manifest))(
yield* fs.readFileString("package.json"),
)
const tag = `${name}@${version}`
const published = yield* run("npm", ["view", `${name}@${version}`, "version"], ".")
if (published.stdout.trim() === version) {
return yield* Console.log(`${name}@${version} is already on npm.`)
const publishNow = published.stdout.trim() !== version
if (publishNow) {
const publish = yield* run("npm", ["publish", "--provenance", "--access", "public"], ".")
yield* Console.log(publish.stdout)
if (publish.exitCode !== 0) {
return yield* new ReleaseError({ message: `npm publish failed:\n${publish.stderr}` })
}
} else {
yield* Console.log(`${tag} is already on npm.`)
}
const publish = yield* run("npm", ["publish", "--provenance", "--access", "public"], ".")
yield* Console.log(publish.stdout)
if (publish.exitCode !== 0) {
return yield* new ReleaseError({ message: `npm publish failed:\n${publish.stderr}` })
// Exit code 2 means the remote has no such tag.
const remoteTag = yield* run("git", ["ls-remote", "--exit-code", "--tags", "origin", `refs/tags/${tag}`], ".")
if (remoteTag.exitCode !== 0 && remoteTag.exitCode !== 2) {
return yield* new ReleaseError({ message: `git ls-remote failed:\n${remoteTag.stderr}` })
}
const tagMissing = remoteTag.exitCode === 2
if (!publishNow && !tagMissing) return yield* Console.log(`${tag} is already tagged.`)
// A retry in the same checkout reuses the tag an earlier run created but never pushed.
const localTag = yield* run("git", ["rev-parse", "--quiet", "--verify", `refs/tags/${tag}`], ".")
if (tagMissing && localTag.exitCode !== 0) {
const tagged = yield* run("git", ["tag", tag], ".")
if (tagged.exitCode !== 0) return yield* new ReleaseError({ message: `git tag failed:\n${tagged.stderr}` })
yield* Console.log(`New tag: ${tag}`)
}
const tag = `${name}@${version}`
const tagged = yield* run("git", ["tag", "-a", tag, "-m", tag], ".")
if (tagged.exitCode !== 0) return yield* new ReleaseError({ message: `git tag failed:\n${tagged.stderr}` })
yield* Console.log(`New tag: ${tag}`)
const output = yield* Config.option(Config.String("CHANGESETS_OUTPUT"))
if (Option.isSome(output)) {
yield* fs.writeFileString(output.value, `${JSON.stringify({ type: "git-tag", tag, packageName: name })}\n`, {
Expand Down
Loading