@mlaursen/release-script 0.0.8 → 0.1.1
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 +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +58 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -21
- package/src/createRelease.ts +2 -2
- package/src/getPackageManager.ts +7 -3
- package/src/getPendingReleases.ts +24 -6
- package/src/getUnpushedTags.ts +4 -3
- package/src/release.ts +21 -13
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 {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sources":["../types/createRelease.d.ts","../types/getPendingReleases.d.ts","../types/release.d.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sources":["../types/createRelease.d.ts","../types/getPendingReleases.d.ts","../types/release.d.ts"],"mappings":"AAAA,UAAU,gCAAgC;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,oBAAoB,SAAS,gCAAgC;AACvE;AACA;AACA;AACA;AACA;AACA,iBAAiB,aAAa,UAAU,oBAAoB,GAAG,OAAO;;ACvBtE,UAAU,yBAAyB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,MAAM;AACzB;AACA;AACA;AACA;AACA;AACA,mCAAmC,WAAW;AAC9C;;ACrBA,UAAU,cAAc,SAAS,gCAAgC,EAAE,yBAAyB;AAC5F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,OAAO,UAAU,cAAc,GAAG,OAAO;;;;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import confirm from '@inquirer/confirm';
|
|
2
2
|
import { Octokit } from '@octokit/core';
|
|
3
3
|
import dotenv from 'dotenv';
|
|
4
|
-
import { execSync } from 'node:child_process';
|
|
4
|
+
import { execSync, spawnSync } from 'node:child_process';
|
|
5
5
|
import { readFile } from 'node:fs/promises';
|
|
6
6
|
import { resolve } from 'node:path';
|
|
7
7
|
import input from '@inquirer/input';
|
|
8
8
|
|
|
9
9
|
async function createRelease(options) {
|
|
10
|
-
const { body, override, owner = "mlaursen", repo, prerelease, envPath = ".env.local", tagName, tokenName = "GITHUB_RELEASE_TOKEN" } = options;
|
|
10
|
+
const { body, override = false, owner = "mlaursen", repo, prerelease, envPath = ".env.local", tagName, tokenName = "GITHUB_RELEASE_TOKEN" } = options;
|
|
11
11
|
dotenv.config({
|
|
12
12
|
path: envPath,
|
|
13
13
|
override,
|
|
@@ -33,7 +33,9 @@ async function createRelease(options) {
|
|
|
33
33
|
if (!await confirm({
|
|
34
34
|
message: "Try creating the Github release again?"
|
|
35
35
|
})) {
|
|
36
|
-
throw new Error("Unable to create a Github release"
|
|
36
|
+
throw new Error("Unable to create a Github release", {
|
|
37
|
+
cause: error
|
|
38
|
+
});
|
|
37
39
|
}
|
|
38
40
|
return createRelease({
|
|
39
41
|
...options,
|
|
@@ -65,17 +67,19 @@ async function getPackageManager() {
|
|
|
65
67
|
return "npm";
|
|
66
68
|
}
|
|
67
69
|
if (typeof packageJson.packageManager === "string") {
|
|
68
|
-
const mgr = packageJson.
|
|
70
|
+
const mgr = packageJson.packageManager.replace(/@.+/, "");
|
|
69
71
|
if (mgr === "pnpm" || mgr === "yarn" || mgr === "npm") {
|
|
70
72
|
return mgr;
|
|
71
73
|
}
|
|
72
|
-
throw new Error(`Unsupported package
|
|
74
|
+
throw new Error(`Unsupported package manager "${mgr}" in package.json`);
|
|
73
75
|
}
|
|
74
76
|
throw new Error("Unable to find a package manager");
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
const LOCAL_TAGS_COMMAND = "git tag --sort=-creatordate";
|
|
80
|
+
const REMOTE_TAGS_COMMAND = "git ls-remote --tags origin";
|
|
77
81
|
function getTags(local) {
|
|
78
|
-
const command = local ?
|
|
82
|
+
const command = local ? LOCAL_TAGS_COMMAND : REMOTE_TAGS_COMMAND;
|
|
79
83
|
const tags = execSync(command).toString().trim();
|
|
80
84
|
const lines = tags.split(/\r?\n/);
|
|
81
85
|
if (local) {
|
|
@@ -92,23 +96,26 @@ function getUnpushedTags() {
|
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
async function getPendingReleases(options) {
|
|
95
|
-
const { packagePaths = {} } = options;
|
|
99
|
+
const { packagePaths = {}, disableGithubReleasePackages = new Set() } = options;
|
|
96
100
|
const unpushedTags = getUnpushedTags();
|
|
97
101
|
if (unpushedTags.length === 0) {
|
|
98
102
|
throw new Error("Unable to find any pending releases");
|
|
99
103
|
}
|
|
100
104
|
const pending = [];
|
|
101
105
|
for (const unpushedTag of unpushedTags){
|
|
102
|
-
|
|
106
|
+
const name = unpushedTag.replace(/@\d+.+$/, "");
|
|
107
|
+
if (disableGithubReleasePackages.has(name) || !await confirm({
|
|
103
108
|
message: `Include ${unpushedTag} in the release?`
|
|
104
109
|
})) {
|
|
105
110
|
continue;
|
|
106
111
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
let path = packagePaths[name];
|
|
113
|
+
if (!path) {
|
|
114
|
+
path = await input({
|
|
115
|
+
message: `${name} CHANGELOG exists at:`,
|
|
116
|
+
default: "."
|
|
117
|
+
});
|
|
118
|
+
}
|
|
112
119
|
const changelog = await readFile(resolve(process.cwd(), path, "CHANGELOG.md"), "utf8");
|
|
113
120
|
let body = "";
|
|
114
121
|
let isTracking = false;
|
|
@@ -129,32 +136,59 @@ async function getPendingReleases(options) {
|
|
|
129
136
|
tagName: unpushedTag
|
|
130
137
|
});
|
|
131
138
|
}
|
|
139
|
+
if (pending.length === 0) {
|
|
140
|
+
throw new Error("No pending releases were confirmed");
|
|
141
|
+
}
|
|
132
142
|
return pending;
|
|
133
143
|
}
|
|
134
144
|
|
|
135
|
-
const exec = (command, opts)=>{
|
|
136
|
-
|
|
137
|
-
|
|
145
|
+
const exec = (command, args, opts)=>{
|
|
146
|
+
const cmd = command + " " + args.join(" ");
|
|
147
|
+
console.log(cmd);
|
|
148
|
+
const result = spawnSync(command, args, opts);
|
|
149
|
+
if (result.status !== 0) {
|
|
150
|
+
throw new Error(`${cmd} failed with exit code: ${result.status ?? 1}`);
|
|
151
|
+
}
|
|
138
152
|
};
|
|
139
153
|
async function release(options) {
|
|
140
|
-
const { owner, repo, envPath, cleanCommand = "clean", buildCommand = "build", skipBuild = !buildCommand, versionMessage = "build(version): version package" } = options;
|
|
154
|
+
const { owner = "mlaursen", repo, envPath = ".env.local", cleanCommand = "clean", buildCommand = "build", skipBuild = !buildCommand, versionMessage = "build(version): version package" } = options;
|
|
141
155
|
const pkgManager = await getPackageManager();
|
|
142
156
|
if (!skipBuild) {
|
|
143
|
-
exec(
|
|
144
|
-
|
|
157
|
+
exec(pkgManager, [
|
|
158
|
+
cleanCommand
|
|
159
|
+
]);
|
|
160
|
+
exec(pkgManager, [
|
|
161
|
+
buildCommand
|
|
162
|
+
]);
|
|
145
163
|
}
|
|
146
164
|
await continueRelease();
|
|
147
|
-
exec(
|
|
165
|
+
exec(pkgManager, [
|
|
166
|
+
"changeset",
|
|
167
|
+
"version"
|
|
168
|
+
], {
|
|
148
169
|
stdio: "inherit"
|
|
149
170
|
});
|
|
150
|
-
exec("git
|
|
171
|
+
exec("git", [
|
|
172
|
+
"add",
|
|
173
|
+
"-u"
|
|
174
|
+
]);
|
|
151
175
|
await continueRelease();
|
|
152
|
-
exec(
|
|
153
|
-
|
|
176
|
+
exec("git", [
|
|
177
|
+
"commit",
|
|
178
|
+
"-m",
|
|
179
|
+
versionMessage
|
|
180
|
+
]);
|
|
181
|
+
exec(pkgManager, [
|
|
182
|
+
"changeset",
|
|
183
|
+
"publish"
|
|
184
|
+
], {
|
|
154
185
|
stdio: "inherit"
|
|
155
186
|
});
|
|
156
187
|
const pendingReleases = await getPendingReleases(options);
|
|
157
|
-
exec("git
|
|
188
|
+
exec("git", [
|
|
189
|
+
"push",
|
|
190
|
+
"--follow-tags"
|
|
191
|
+
]);
|
|
158
192
|
for (const release of pendingReleases){
|
|
159
193
|
await createRelease({
|
|
160
194
|
owner,
|
package/dist/index.mjs.map
CHANGED
|
@@ -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":"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"}
|
|
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 = false,\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\", { cause: error });\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 SpawnSyncOptions, spawnSync } 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 = (\n command: string,\n args: readonly string[],\n opts?: SpawnSyncOptions\n): void => {\n const cmd = command + \" \" + args.join(\" \");\n console.log(cmd);\n const result = spawnSync(command, args, opts);\n if (result.status !== 0) {\n throw new Error(`${cmd} failed with exit code: ${result.status ?? 1}`);\n }\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 = \"mlaursen\",\n repo,\n envPath = \".env.local\",\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(pkgManager, [\"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","cause","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","args","opts","cmd","join","result","spawnSync","status","release","cleanCommand","buildCommand","skipBuild","versionMessage","pkgManager","stdio","pendingReleases","test"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mlaursen/release-script",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "The release script I normally use for packages I publish to npm",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -26,37 +26,34 @@
|
|
|
26
26
|
],
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@changesets/cli": "^2.
|
|
30
|
-
"@inquirer/confirm": "^6.0.
|
|
31
|
-
"@inquirer/input": "^5.0.
|
|
32
|
-
"@inquirer/rawlist": "^5.
|
|
29
|
+
"@changesets/cli": "^2.30.0",
|
|
30
|
+
"@inquirer/confirm": "^6.0.11",
|
|
31
|
+
"@inquirer/input": "^5.0.11",
|
|
32
|
+
"@inquirer/rawlist": "^5.2.7",
|
|
33
33
|
"@octokit/core": "^7.0.6",
|
|
34
|
-
"dotenv": "^17.
|
|
34
|
+
"dotenv": "^17.4.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
38
|
-
"@trivago/prettier-plugin-sort-imports": "^6.0.
|
|
39
|
-
"@types/node": "^
|
|
38
|
+
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
39
|
+
"@types/node": "^24.12.2",
|
|
40
|
+
"@vitest/coverage-v8": "^4.1.3",
|
|
40
41
|
"concurrently": "^9.2.1",
|
|
41
|
-
"eslint": "^9.39.
|
|
42
|
-
"prettier": "^3.
|
|
43
|
-
"rollup": "^4.
|
|
44
|
-
"rollup-plugin-dts": "^6.
|
|
42
|
+
"eslint": "^9.39.4",
|
|
43
|
+
"prettier": "^3.8.1",
|
|
44
|
+
"rollup": "^4.60.1",
|
|
45
|
+
"rollup-plugin-dts": "^6.4.1",
|
|
45
46
|
"rollup-plugin-swc3": "^0.12.1",
|
|
46
|
-
"typescript": "^
|
|
47
|
-
"
|
|
47
|
+
"typescript": "^6.0.2",
|
|
48
|
+
"vitest": "^4.1.3",
|
|
49
|
+
"@mlaursen/eslint-config": "12.0.7"
|
|
48
50
|
},
|
|
49
51
|
"publishConfig": {
|
|
50
52
|
"access": "public"
|
|
51
53
|
},
|
|
52
|
-
"lint-staged": {
|
|
53
|
-
"**/*.{js,jsx,ts,tsx,md,yml,yaml,json}": [
|
|
54
|
-
"prettier --write"
|
|
55
|
-
]
|
|
56
|
-
},
|
|
57
54
|
"volta": {
|
|
58
|
-
"node": "24.
|
|
59
|
-
"pnpm": "10.
|
|
55
|
+
"node": "24.14.1",
|
|
56
|
+
"pnpm": "10.33.0"
|
|
60
57
|
},
|
|
61
58
|
"scripts": {
|
|
62
59
|
"clean-dist": "rm -rf dist",
|
|
@@ -73,6 +70,11 @@
|
|
|
73
70
|
"build-types": "tsc -p tsconfig.types.json",
|
|
74
71
|
"build-types-watch": "pnpm build-types --watch",
|
|
75
72
|
"build": "pnpm build-types && pnpm build-dist",
|
|
73
|
+
"test": "vitest",
|
|
74
|
+
"test-coverage": "vitest --coverage",
|
|
75
|
+
"test-run": "vitest run",
|
|
76
|
+
"test-run-snapshot": "vitest run -u",
|
|
77
|
+
"test-run-coverage": "vitest run --coverage",
|
|
76
78
|
"dev": "concurrently 'pnpm build-types-watch' 'pnpm build-dist-watch'"
|
|
77
79
|
}
|
|
78
80
|
}
|
package/src/createRelease.ts
CHANGED
|
@@ -35,7 +35,7 @@ export async function createRelease(
|
|
|
35
35
|
): Promise<void> {
|
|
36
36
|
const {
|
|
37
37
|
body,
|
|
38
|
-
override,
|
|
38
|
+
override = false,
|
|
39
39
|
owner = "mlaursen",
|
|
40
40
|
repo,
|
|
41
41
|
prerelease,
|
|
@@ -72,7 +72,7 @@ export async function createRelease(
|
|
|
72
72
|
if (
|
|
73
73
|
!(await confirm({ message: "Try creating the Github release again?" }))
|
|
74
74
|
) {
|
|
75
|
-
throw new Error("Unable to create a Github release");
|
|
75
|
+
throw new Error("Unable to create a Github release", { cause: error });
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
return createRelease({ ...options, override: true });
|
package/src/getPackageManager.ts
CHANGED
|
@@ -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.
|
|
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
|
|
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 {
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
}
|
package/src/getUnpushedTags.ts
CHANGED
|
@@ -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) {
|
package/src/release.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type SpawnSyncOptions, spawnSync } from "node:child_process";
|
|
2
2
|
|
|
3
3
|
import { continueRelease } from "./continueRelease.js";
|
|
4
4
|
import {
|
|
@@ -11,9 +11,17 @@ import {
|
|
|
11
11
|
getPendingReleases,
|
|
12
12
|
} from "./getPendingReleases.js";
|
|
13
13
|
|
|
14
|
-
const exec = (
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const exec = (
|
|
15
|
+
command: string,
|
|
16
|
+
args: readonly string[],
|
|
17
|
+
opts?: SpawnSyncOptions
|
|
18
|
+
): void => {
|
|
19
|
+
const cmd = command + " " + args.join(" ");
|
|
20
|
+
console.log(cmd);
|
|
21
|
+
const result = spawnSync(command, args, opts);
|
|
22
|
+
if (result.status !== 0) {
|
|
23
|
+
throw new Error(`${cmd} failed with exit code: ${result.status ?? 1}`);
|
|
24
|
+
}
|
|
17
25
|
};
|
|
18
26
|
|
|
19
27
|
export interface ReleaseOptions
|
|
@@ -41,9 +49,9 @@ export interface ReleaseOptions
|
|
|
41
49
|
|
|
42
50
|
export async function release(options: ReleaseOptions): Promise<void> {
|
|
43
51
|
const {
|
|
44
|
-
owner,
|
|
52
|
+
owner = "mlaursen",
|
|
45
53
|
repo,
|
|
46
|
-
envPath,
|
|
54
|
+
envPath = ".env.local",
|
|
47
55
|
cleanCommand = "clean",
|
|
48
56
|
buildCommand = "build",
|
|
49
57
|
skipBuild = !buildCommand,
|
|
@@ -53,20 +61,20 @@ export async function release(options: ReleaseOptions): Promise<void> {
|
|
|
53
61
|
const pkgManager = await getPackageManager();
|
|
54
62
|
|
|
55
63
|
if (!skipBuild) {
|
|
56
|
-
exec(
|
|
57
|
-
exec(
|
|
64
|
+
exec(pkgManager, [cleanCommand]);
|
|
65
|
+
exec(pkgManager, [buildCommand]);
|
|
58
66
|
}
|
|
59
67
|
await continueRelease();
|
|
60
68
|
|
|
61
|
-
exec("
|
|
62
|
-
exec("git add -u");
|
|
69
|
+
exec(pkgManager, ["changeset", "version"], { stdio: "inherit" });
|
|
70
|
+
exec("git", ["add", "-u"]);
|
|
63
71
|
await continueRelease();
|
|
64
72
|
|
|
65
|
-
exec(
|
|
66
|
-
exec(
|
|
73
|
+
exec("git", ["commit", "-m", versionMessage]);
|
|
74
|
+
exec(pkgManager, ["changeset", "publish"], { stdio: "inherit" });
|
|
67
75
|
const pendingReleases = await getPendingReleases(options);
|
|
68
76
|
|
|
69
|
-
exec("git push --follow-tags");
|
|
77
|
+
exec("git", ["push", "--follow-tags"]);
|
|
70
78
|
|
|
71
79
|
for (const release of pendingReleases) {
|
|
72
80
|
await createRelease({
|