@mlaursen/release-script 0.0.7 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -40,6 +40,12 @@ interface GetPendingReleasesOptions {
40
40
  * @defaultValue `{}`
41
41
  */
42
42
  packagePaths?: Record<string, string>;
43
+ /**
44
+ * A set of packages that should never attempt to create a github release.
45
+ *
46
+ * @defaultValue `new Set()`
47
+ */
48
+ disableGithubReleasePackages?: ReadonlySet<string>;
43
49
  }
44
50
 
45
51
  interface ReleaseOptions extends ConfigurableCreateReleaseOptions, GetPendingReleasesOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sources":["../types/createRelease.d.ts","../types/getPendingReleases.d.ts","../types/release.d.ts"],"sourcesContent":["export interface ConfigurableCreateReleaseOptions {\n repo: string;\n /**\n * @defaultValue `\"mlaursen\"`\n */\n owner?: string;\n /**\n * The `.env` file to load to get the {@link tokenName} environment variable.\n *\n * @defaultValue `\".env.local\"`\n */\n envPath?: string;\n /**\n * @defaultValue `\"GITHUB_RELEASE_TOKEN\"`\n */\n tokenName?: string;\n}\nexport interface CreateReleaseOptions extends ConfigurableCreateReleaseOptions {\n body: string;\n override?: boolean;\n tagName: string;\n prerelease: boolean;\n}\nexport declare function createRelease(options: CreateReleaseOptions): Promise<void>;\n","export interface GetPendingReleasesOptions {\n /**\n * This should be a record of package names to paths for monorepos.\n *\n * @example Monorepo Setup\n * ```tsx\n * packagePaths: {\n * \"@react-md/core\": \"./packages/core\",\n * \"docs\": \"./apps/docs\"\n * },\n * ```\n *\n * If this is omitted or not matched, it will default to `\".\"`\n *\n * @defaultValue `{}`\n */\n packagePaths?: Record<string, string>;\n}\nexport interface PendingRelease {\n tagName: string;\n body: string;\n}\nexport declare function getPendingReleases(options: GetPendingReleasesOptions): Promise<readonly PendingRelease[]>;\n","import { type ConfigurableCreateReleaseOptions } from \"./createRelease.js\";\nimport { type GetPendingReleasesOptions } from \"./getPendingReleases.js\";\nexport interface ReleaseOptions extends ConfigurableCreateReleaseOptions, GetPendingReleasesOptions {\n /**\n * @defaultValue `!buildCommand`\n */\n skipBuild?: boolean;\n /**\n * @defaultValue `\"clean\"`\n */\n cleanCommand?: string;\n /**\n * @defaultValue `\"build\"`\n */\n buildCommand?: string;\n /**\n * @defaultValue `\"build(version): version package\"`\n */\n versionMessage?: string;\n}\nexport declare function release(options: ReleaseOptions): Promise<void>;\n"],"names":[],"mappings":"AAAO,UAAA,gCAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,UAAA,oBAAA,SAAA,gCAAA;AACP;AACA;AACA;AACA;AACA;AACO,iBAAA,aAAA,UAAA,oBAAA,GAAA,OAAA;;ACvBA,UAAA,yBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;;ACfO,UAAA,cAAA,SAAA,gCAAA,EAAA,yBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,UAAA,cAAA,GAAA,OAAA;;;;"}
1
+ {"version":3,"file":"index.d.ts","sources":["../types/createRelease.d.ts","../types/getPendingReleases.d.ts","../types/release.d.ts"],"sourcesContent":["export interface ConfigurableCreateReleaseOptions {\n repo: string;\n /**\n * @defaultValue `\"mlaursen\"`\n */\n owner?: string;\n /**\n * The `.env` file to load to get the {@link tokenName} environment variable.\n *\n * @defaultValue `\".env.local\"`\n */\n envPath?: string;\n /**\n * @defaultValue `\"GITHUB_RELEASE_TOKEN\"`\n */\n tokenName?: string;\n}\nexport interface CreateReleaseOptions extends ConfigurableCreateReleaseOptions {\n body: string;\n override?: boolean;\n tagName: string;\n prerelease: boolean;\n}\nexport declare function createRelease(options: CreateReleaseOptions): Promise<void>;\n","export interface GetPendingReleasesOptions {\n /**\n * This should be a record of package names to paths for monorepos.\n *\n * @example Monorepo Setup\n * ```tsx\n * packagePaths: {\n * \"@react-md/core\": \"./packages/core\",\n * \"docs\": \"./apps/docs\"\n * },\n * ```\n *\n * If this is omitted or not matched, it will default to `\".\"`\n *\n * @defaultValue `{}`\n */\n packagePaths?: Record<string, string>;\n /**\n * A set of packages that should never attempt to create a github release.\n *\n * @defaultValue `new Set()`\n */\n disableGithubReleasePackages?: ReadonlySet<string>;\n}\nexport interface PendingRelease {\n tagName: string;\n body: string;\n}\nexport declare function getPendingReleases(options: GetPendingReleasesOptions): Promise<readonly PendingRelease[]>;\n","import { type ConfigurableCreateReleaseOptions } from \"./createRelease.js\";\nimport { type GetPendingReleasesOptions } from \"./getPendingReleases.js\";\nexport interface ReleaseOptions extends ConfigurableCreateReleaseOptions, GetPendingReleasesOptions {\n /**\n * @defaultValue `!buildCommand`\n */\n skipBuild?: boolean;\n /**\n * @defaultValue `\"clean\"`\n */\n cleanCommand?: string;\n /**\n * @defaultValue `\"build\"`\n */\n buildCommand?: string;\n /**\n * @defaultValue `\"build(version): version package\"`\n */\n versionMessage?: string;\n}\nexport declare function release(options: ReleaseOptions): Promise<void>;\n"],"names":[],"mappings":"AAAO,UAAA,gCAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,UAAA,oBAAA,SAAA,gCAAA;AACP;AACA;AACA;AACA;AACA;AACO,iBAAA,aAAA,UAAA,oBAAA,GAAA,OAAA;;ACvBA,UAAA,yBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,WAAA;AACA;;ACrBO,UAAA,cAAA,SAAA,gCAAA,EAAA,yBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,UAAA,cAAA,GAAA,OAAA;;;;"}
package/dist/index.mjs CHANGED
@@ -65,17 +65,19 @@ async function getPackageManager() {
65
65
  return "npm";
66
66
  }
67
67
  if (typeof packageJson.packageManager === "string") {
68
- const mgr = packageJson.packageManagerreplace(/@.+/, "");
68
+ const mgr = packageJson.packageManager.replace(/@.+/, "");
69
69
  if (mgr === "pnpm" || mgr === "yarn" || mgr === "npm") {
70
70
  return mgr;
71
71
  }
72
- throw new Error(`Unsupported package mananger "${mgr}" in package.json`);
72
+ throw new Error(`Unsupported package manager "${mgr}" in package.json`);
73
73
  }
74
74
  throw new Error("Unable to find a package manager");
75
75
  }
76
76
 
77
+ const LOCAL_TAGS_COMMAND = "git tag --sort=-creatordate";
78
+ const REMOTE_TAGS_COMMAND = "git ls-remote --tags origin";
77
79
  function getTags(local) {
78
- const command = local ? "git tag --sort=-creatordate" : "git ls-remote --tags origin";
80
+ const command = local ? LOCAL_TAGS_COMMAND : REMOTE_TAGS_COMMAND;
79
81
  const tags = execSync(command).toString().trim();
80
82
  const lines = tags.split(/\r?\n/);
81
83
  if (local) {
@@ -92,23 +94,26 @@ function getUnpushedTags() {
92
94
  }
93
95
 
94
96
  async function getPendingReleases(options) {
95
- const { packagePaths = {} } = options;
97
+ const { packagePaths = {}, disableGithubReleasePackages = new Set() } = options;
96
98
  const unpushedTags = getUnpushedTags();
97
99
  if (unpushedTags.length === 0) {
98
100
  throw new Error("Unable to find any pending releases");
99
101
  }
100
102
  const pending = [];
101
103
  for (const unpushedTag of unpushedTags){
102
- if (!await confirm({
104
+ const name = unpushedTag.replace(/@\d+.+$/, "");
105
+ if (disableGithubReleasePackages.has(name) || !await confirm({
103
106
  message: `Include ${unpushedTag} in the release?`
104
107
  })) {
105
108
  continue;
106
109
  }
107
- const name = unpushedTag.replace(/@\d+.+$/, "");
108
- const path = await input({
109
- message: `${name} CHANGELOG exists at:`,
110
- default: packagePaths[name] ?? "."
111
- });
110
+ let path = packagePaths[name];
111
+ if (!path) {
112
+ path = await input({
113
+ message: `${name} CHANGELOG exists at:`,
114
+ default: "."
115
+ });
116
+ }
112
117
  const changelog = await readFile(resolve(process.cwd(), path, "CHANGELOG.md"), "utf8");
113
118
  let body = "";
114
119
  let isTracking = false;
@@ -129,6 +134,9 @@ async function getPendingReleases(options) {
129
134
  tagName: unpushedTag
130
135
  });
131
136
  }
137
+ if (pending.length === 0) {
138
+ throw new Error("No pending releases were confirmed");
139
+ }
132
140
  return pending;
133
141
  }
134
142
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/createRelease.ts","../src/continueRelease.ts","../src/getPackageManager.ts","../src/getUnpushedTags.ts","../src/getPendingReleases.ts","../src/release.ts"],"sourcesContent":["import confirm from \"@inquirer/confirm\";\nimport { Octokit } from \"@octokit/core\";\nimport dotenv from \"dotenv\";\n\nexport interface ConfigurableCreateReleaseOptions {\n repo: string;\n\n /**\n * @defaultValue `\"mlaursen\"`\n */\n owner?: string;\n\n /**\n * The `.env` file to load to get the {@link tokenName} environment variable.\n *\n * @defaultValue `\".env.local\"`\n */\n envPath?: string;\n\n /**\n * @defaultValue `\"GITHUB_RELEASE_TOKEN\"`\n */\n tokenName?: string;\n}\n\nexport interface CreateReleaseOptions extends ConfigurableCreateReleaseOptions {\n body: string;\n override?: boolean;\n tagName: string;\n prerelease: boolean;\n}\n\nexport async function createRelease(\n options: CreateReleaseOptions\n): Promise<void> {\n const {\n body,\n override,\n owner = \"mlaursen\",\n repo,\n prerelease,\n envPath = \".env.local\",\n tagName,\n tokenName = \"GITHUB_RELEASE_TOKEN\",\n } = options;\n\n dotenv.config({ path: envPath, override, quiet: true });\n const octokit = new Octokit({ auth: process.env[tokenName] });\n try {\n const response = await octokit.request(\n \"POST /repos/{owner}/{repo}/releases\",\n {\n owner,\n repo,\n tag_name: tagName,\n body,\n prerelease,\n }\n );\n\n console.log(`Created release: ${response.data.html_url}`);\n } catch (error) {\n console.error(error);\n\n console.log();\n console.log(\n \"The npm token is most likely expired or never created. Update the `.env.local` to include the latest GITHUB_TOKEN\"\n );\n console.log(\n \"Regenerate the token: https://github.com/settings/personal-access-tokens\"\n );\n if (\n !(await confirm({ message: \"Try creating the Github release again?\" }))\n ) {\n throw new Error(\"Unable to create a Github release\");\n }\n\n return createRelease({ ...options, override: true });\n }\n}\n","import confirm from \"@inquirer/confirm\";\n\nexport async function continueRelease(): Promise<void> {\n const confirmed = await confirm({ message: \"Continue the release?\" });\n if (!confirmed) {\n throw new Error(\"Release cancelled\");\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\n\nexport type PackageManager = \"npm\" | \"yarn\" | \"pnpm\";\n\nexport async function getPackageManager(): Promise<PackageManager> {\n const rawPackageJson = await readFile(\n resolve(process.cwd(), \"package.json\"),\n \"utf8\"\n );\n const packageJson = JSON.parse(rawPackageJson);\n\n if (typeof packageJson.volta === \"object\" && packageJson.volta) {\n const { volta } = packageJson;\n if (\"pnpm\" in volta) {\n return \"pnpm\";\n }\n\n if (\"yarn\" in volta) {\n return \"yarn\";\n }\n\n return \"npm\";\n }\n\n if (typeof packageJson.packageManager === \"string\") {\n const mgr = packageJson.packageManagerreplace(/@.+/, \"\");\n\n if (mgr === \"pnpm\" || mgr === \"yarn\" || mgr === \"npm\") {\n return mgr;\n }\n\n throw new Error(`Unsupported package mananger \"${mgr}\" in package.json`);\n }\n\n throw new Error(\"Unable to find a package manager\");\n}\n","import { execSync } from \"node:child_process\";\n\nfunction getTags(local: boolean): Set<string> {\n const command = local\n ? \"git tag --sort=-creatordate\"\n : \"git ls-remote --tags origin\";\n const tags = execSync(command).toString().trim();\n const lines = tags.split(/\\r?\\n/);\n if (local) {\n return new Set(lines);\n }\n\n return new Set(\n lines.map((line) => line.replace(/^.+refs\\/tags\\//, \"\").replace(\"^{}\", \"\"))\n );\n}\n\nexport function getUnpushedTags(): readonly string[] {\n const localTags = getTags(true);\n const pushedTags = getTags(false);\n\n return [...localTags.difference(pushedTags)];\n}\n","import confirm from \"@inquirer/confirm\";\nimport input from \"@inquirer/input\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\n\nimport { getUnpushedTags } from \"./getUnpushedTags.js\";\n\nexport interface GetPendingReleasesOptions {\n /**\n * This should be a record of package names to paths for monorepos.\n *\n * @example Monorepo Setup\n * ```tsx\n * packagePaths: {\n * \"@react-md/core\": \"./packages/core\",\n * \"docs\": \"./apps/docs\"\n * },\n * ```\n *\n * If this is omitted or not matched, it will default to `\".\"`\n *\n * @defaultValue `{}`\n */\n packagePaths?: Record<string, string>;\n}\n\nexport interface PendingRelease {\n tagName: string;\n body: string;\n}\n\nexport async function getPendingReleases(\n options: GetPendingReleasesOptions\n): Promise<readonly PendingRelease[]> {\n const { packagePaths = {} } = options;\n const unpushedTags = getUnpushedTags();\n if (unpushedTags.length === 0) {\n throw new Error(\"Unable to find any pending releases\");\n }\n\n const pending: PendingRelease[] = [];\n for (const unpushedTag of unpushedTags) {\n if (\n !(await confirm({ message: `Include ${unpushedTag} in the release?` }))\n ) {\n continue;\n }\n\n const name = unpushedTag.replace(/@\\d+.+$/, \"\");\n const path = await input({\n message: `${name} CHANGELOG exists at:`,\n default: packagePaths[name] ?? \".\",\n });\n\n const changelog = await readFile(\n resolve(process.cwd(), path, \"CHANGELOG.md\"),\n \"utf8\"\n );\n\n let body = \"\";\n let isTracking = false;\n const lines = changelog.split(/\\r?\\n/);\n for (const line of lines) {\n if (line.startsWith(\"## \")) {\n if (isTracking) {\n break;\n }\n\n isTracking = true;\n body = line;\n } else if (isTracking) {\n body += `\\n${line}`;\n }\n }\n\n pending.push({\n body,\n tagName: unpushedTag,\n });\n }\n\n return pending;\n}\n","import { type ExecSyncOptions, execSync } from \"node:child_process\";\n\nimport { continueRelease } from \"./continueRelease.js\";\nimport {\n type ConfigurableCreateReleaseOptions,\n createRelease,\n} from \"./createRelease.js\";\nimport { getPackageManager } from \"./getPackageManager.js\";\nimport {\n type GetPendingReleasesOptions,\n getPendingReleases,\n} from \"./getPendingReleases.js\";\n\nconst exec = (command: string, opts?: ExecSyncOptions): void => {\n console.log(command);\n execSync(command, opts);\n};\n\nexport interface ReleaseOptions\n extends ConfigurableCreateReleaseOptions, GetPendingReleasesOptions {\n /**\n * @defaultValue `!buildCommand`\n */\n skipBuild?: boolean;\n\n /**\n * @defaultValue `\"clean\"`\n */\n cleanCommand?: string;\n\n /**\n * @defaultValue `\"build\"`\n */\n buildCommand?: string;\n\n /**\n * @defaultValue `\"build(version): version package\"`\n */\n versionMessage?: string;\n}\n\nexport async function release(options: ReleaseOptions): Promise<void> {\n const {\n owner,\n repo,\n envPath,\n cleanCommand = \"clean\",\n buildCommand = \"build\",\n skipBuild = !buildCommand,\n versionMessage = \"build(version): version package\",\n } = options;\n\n const pkgManager = await getPackageManager();\n\n if (!skipBuild) {\n exec(`${pkgManager} ${cleanCommand}`);\n exec(`${pkgManager} ${buildCommand}`);\n }\n await continueRelease();\n\n exec(\"pnpm changeset version\", { stdio: \"inherit\" });\n exec(\"git add -u\");\n await continueRelease();\n\n exec(`git commit -m \"${versionMessage}\"`);\n exec(`${pkgManager} changeset publish`, { stdio: \"inherit\" });\n const pendingReleases = await getPendingReleases(options);\n\n exec(\"git push --follow-tags\");\n\n for (const release of pendingReleases) {\n await createRelease({\n owner,\n repo,\n body: release.body,\n tagName: release.tagName,\n envPath,\n prerelease: /-(alpha|next|beta)\\.\\d+$/.test(release.tagName),\n });\n }\n}\n"],"names":["createRelease","options","body","override","owner","repo","prerelease","envPath","tagName","tokenName","dotenv","config","path","quiet","octokit","Octokit","auth","process","env","response","request","tag_name","console","log","data","html_url","error","confirm","message","Error","continueRelease","confirmed","getPackageManager","rawPackageJson","readFile","resolve","cwd","packageJson","JSON","parse","volta","packageManager","mgr","packageManagerreplace","getTags","local","command","tags","execSync","toString","trim","lines","split","Set","map","line","replace","getUnpushedTags","localTags","pushedTags","difference","getPendingReleases","packagePaths","unpushedTags","length","pending","unpushedTag","name","input","default","changelog","isTracking","startsWith","push","exec","opts","release","cleanCommand","buildCommand","skipBuild","versionMessage","pkgManager","stdio","pendingReleases","test"],"mappings":";;;;;;;;AAgCO,eAAeA,cACpBC,OAA6B,EAAA;IAE7B,MAAM,EACJC,IAAI,EACJC,QAAQ,EACRC,KAAAA,GAAQ,UAAU,EAClBC,IAAI,EACJC,UAAU,EACVC,OAAAA,GAAU,YAAY,EACtBC,OAAO,EACPC,SAAAA,GAAY,sBAAsB,EACnC,GAAGR,OAAAA;AAEJS,IAAAA,MAAAA,CAAOC,MAAM,CAAC;QAAEC,IAAAA,EAAML,OAAAA;AAASJ,QAAAA,QAAAA;QAAUU,KAAAA,EAAO;AAAK,KAAA,CAAA;IACrD,MAAMC,OAAAA,GAAU,IAAIC,OAAAA,CAAQ;QAAEC,IAAAA,EAAMC,OAAAA,CAAQC,GAAG,CAACT,SAAAA;AAAW,KAAA,CAAA;IAC3D,IAAI;AACF,QAAA,MAAMU,QAAAA,GAAW,MAAML,OAAAA,CAAQM,OAAO,CACpC,qCAAA,EACA;AACEhB,YAAAA,KAAAA;AACAC,YAAAA,IAAAA;YACAgB,QAAAA,EAAUb,OAAAA;AACVN,YAAAA,IAAAA;AACAI,YAAAA;AACF,SAAA,CAAA;QAGFgB,OAAAA,CAAQC,GAAG,CAAC,CAAC,iBAAiB,EAAEJ,QAAAA,CAASK,IAAI,CAACC,QAAQ,CAAA,CAAE,CAAA;AAC1D,IAAA,CAAA,CAAE,OAAOC,KAAAA,EAAO;AACdJ,QAAAA,OAAAA,CAAQI,KAAK,CAACA,KAAAA,CAAAA;AAEdJ,QAAAA,OAAAA,CAAQC,GAAG,EAAA;AACXD,QAAAA,OAAAA,CAAQC,GAAG,CACT,mHAAA,CAAA;AAEFD,QAAAA,OAAAA,CAAQC,GAAG,CACT,0EAAA,CAAA;QAEF,IACE,CAAE,MAAMI,OAAAA,CAAQ;YAAEC,OAAAA,EAAS;SAAyC,CAAA,EACpE;AACA,YAAA,MAAM,IAAIC,KAAAA,CAAM,mCAAA,CAAA;AAClB,QAAA;AAEA,QAAA,OAAO7B,aAAAA,CAAc;AAAE,YAAA,GAAGC,OAAO;YAAEE,QAAAA,EAAU;AAAK,SAAA,CAAA;AACpD,IAAA;AACF;;AC7EO,eAAe2B,eAAAA,GAAAA;IACpB,MAAMC,SAAAA,GAAY,MAAMJ,OAAAA,CAAQ;QAAEC,OAAAA,EAAS;AAAwB,KAAA,CAAA;AACnE,IAAA,IAAI,CAACG,SAAAA,EAAW;AACd,QAAA,MAAM,IAAIF,KAAAA,CAAM,mBAAA,CAAA;AAClB,IAAA;AACF;;ACFO,eAAeG,iBAAAA,GAAAA;AACpB,IAAA,MAAMC,iBAAiB,MAAMC,QAAAA,CAC3BC,QAAQlB,OAAAA,CAAQmB,GAAG,IAAI,cAAA,CAAA,EACvB,MAAA,CAAA;IAEF,MAAMC,WAAAA,GAAcC,IAAAA,CAAKC,KAAK,CAACN,cAAAA,CAAAA;AAE/B,IAAA,IAAI,OAAOI,WAAAA,CAAYG,KAAK,KAAK,QAAA,IAAYH,WAAAA,CAAYG,KAAK,EAAE;QAC9D,MAAM,EAAEA,KAAK,EAAE,GAAGH,WAAAA;AAClB,QAAA,IAAI,UAAUG,KAAAA,EAAO;YACnB,OAAO,MAAA;AACT,QAAA;AAEA,QAAA,IAAI,UAAUA,KAAAA,EAAO;YACnB,OAAO,MAAA;AACT,QAAA;QAEA,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,IAAI,OAAOH,WAAAA,CAAYI,cAAc,KAAK,QAAA,EAAU;AAClD,QAAA,MAAMC,GAAAA,GAAML,WAAAA,CAAYM,qBAAqB,CAAC,KAAA,EAAO,EAAA,CAAA;AAErD,QAAA,IAAID,GAAAA,KAAQ,MAAA,IAAUA,GAAAA,KAAQ,MAAA,IAAUA,QAAQ,KAAA,EAAO;YACrD,OAAOA,GAAAA;AACT,QAAA;AAEA,QAAA,MAAM,IAAIb,KAAAA,CAAM,CAAC,8BAA8B,EAAEa,GAAAA,CAAI,iBAAiB,CAAC,CAAA;AACzE,IAAA;AAEA,IAAA,MAAM,IAAIb,KAAAA,CAAM,kCAAA,CAAA;AAClB;;AClCA,SAASe,QAAQC,KAAc,EAAA;IAC7B,MAAMC,OAAAA,GAAUD,QACZ,6BAAA,GACA,6BAAA;AACJ,IAAA,MAAME,IAAAA,GAAOC,QAAAA,CAASF,OAAAA,CAAAA,CAASG,QAAQ,GAAGC,IAAI,EAAA;IAC9C,MAAMC,KAAAA,GAAQJ,IAAAA,CAAKK,KAAK,CAAC,OAAA,CAAA;AACzB,IAAA,IAAIP,KAAAA,EAAO;AACT,QAAA,OAAO,IAAIQ,GAAAA,CAAIF,KAAAA,CAAAA;AACjB,IAAA;AAEA,IAAA,OAAO,IAAIE,GAAAA,CACTF,KAAAA,CAAMG,GAAG,CAAC,CAACC,IAAAA,GAASA,IAAAA,CAAKC,OAAO,CAAC,iBAAA,EAAmB,EAAA,CAAA,CAAIA,OAAO,CAAC,KAAA,EAAO,EAAA,CAAA,CAAA,CAAA;AAE3E;AAEO,SAASC,eAAAA,GAAAA;AACd,IAAA,MAAMC,YAAYd,OAAAA,CAAQ,IAAA,CAAA;AAC1B,IAAA,MAAMe,aAAaf,OAAAA,CAAQ,KAAA,CAAA;IAE3B,OAAO;AAAIc,QAAAA,GAAAA,SAAAA,CAAUE,UAAU,CAACD,UAAAA;AAAY,KAAA;AAC9C;;ACSO,eAAeE,mBACpB5D,OAAkC,EAAA;AAElC,IAAA,MAAM,EAAE6D,YAAAA,GAAe,EAAE,EAAE,GAAG7D,OAAAA;AAC9B,IAAA,MAAM8D,YAAAA,GAAeN,eAAAA,EAAAA;IACrB,IAAIM,YAAAA,CAAaC,MAAM,KAAK,CAAA,EAAG;AAC7B,QAAA,MAAM,IAAInC,KAAAA,CAAM,qCAAA,CAAA;AAClB,IAAA;AAEA,IAAA,MAAMoC,UAA4B,EAAE;IACpC,KAAK,MAAMC,eAAeH,YAAAA,CAAc;QACtC,IACE,CAAE,MAAMpC,OAAAA,CAAQ;AAAEC,YAAAA,OAAAA,EAAS,CAAC,QAAQ,EAAEsC,WAAAA,CAAY,gBAAgB;SAAE,CAAA,EACpE;AACA,YAAA;AACF,QAAA;AAEA,QAAA,MAAMC,IAAAA,GAAOD,WAAAA,CAAYV,OAAO,CAAC,SAAA,EAAW,EAAA,CAAA;QAC5C,MAAM5C,IAAAA,GAAO,MAAMwD,KAAAA,CAAM;YACvBxC,OAAAA,EAAS,CAAA,EAAGuC,IAAAA,CAAK,qBAAqB,CAAC;YACvCE,OAAAA,EAASP,YAAY,CAACK,IAAAA,CAAK,IAAI;AACjC,SAAA,CAAA;QAEA,MAAMG,SAAAA,GAAY,MAAMpC,QAAAA,CACtBC,OAAAA,CAAQlB,QAAQmB,GAAG,EAAA,EAAIxB,MAAM,cAAA,CAAA,EAC7B,MAAA,CAAA;AAGF,QAAA,IAAIV,IAAAA,GAAO,EAAA;AACX,QAAA,IAAIqE,UAAAA,GAAa,KAAA;QACjB,MAAMpB,KAAAA,GAAQmB,SAAAA,CAAUlB,KAAK,CAAC,OAAA,CAAA;QAC9B,KAAK,MAAMG,QAAQJ,KAAAA,CAAO;YACxB,IAAII,IAAAA,CAAKiB,UAAU,CAAC,KAAA,CAAA,EAAQ;AAC1B,gBAAA,IAAID,UAAAA,EAAY;AACd,oBAAA;AACF,gBAAA;gBAEAA,UAAAA,GAAa,IAAA;gBACbrE,IAAAA,GAAOqD,IAAAA;AACT,YAAA,CAAA,MAAO,IAAIgB,UAAAA,EAAY;gBACrBrE,IAAAA,IAAQ,CAAC,EAAE,EAAEqD,IAAAA,CAAAA,CAAM;AACrB,YAAA;AACF,QAAA;AAEAU,QAAAA,OAAAA,CAAQQ,IAAI,CAAC;AACXvE,YAAAA,IAAAA;YACAM,OAAAA,EAAS0D;AACX,SAAA,CAAA;AACF,IAAA;IAEA,OAAOD,OAAAA;AACT;;ACrEA,MAAMS,IAAAA,GAAO,CAAC5B,OAAAA,EAAiB6B,IAAAA,GAAAA;AAC7BrD,IAAAA,OAAAA,CAAQC,GAAG,CAACuB,OAAAA,CAAAA;AACZE,IAAAA,QAAAA,CAASF,OAAAA,EAAS6B,IAAAA,CAAAA;AACpB,CAAA;AAyBO,eAAeC,QAAQ3E,OAAuB,EAAA;IACnD,MAAM,EACJG,KAAK,EACLC,IAAI,EACJE,OAAO,EACPsE,eAAe,OAAO,EACtBC,eAAe,OAAO,EACtBC,YAAY,CAACD,YAAY,EACzBE,cAAAA,GAAiB,iCAAiC,EACnD,GAAG/E,OAAAA;AAEJ,IAAA,MAAMgF,aAAa,MAAMjD,iBAAAA,EAAAA;AAEzB,IAAA,IAAI,CAAC+C,SAAAA,EAAW;AACdL,QAAAA,IAAAA,CAAK,CAAA,EAAGO,UAAAA,CAAW,CAAC,EAAEJ,YAAAA,CAAAA,CAAc,CAAA;AACpCH,QAAAA,IAAAA,CAAK,CAAA,EAAGO,UAAAA,CAAW,CAAC,EAAEH,YAAAA,CAAAA,CAAc,CAAA;AACtC,IAAA;IACA,MAAMhD,eAAAA,EAAAA;AAEN4C,IAAAA,IAAAA,CAAK,wBAAA,EAA0B;QAAEQ,KAAAA,EAAO;AAAU,KAAA,CAAA;IAClDR,IAAAA,CAAK,YAAA,CAAA;IACL,MAAM5C,eAAAA,EAAAA;AAEN4C,IAAAA,IAAAA,CAAK,CAAC,eAAe,EAAEM,cAAAA,CAAe,CAAC,CAAC,CAAA;AACxCN,IAAAA,IAAAA,CAAK,CAAA,EAAGO,UAAAA,CAAW,kBAAkB,CAAC,EAAE;QAAEC,KAAAA,EAAO;AAAU,KAAA,CAAA;IAC3D,MAAMC,eAAAA,GAAkB,MAAMtB,kBAAAA,CAAmB5D,OAAAA,CAAAA;IAEjDyE,IAAAA,CAAK,wBAAA,CAAA;IAEL,KAAK,MAAME,WAAWO,eAAAA,CAAiB;AACrC,QAAA,MAAMnF,aAAAA,CAAc;AAClBI,YAAAA,KAAAA;AACAC,YAAAA,IAAAA;AACAH,YAAAA,IAAAA,EAAM0E,QAAQ1E,IAAI;AAClBM,YAAAA,OAAAA,EAASoE,QAAQpE,OAAO;AACxBD,YAAAA,OAAAA;AACAD,YAAAA,UAAAA,EAAY,0BAAA,CAA2B8E,IAAI,CAACR,OAAAA,CAAQpE,OAAO;AAC7D,SAAA,CAAA;AACF,IAAA;AACF;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/createRelease.ts","../src/continueRelease.ts","../src/getPackageManager.ts","../src/getUnpushedTags.ts","../src/getPendingReleases.ts","../src/release.ts"],"sourcesContent":["import confirm from \"@inquirer/confirm\";\nimport { Octokit } from \"@octokit/core\";\nimport dotenv from \"dotenv\";\n\nexport interface ConfigurableCreateReleaseOptions {\n repo: string;\n\n /**\n * @defaultValue `\"mlaursen\"`\n */\n owner?: string;\n\n /**\n * The `.env` file to load to get the {@link tokenName} environment variable.\n *\n * @defaultValue `\".env.local\"`\n */\n envPath?: string;\n\n /**\n * @defaultValue `\"GITHUB_RELEASE_TOKEN\"`\n */\n tokenName?: string;\n}\n\nexport interface CreateReleaseOptions extends ConfigurableCreateReleaseOptions {\n body: string;\n override?: boolean;\n tagName: string;\n prerelease: boolean;\n}\n\nexport async function createRelease(\n options: CreateReleaseOptions\n): Promise<void> {\n const {\n body,\n override,\n owner = \"mlaursen\",\n repo,\n prerelease,\n envPath = \".env.local\",\n tagName,\n tokenName = \"GITHUB_RELEASE_TOKEN\",\n } = options;\n\n dotenv.config({ path: envPath, override, quiet: true });\n const octokit = new Octokit({ auth: process.env[tokenName] });\n try {\n const response = await octokit.request(\n \"POST /repos/{owner}/{repo}/releases\",\n {\n owner,\n repo,\n tag_name: tagName,\n body,\n prerelease,\n }\n );\n\n console.log(`Created release: ${response.data.html_url}`);\n } catch (error) {\n console.error(error);\n\n console.log();\n console.log(\n \"The npm token is most likely expired or never created. Update the `.env.local` to include the latest GITHUB_TOKEN\"\n );\n console.log(\n \"Regenerate the token: https://github.com/settings/personal-access-tokens\"\n );\n if (\n !(await confirm({ message: \"Try creating the Github release again?\" }))\n ) {\n throw new Error(\"Unable to create a Github release\");\n }\n\n return createRelease({ ...options, override: true });\n }\n}\n","import confirm from \"@inquirer/confirm\";\n\nexport async function continueRelease(): Promise<void> {\n const confirmed = await confirm({ message: \"Continue the release?\" });\n if (!confirmed) {\n throw new Error(\"Release cancelled\");\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\n\nexport type PackageManager = \"npm\" | \"yarn\" | \"pnpm\";\ninterface PartialPackageJson {\n volta?: Record<string, string>;\n packageManager?: string;\n}\n\nexport async function getPackageManager(): Promise<PackageManager> {\n const rawPackageJson = await readFile(\n resolve(process.cwd(), \"package.json\"),\n \"utf8\"\n );\n const packageJson = JSON.parse(rawPackageJson) as PartialPackageJson;\n\n if (typeof packageJson.volta === \"object\" && packageJson.volta) {\n const { volta } = packageJson;\n if (\"pnpm\" in volta) {\n return \"pnpm\";\n }\n\n if (\"yarn\" in volta) {\n return \"yarn\";\n }\n\n return \"npm\";\n }\n\n if (typeof packageJson.packageManager === \"string\") {\n const mgr = packageJson.packageManager.replace(/@.+/, \"\");\n\n if (mgr === \"pnpm\" || mgr === \"yarn\" || mgr === \"npm\") {\n return mgr;\n }\n\n throw new Error(`Unsupported package manager \"${mgr}\" in package.json`);\n }\n\n throw new Error(\"Unable to find a package manager\");\n}\n","import { execSync } from \"node:child_process\";\n\nexport const LOCAL_TAGS_COMMAND = \"git tag --sort=-creatordate\";\nexport const REMOTE_TAGS_COMMAND = \"git ls-remote --tags origin\";\n\nfunction getTags(local: boolean): Set<string> {\n const command = local ? LOCAL_TAGS_COMMAND : REMOTE_TAGS_COMMAND;\n const tags = execSync(command).toString().trim();\n const lines = tags.split(/\\r?\\n/);\n if (local) {\n return new Set(lines);\n }\n\n return new Set(\n lines.map((line) => line.replace(/^.+refs\\/tags\\//, \"\").replace(\"^{}\", \"\"))\n );\n}\n\nexport function getUnpushedTags(): readonly string[] {\n const localTags = getTags(true);\n const pushedTags = getTags(false);\n\n return [...localTags.difference(pushedTags)];\n}\n","import confirm from \"@inquirer/confirm\";\nimport input from \"@inquirer/input\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\n\nimport { getUnpushedTags } from \"./getUnpushedTags.js\";\n\nexport interface GetPendingReleasesOptions {\n /**\n * This should be a record of package names to paths for monorepos.\n *\n * @example Monorepo Setup\n * ```tsx\n * packagePaths: {\n * \"@react-md/core\": \"./packages/core\",\n * \"docs\": \"./apps/docs\"\n * },\n * ```\n *\n * If this is omitted or not matched, it will default to `\".\"`\n *\n * @defaultValue `{}`\n */\n packagePaths?: Record<string, string>;\n\n /**\n * A set of packages that should never attempt to create a github release.\n *\n * @defaultValue `new Set()`\n */\n disableGithubReleasePackages?: ReadonlySet<string>;\n}\n\nexport interface PendingRelease {\n tagName: string;\n body: string;\n}\n\nexport async function getPendingReleases(\n options: GetPendingReleasesOptions\n): Promise<readonly PendingRelease[]> {\n const {\n packagePaths = {},\n disableGithubReleasePackages = new Set<string>(),\n } = options;\n const unpushedTags = getUnpushedTags();\n if (unpushedTags.length === 0) {\n throw new Error(\"Unable to find any pending releases\");\n }\n\n const pending: PendingRelease[] = [];\n for (const unpushedTag of unpushedTags) {\n const name = unpushedTag.replace(/@\\d+.+$/, \"\");\n if (\n disableGithubReleasePackages.has(name) ||\n !(await confirm({ message: `Include ${unpushedTag} in the release?` }))\n ) {\n continue;\n }\n\n let path = packagePaths[name];\n if (!path) {\n path = await input({\n message: `${name} CHANGELOG exists at:`,\n default: \".\",\n });\n }\n\n const changelog = await readFile(\n resolve(process.cwd(), path, \"CHANGELOG.md\"),\n \"utf8\"\n );\n\n let body = \"\";\n let isTracking = false;\n const lines = changelog.split(/\\r?\\n/);\n for (const line of lines) {\n if (line.startsWith(\"## \")) {\n if (isTracking) {\n break;\n }\n\n isTracking = true;\n body = line;\n } else if (isTracking) {\n body += `\\n${line}`;\n }\n }\n\n pending.push({\n body,\n tagName: unpushedTag,\n });\n }\n\n if (pending.length === 0) {\n throw new Error(\"No pending releases were confirmed\");\n }\n\n return pending;\n}\n","import { type ExecSyncOptions, execSync } from \"node:child_process\";\n\nimport { continueRelease } from \"./continueRelease.js\";\nimport {\n type ConfigurableCreateReleaseOptions,\n createRelease,\n} from \"./createRelease.js\";\nimport { getPackageManager } from \"./getPackageManager.js\";\nimport {\n type GetPendingReleasesOptions,\n getPendingReleases,\n} from \"./getPendingReleases.js\";\n\nconst exec = (command: string, opts?: ExecSyncOptions): void => {\n console.log(command);\n execSync(command, opts);\n};\n\nexport interface ReleaseOptions\n extends ConfigurableCreateReleaseOptions, GetPendingReleasesOptions {\n /**\n * @defaultValue `!buildCommand`\n */\n skipBuild?: boolean;\n\n /**\n * @defaultValue `\"clean\"`\n */\n cleanCommand?: string;\n\n /**\n * @defaultValue `\"build\"`\n */\n buildCommand?: string;\n\n /**\n * @defaultValue `\"build(version): version package\"`\n */\n versionMessage?: string;\n}\n\nexport async function release(options: ReleaseOptions): Promise<void> {\n const {\n owner,\n repo,\n envPath,\n cleanCommand = \"clean\",\n buildCommand = \"build\",\n skipBuild = !buildCommand,\n versionMessage = \"build(version): version package\",\n } = options;\n\n const pkgManager = await getPackageManager();\n\n if (!skipBuild) {\n exec(`${pkgManager} ${cleanCommand}`);\n exec(`${pkgManager} ${buildCommand}`);\n }\n await continueRelease();\n\n exec(\"pnpm changeset version\", { stdio: \"inherit\" });\n exec(\"git add -u\");\n await continueRelease();\n\n exec(`git commit -m \"${versionMessage}\"`);\n exec(`${pkgManager} changeset publish`, { stdio: \"inherit\" });\n const pendingReleases = await getPendingReleases(options);\n\n exec(\"git push --follow-tags\");\n\n for (const release of pendingReleases) {\n await createRelease({\n owner,\n repo,\n body: release.body,\n tagName: release.tagName,\n envPath,\n prerelease: /-(alpha|next|beta)\\.\\d+$/.test(release.tagName),\n });\n }\n}\n"],"names":["createRelease","options","body","override","owner","repo","prerelease","envPath","tagName","tokenName","dotenv","config","path","quiet","octokit","Octokit","auth","process","env","response","request","tag_name","console","log","data","html_url","error","confirm","message","Error","continueRelease","confirmed","getPackageManager","rawPackageJson","readFile","resolve","cwd","packageJson","JSON","parse","volta","packageManager","mgr","replace","LOCAL_TAGS_COMMAND","REMOTE_TAGS_COMMAND","getTags","local","command","tags","execSync","toString","trim","lines","split","Set","map","line","getUnpushedTags","localTags","pushedTags","difference","getPendingReleases","packagePaths","disableGithubReleasePackages","unpushedTags","length","pending","unpushedTag","name","has","input","default","changelog","isTracking","startsWith","push","exec","opts","release","cleanCommand","buildCommand","skipBuild","versionMessage","pkgManager","stdio","pendingReleases","test"],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@mlaursen/release-script",
3
- "version": "0.0.7",
3
+ "version": "0.1.0",
4
4
  "description": "The release script I normally use for packages I publish to npm",
5
5
  "type": "module",
6
6
  "exports": {
7
- ".": "./dist/index.mjs",
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.mjs"
10
+ },
8
11
  "./package.json": "./package.json"
9
12
  },
10
13
  "author": "Mikkel Laursen <mlaursen03@gmail.com>",
@@ -24,24 +27,26 @@
24
27
  "license": "MIT",
25
28
  "dependencies": {
26
29
  "@changesets/cli": "^2.29.8",
27
- "@inquirer/confirm": "^6.0.2",
28
- "@inquirer/input": "^5.0.2",
29
- "@inquirer/rawlist": "^5.0.2",
30
+ "@inquirer/confirm": "^6.0.3",
31
+ "@inquirer/input": "^5.0.3",
32
+ "@inquirer/rawlist": "^5.1.0",
30
33
  "@octokit/core": "^7.0.6",
31
34
  "dotenv": "^17.2.3"
32
35
  },
33
36
  "devDependencies": {
34
37
  "@rollup/plugin-node-resolve": "^16.0.3",
35
- "@trivago/prettier-plugin-sort-imports": "^6.0.0",
36
- "@types/node": "^24.10.1",
38
+ "@trivago/prettier-plugin-sort-imports": "^6.0.2",
39
+ "@types/node": "^25.0.6",
40
+ "@vitest/coverage-v8": "^4.0.16",
37
41
  "concurrently": "^9.2.1",
38
- "eslint": "^9.39.1",
42
+ "eslint": "^9.39.2",
39
43
  "prettier": "^3.7.4",
40
- "rollup": "^4.53.3",
44
+ "rollup": "^4.55.1",
41
45
  "rollup-plugin-dts": "^6.3.0",
42
46
  "rollup-plugin-swc3": "^0.12.1",
43
47
  "typescript": "^5.9.3",
44
- "@mlaursen/eslint-config": "11.0.1"
48
+ "vitest": "^4.0.16",
49
+ "@mlaursen/eslint-config": "12.0.1"
45
50
  },
46
51
  "publishConfig": {
47
52
  "access": "public"
@@ -52,8 +57,8 @@
52
57
  ]
53
58
  },
54
59
  "volta": {
55
- "node": "24.11.0",
56
- "pnpm": "10.20.0"
60
+ "node": "24.12.0",
61
+ "pnpm": "10.26.1"
57
62
  },
58
63
  "scripts": {
59
64
  "clean-dist": "rm -rf dist",
@@ -70,6 +75,11 @@
70
75
  "build-types": "tsc -p tsconfig.types.json",
71
76
  "build-types-watch": "pnpm build-types --watch",
72
77
  "build": "pnpm build-types && pnpm build-dist",
78
+ "test": "vitest",
79
+ "test-coverage": "vitest --coverage",
80
+ "test-run": "vitest run",
81
+ "test-run-snapshot": "vitest run -u",
82
+ "test-run-coverage": "vitest run --coverage",
73
83
  "dev": "concurrently 'pnpm build-types-watch' 'pnpm build-dist-watch'"
74
84
  }
75
85
  }
@@ -2,13 +2,17 @@ import { readFile } from "node:fs/promises";
2
2
  import { resolve } from "node:path";
3
3
 
4
4
  export type PackageManager = "npm" | "yarn" | "pnpm";
5
+ interface PartialPackageJson {
6
+ volta?: Record<string, string>;
7
+ packageManager?: string;
8
+ }
5
9
 
6
10
  export async function getPackageManager(): Promise<PackageManager> {
7
11
  const rawPackageJson = await readFile(
8
12
  resolve(process.cwd(), "package.json"),
9
13
  "utf8"
10
14
  );
11
- const packageJson = JSON.parse(rawPackageJson);
15
+ const packageJson = JSON.parse(rawPackageJson) as PartialPackageJson;
12
16
 
13
17
  if (typeof packageJson.volta === "object" && packageJson.volta) {
14
18
  const { volta } = packageJson;
@@ -24,13 +28,13 @@ export async function getPackageManager(): Promise<PackageManager> {
24
28
  }
25
29
 
26
30
  if (typeof packageJson.packageManager === "string") {
27
- const mgr = packageJson.packageManagerreplace(/@.+/, "");
31
+ const mgr = packageJson.packageManager.replace(/@.+/, "");
28
32
 
29
33
  if (mgr === "pnpm" || mgr === "yarn" || mgr === "npm") {
30
34
  return mgr;
31
35
  }
32
36
 
33
- throw new Error(`Unsupported package mananger "${mgr}" in package.json`);
37
+ throw new Error(`Unsupported package manager "${mgr}" in package.json`);
34
38
  }
35
39
 
36
40
  throw new Error("Unable to find a package manager");
@@ -22,6 +22,13 @@ export interface GetPendingReleasesOptions {
22
22
  * @defaultValue `{}`
23
23
  */
24
24
  packagePaths?: Record<string, string>;
25
+
26
+ /**
27
+ * A set of packages that should never attempt to create a github release.
28
+ *
29
+ * @defaultValue `new Set()`
30
+ */
31
+ disableGithubReleasePackages?: ReadonlySet<string>;
25
32
  }
26
33
 
27
34
  export interface PendingRelease {
@@ -32,7 +39,10 @@ export interface PendingRelease {
32
39
  export async function getPendingReleases(
33
40
  options: GetPendingReleasesOptions
34
41
  ): Promise<readonly PendingRelease[]> {
35
- const { packagePaths = {} } = options;
42
+ const {
43
+ packagePaths = {},
44
+ disableGithubReleasePackages = new Set<string>(),
45
+ } = options;
36
46
  const unpushedTags = getUnpushedTags();
37
47
  if (unpushedTags.length === 0) {
38
48
  throw new Error("Unable to find any pending releases");
@@ -40,17 +50,21 @@ export async function getPendingReleases(
40
50
 
41
51
  const pending: PendingRelease[] = [];
42
52
  for (const unpushedTag of unpushedTags) {
53
+ const name = unpushedTag.replace(/@\d+.+$/, "");
43
54
  if (
55
+ disableGithubReleasePackages.has(name) ||
44
56
  !(await confirm({ message: `Include ${unpushedTag} in the release?` }))
45
57
  ) {
46
58
  continue;
47
59
  }
48
60
 
49
- const name = unpushedTag.replace(/@\d+.+$/, "");
50
- const path = await input({
51
- message: `${name} CHANGELOG exists at:`,
52
- default: packagePaths[name] ?? ".",
53
- });
61
+ let path = packagePaths[name];
62
+ if (!path) {
63
+ path = await input({
64
+ message: `${name} CHANGELOG exists at:`,
65
+ default: ".",
66
+ });
67
+ }
54
68
 
55
69
  const changelog = await readFile(
56
70
  resolve(process.cwd(), path, "CHANGELOG.md"),
@@ -79,5 +93,9 @@ export async function getPendingReleases(
79
93
  });
80
94
  }
81
95
 
96
+ if (pending.length === 0) {
97
+ throw new Error("No pending releases were confirmed");
98
+ }
99
+
82
100
  return pending;
83
101
  }
@@ -1,9 +1,10 @@
1
1
  import { execSync } from "node:child_process";
2
2
 
3
+ export const LOCAL_TAGS_COMMAND = "git tag --sort=-creatordate";
4
+ export const REMOTE_TAGS_COMMAND = "git ls-remote --tags origin";
5
+
3
6
  function getTags(local: boolean): Set<string> {
4
- const command = local
5
- ? "git tag --sort=-creatordate"
6
- : "git ls-remote --tags origin";
7
+ const command = local ? LOCAL_TAGS_COMMAND : REMOTE_TAGS_COMMAND;
7
8
  const tags = execSync(command).toString().trim();
8
9
  const lines = tags.split(/\r?\n/);
9
10
  if (local) {