runRelease
uses node:path
Runs tcm release.
import { atprotoSession } from "#codebase/tcmts/atproto"; import type { OAuthSession } from "#codebase/tcmts/atproto"; import { ANNOUNCE_SCOPE, announceAndTell, announceSources } from "#codebase/tcmts/cli/announce"; import { routeRelease } from "#codebase/tcmts/cli/commands"; import { author } from "#codebase/tcmts/cli/contributions"; import { execute, printCheck, releaseAt, releaseSpec, when } from "#codebase/tcmts/cli/main"; import { findPackage, packagesIn } from "#codebase/tcmts/cli/manifests"; import { loadMirror, recordRelease, releaseCommit } from "#codebase/tcmts/cli/mirror"; import { blockers, contributionsOn, generatedNotes, MARKER, planRelease, reasonFor, releasePackage, writeDraft, } from "#codebase/tcmts/cli/releases"; import type { Context } from "#codebase/tcmts/cli/run"; import { bold, dim, green, red } from "#codebase/tcmts/cli/style"; import { listRemotes } from "#codebase/tcmts/cli/sync"; import { choose, UsageError } from "#codebase/tcmts/cli/ui"; import { shortHash } from "#codebase/tcmts/core/hash"; import { parse } from "@bomb.sh/router"; import path_1 from "node:path"; export async function runRelease({ cb, cmd, rest, cwd }: Context): Promise<number> { const r = execute(cmd, parse(routeRelease(), { argv: rest })); if (r.route === "/view") { const spec = r.model.release ?? (await choose( "release view <package>@<version>", "Which release?", cb.store.releases().map((x) => ({ value: `${x.package}@${x.version}`, label: `${x.package}@${x.version}`, hint: when(x.ts), })), false, )); const rel = releaseAt(cb, spec); console.log(rel.notes.replace(`${MARKER}\n\n`, "").trimEnd()); return 0; } if (r.route === "/check") { const plan = planRelease(cb, r.model.package, undefined, true); printCheck(plan); // (and whether releasing it would be refused, as it stands) const rows = cb.store.names(); const blocked = blockers(cb, plan.pkg, packagesIn(cb, rows), rows); if (!blocked) return 0; console.log(red(`not released as it stands: ${blocked}`)); return 1; } const m = r.model; const { name, version } = releaseSpec(m.package); if (m.draft) { const plan = planRelease(cb, name, version, m.force); const file = writeDraft( cb, plan, generatedNotes(cb, plan, [ ...cb.store.contributions(), ...(await contributionsOn(cb, m.remote)), ]), ); console.log( `wrote ${path_1.relative(cwd, file)} (${plan.pkg.name}'s next release, ${plan.version} as things stand): write what it's about above the marker, then \`tcm release ${plan.pkg.name}\`; the changes below the marker are regenerated`, ); return 0; } // announcing: where it's fetched from and who announces it are settled first, so a release isn't made and then // left unannounced for want of them let announcing: { sources: string[]; session: OAuthSession } | undefined; if (m.announce) { const pkg = name ?? findPackage(packagesIn(cb, cb.store.names()), undefined).name; const sources = announceSources(cb, pkg, m.source); announcing = { sources, session: await atprotoSession({ who: m.as, scope: ANNOUNCE_SCOPE, why: `announcing ${pkg} writes a record to your AT Protocol repository`, }), }; const existing = version === undefined ? undefined : cb.store.release(pkg, version); if (existing) { await announceAndTell(cb, existing, announcing); return 0; } } else if (m.source.length || m.as !== undefined) throw new UsageError("--source and --as say how to announce: give --announce too"); // a mirrored codebase's releases are kept with its files, in git: made from a commit, so they can be made again const mirror = loadMirror(cb); let commit: string | undefined; try { commit = mirror && releaseCommit(mirror); } catch (e) { throw new UsageError((e as Error).message); } const { release: rel, plan } = await releasePackage(cb, { name, version, notesFile: m.notes === undefined ? undefined : path_1.resolve(cwd, m.notes), remote: m.remote, force: m.force, author: author(), }); console.log( `${green("released")} ${bold(`${rel.package}@${rel.version}`)} ${dim(`as ${shortHash(rel.causal)}${plan.prev ? `, after ${plan.prev.version}` : ""}: ${reasonFor(plan)}`)}\n`, ); console.log(rel.notes.replace(`${MARKER}\n\n`, "").trimEnd()); if (mirror && commit) { recordRelease(mirror, { package: rel.package, version: rel.version, commit, notes: rel.notes, author: rel.author, ts: rel.ts, }); console.log( dim( `\n recorded in ${path_1.relative(cwd, path_1.join(mirror.dir, "tcm-releases.json"))}, from commit ${commit.slice(0, 8)}: commit it, and the release can be made again from git`, ), ); } if (announcing) { console.log(); try { await announceAndTell(cb, rel, announcing); } catch (e) { console.log( `${rel.package}@${rel.version} is released, but not announced: ${(e as Error).message}\n ${dim(`\`tcm release ${rel.package}@${rel.version} --announce\` announces it`)}`, ); return 1; } } else if (listRemotes(cb).length) console.log(dim(`\n \`tcm push\` publishes it`)); return 0; }
uses
- tcmts.atproto.OAuthSession
- tcmts.atproto.atprotoSession
- tcmts.cli.announce.ANNOUNCE_SCOPE
- tcmts.cli.announce.announceAndTell
- tcmts.cli.announce.announceSources
- tcmts.cli.commands.routeRelease
- tcmts.cli.contributions.author
- tcmts.cli.main.execute
- tcmts.cli.main.printCheck
- tcmts.cli.main.releaseAt
- tcmts.cli.main.releaseSpec
- tcmts.cli.main.when
- tcmts.cli.manifests.findPackage
- tcmts.cli.manifests.packagesIn
- tcmts.cli.mirror.loadMirror
- tcmts.cli.mirror.recordRelease
- tcmts.cli.mirror.releaseCommit
- tcmts.cli.releases.MARKER
- tcmts.cli.releases.blockers
- tcmts.cli.releases.contributionsOn
- tcmts.cli.releases.generatedNotes
- tcmts.cli.releases.planRelease
- tcmts.cli.releases.reasonFor
- tcmts.cli.releases.releasePackage
- tcmts.cli.releases.writeDraft
- tcmts.cli.run.Context
- tcmts.cli.style.bold
- tcmts.cli.style.dim
- tcmts.cli.style.green
- tcmts.cli.style.red
- tcmts.cli.sync.listRemotes
- tcmts.cli.ui.UsageError
- tcmts.cli.ui.choose
- tcmts.core.hash.shortHash