@mlaursen/release-script 0.0.6 → 0.0.7
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/README.md +16 -17
- package/dist/index.d.ts +67 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +171 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +40 -25
- package/src/continueRelease.ts +8 -0
- package/src/createRelease.ts +80 -0
- package/src/getCurrentChangeset.ts +33 -0
- package/src/getPackageManager.ts +37 -0
- package/src/getPendingReleases.ts +83 -0
- package/src/getUnpushedTags.ts +23 -0
- package/src/index.ts +2 -0
- package/src/release.ts +81 -0
- package/dist/continueRelease.d.ts +0 -1
- package/dist/continueRelease.js +0 -7
- package/dist/createGetTagName.d.ts +0 -1
- package/dist/createGetTagName.js +0 -19
- package/dist/createRelease.d.ts +0 -24
- package/dist/createRelease.js +0 -28
- package/dist/getCurrentChangeset.d.ts +0 -1
- package/dist/getCurrentChangeset.js +0 -26
- package/dist/getLatestTag.d.ts +0 -1
- package/dist/getLatestTag.js +0 -4
- package/dist/getPackageManager.d.ts +0 -2
- package/dist/getPackageManager.js +0 -24
- package/dist/index.js +0 -2
- package/dist/release.d.ts +0 -22
- package/dist/release.js +0 -39
package/README.md
CHANGED
|
@@ -52,10 +52,6 @@ await release({
|
|
|
52
52
|
// An optional flag if the build step should be skipped. `!buildCommand` by default
|
|
53
53
|
// skipBuild: process.argv.includes("--skip-build"),
|
|
54
54
|
|
|
55
|
-
// This is useful for monorepos where only a single Github release needs to
|
|
56
|
-
// be created. Defaults to `JSON.parse(await readFile("package.json)).name`
|
|
57
|
-
// mainPackage: "{{PACKAGE_NAME}}",
|
|
58
|
-
|
|
59
55
|
// If the version message needs to be customized. The following is the default
|
|
60
56
|
// versionMessage: "build(version): version package",
|
|
61
57
|
|
|
@@ -63,18 +59,11 @@ await release({
|
|
|
63
59
|
// variable.
|
|
64
60
|
// envPath: ".env.local",
|
|
65
61
|
|
|
66
|
-
// An optional
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
// ).getLatestTag();
|
|
72
|
-
// let tagName =
|
|
73
|
-
// mainPackage && /@\d/.test(latestTag)
|
|
74
|
-
// ? latestTag.replace(/.+(@\d)/, `${mainPackage}$1`)
|
|
75
|
-
// : latestTag;
|
|
76
|
-
//
|
|
77
|
-
// return tagName;
|
|
62
|
+
// An optional lookup of package name -> package path in the repo used to
|
|
63
|
+
// find the CHANGELOG.md for each release in a monorepo. Will default to
|
|
64
|
+
// `"."` when omitted.
|
|
65
|
+
// packagePaths: {
|
|
66
|
+
// "@react-md/core": "./packages/core",
|
|
78
67
|
// },
|
|
79
68
|
});
|
|
80
69
|
```
|
|
@@ -89,7 +78,7 @@ Next, update `package.json` to include the release script:
|
|
|
89
78
|
"format": "prettier --write .",
|
|
90
79
|
"clean": "rm -rf dist",
|
|
91
80
|
"build": "tsc -p tsconfig.json",
|
|
92
|
-
+ "release": "tsx
|
|
81
|
+
+ "release": "tsx scripts/release.ts"
|
|
93
82
|
},
|
|
94
83
|
```
|
|
95
84
|
|
|
@@ -99,6 +88,16 @@ Finally, run the release script whenever a new release should go out:
|
|
|
99
88
|
pnpm release
|
|
100
89
|
```
|
|
101
90
|
|
|
91
|
+
## Adding Changesets
|
|
92
|
+
|
|
93
|
+
During normal development, add changesets and commit them. They will normally
|
|
94
|
+
be close to my commit messages which is a bit annoying.
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
pnpm changeset
|
|
98
|
+
git add .changeset
|
|
99
|
+
```
|
|
100
|
+
|
|
102
101
|
## Alpha Releases
|
|
103
102
|
|
|
104
103
|
Use the changesets api to enter the pre-release flow:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface ConfigurableCreateReleaseOptions {
|
|
2
|
+
repo: string;
|
|
3
|
+
/**
|
|
4
|
+
* @defaultValue `"mlaursen"`
|
|
5
|
+
*/
|
|
6
|
+
owner?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The `.env` file to load to get the {@link tokenName} environment variable.
|
|
9
|
+
*
|
|
10
|
+
* @defaultValue `".env.local"`
|
|
11
|
+
*/
|
|
12
|
+
envPath?: string;
|
|
13
|
+
/**
|
|
14
|
+
* @defaultValue `"GITHUB_RELEASE_TOKEN"`
|
|
15
|
+
*/
|
|
16
|
+
tokenName?: string;
|
|
17
|
+
}
|
|
18
|
+
interface CreateReleaseOptions extends ConfigurableCreateReleaseOptions {
|
|
19
|
+
body: string;
|
|
20
|
+
override?: boolean;
|
|
21
|
+
tagName: string;
|
|
22
|
+
prerelease: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare function createRelease(options: CreateReleaseOptions): Promise<void>;
|
|
25
|
+
|
|
26
|
+
interface GetPendingReleasesOptions {
|
|
27
|
+
/**
|
|
28
|
+
* This should be a record of package names to paths for monorepos.
|
|
29
|
+
*
|
|
30
|
+
* @example Monorepo Setup
|
|
31
|
+
* ```tsx
|
|
32
|
+
* packagePaths: {
|
|
33
|
+
* "@react-md/core": "./packages/core",
|
|
34
|
+
* "docs": "./apps/docs"
|
|
35
|
+
* },
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* If this is omitted or not matched, it will default to `"."`
|
|
39
|
+
*
|
|
40
|
+
* @defaultValue `{}`
|
|
41
|
+
*/
|
|
42
|
+
packagePaths?: Record<string, string>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface ReleaseOptions extends ConfigurableCreateReleaseOptions, GetPendingReleasesOptions {
|
|
46
|
+
/**
|
|
47
|
+
* @defaultValue `!buildCommand`
|
|
48
|
+
*/
|
|
49
|
+
skipBuild?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* @defaultValue `"clean"`
|
|
52
|
+
*/
|
|
53
|
+
cleanCommand?: string;
|
|
54
|
+
/**
|
|
55
|
+
* @defaultValue `"build"`
|
|
56
|
+
*/
|
|
57
|
+
buildCommand?: string;
|
|
58
|
+
/**
|
|
59
|
+
* @defaultValue `"build(version): version package"`
|
|
60
|
+
*/
|
|
61
|
+
versionMessage?: string;
|
|
62
|
+
}
|
|
63
|
+
declare function release(options: ReleaseOptions): Promise<void>;
|
|
64
|
+
|
|
65
|
+
export { createRelease, release };
|
|
66
|
+
export type { ConfigurableCreateReleaseOptions, CreateReleaseOptions, ReleaseOptions };
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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;;;;"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import confirm from '@inquirer/confirm';
|
|
2
|
+
import { Octokit } from '@octokit/core';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
import { readFile } from 'node:fs/promises';
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
import input from '@inquirer/input';
|
|
8
|
+
|
|
9
|
+
async function createRelease(options) {
|
|
10
|
+
const { body, override, owner = "mlaursen", repo, prerelease, envPath = ".env.local", tagName, tokenName = "GITHUB_RELEASE_TOKEN" } = options;
|
|
11
|
+
dotenv.config({
|
|
12
|
+
path: envPath,
|
|
13
|
+
override,
|
|
14
|
+
quiet: true
|
|
15
|
+
});
|
|
16
|
+
const octokit = new Octokit({
|
|
17
|
+
auth: process.env[tokenName]
|
|
18
|
+
});
|
|
19
|
+
try {
|
|
20
|
+
const response = await octokit.request("POST /repos/{owner}/{repo}/releases", {
|
|
21
|
+
owner,
|
|
22
|
+
repo,
|
|
23
|
+
tag_name: tagName,
|
|
24
|
+
body,
|
|
25
|
+
prerelease
|
|
26
|
+
});
|
|
27
|
+
console.log(`Created release: ${response.data.html_url}`);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(error);
|
|
30
|
+
console.log();
|
|
31
|
+
console.log("The npm token is most likely expired or never created. Update the `.env.local` to include the latest GITHUB_TOKEN");
|
|
32
|
+
console.log("Regenerate the token: https://github.com/settings/personal-access-tokens");
|
|
33
|
+
if (!await confirm({
|
|
34
|
+
message: "Try creating the Github release again?"
|
|
35
|
+
})) {
|
|
36
|
+
throw new Error("Unable to create a Github release");
|
|
37
|
+
}
|
|
38
|
+
return createRelease({
|
|
39
|
+
...options,
|
|
40
|
+
override: true
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function continueRelease() {
|
|
46
|
+
const confirmed = await confirm({
|
|
47
|
+
message: "Continue the release?"
|
|
48
|
+
});
|
|
49
|
+
if (!confirmed) {
|
|
50
|
+
throw new Error("Release cancelled");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function getPackageManager() {
|
|
55
|
+
const rawPackageJson = await readFile(resolve(process.cwd(), "package.json"), "utf8");
|
|
56
|
+
const packageJson = JSON.parse(rawPackageJson);
|
|
57
|
+
if (typeof packageJson.volta === "object" && packageJson.volta) {
|
|
58
|
+
const { volta } = packageJson;
|
|
59
|
+
if ("pnpm" in volta) {
|
|
60
|
+
return "pnpm";
|
|
61
|
+
}
|
|
62
|
+
if ("yarn" in volta) {
|
|
63
|
+
return "yarn";
|
|
64
|
+
}
|
|
65
|
+
return "npm";
|
|
66
|
+
}
|
|
67
|
+
if (typeof packageJson.packageManager === "string") {
|
|
68
|
+
const mgr = packageJson.packageManagerreplace(/@.+/, "");
|
|
69
|
+
if (mgr === "pnpm" || mgr === "yarn" || mgr === "npm") {
|
|
70
|
+
return mgr;
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Unsupported package mananger "${mgr}" in package.json`);
|
|
73
|
+
}
|
|
74
|
+
throw new Error("Unable to find a package manager");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getTags(local) {
|
|
78
|
+
const command = local ? "git tag --sort=-creatordate" : "git ls-remote --tags origin";
|
|
79
|
+
const tags = execSync(command).toString().trim();
|
|
80
|
+
const lines = tags.split(/\r?\n/);
|
|
81
|
+
if (local) {
|
|
82
|
+
return new Set(lines);
|
|
83
|
+
}
|
|
84
|
+
return new Set(lines.map((line)=>line.replace(/^.+refs\/tags\//, "").replace("^{}", "")));
|
|
85
|
+
}
|
|
86
|
+
function getUnpushedTags() {
|
|
87
|
+
const localTags = getTags(true);
|
|
88
|
+
const pushedTags = getTags(false);
|
|
89
|
+
return [
|
|
90
|
+
...localTags.difference(pushedTags)
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function getPendingReleases(options) {
|
|
95
|
+
const { packagePaths = {} } = options;
|
|
96
|
+
const unpushedTags = getUnpushedTags();
|
|
97
|
+
if (unpushedTags.length === 0) {
|
|
98
|
+
throw new Error("Unable to find any pending releases");
|
|
99
|
+
}
|
|
100
|
+
const pending = [];
|
|
101
|
+
for (const unpushedTag of unpushedTags){
|
|
102
|
+
if (!await confirm({
|
|
103
|
+
message: `Include ${unpushedTag} in the release?`
|
|
104
|
+
})) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const name = unpushedTag.replace(/@\d+.+$/, "");
|
|
108
|
+
const path = await input({
|
|
109
|
+
message: `${name} CHANGELOG exists at:`,
|
|
110
|
+
default: packagePaths[name] ?? "."
|
|
111
|
+
});
|
|
112
|
+
const changelog = await readFile(resolve(process.cwd(), path, "CHANGELOG.md"), "utf8");
|
|
113
|
+
let body = "";
|
|
114
|
+
let isTracking = false;
|
|
115
|
+
const lines = changelog.split(/\r?\n/);
|
|
116
|
+
for (const line of lines){
|
|
117
|
+
if (line.startsWith("## ")) {
|
|
118
|
+
if (isTracking) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
isTracking = true;
|
|
122
|
+
body = line;
|
|
123
|
+
} else if (isTracking) {
|
|
124
|
+
body += `\n${line}`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
pending.push({
|
|
128
|
+
body,
|
|
129
|
+
tagName: unpushedTag
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return pending;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const exec = (command, opts)=>{
|
|
136
|
+
console.log(command);
|
|
137
|
+
execSync(command, opts);
|
|
138
|
+
};
|
|
139
|
+
async function release(options) {
|
|
140
|
+
const { owner, repo, envPath, cleanCommand = "clean", buildCommand = "build", skipBuild = !buildCommand, versionMessage = "build(version): version package" } = options;
|
|
141
|
+
const pkgManager = await getPackageManager();
|
|
142
|
+
if (!skipBuild) {
|
|
143
|
+
exec(`${pkgManager} ${cleanCommand}`);
|
|
144
|
+
exec(`${pkgManager} ${buildCommand}`);
|
|
145
|
+
}
|
|
146
|
+
await continueRelease();
|
|
147
|
+
exec("pnpm changeset version", {
|
|
148
|
+
stdio: "inherit"
|
|
149
|
+
});
|
|
150
|
+
exec("git add -u");
|
|
151
|
+
await continueRelease();
|
|
152
|
+
exec(`git commit -m "${versionMessage}"`);
|
|
153
|
+
exec(`${pkgManager} changeset publish`, {
|
|
154
|
+
stdio: "inherit"
|
|
155
|
+
});
|
|
156
|
+
const pendingReleases = await getPendingReleases(options);
|
|
157
|
+
exec("git push --follow-tags");
|
|
158
|
+
for (const release of pendingReleases){
|
|
159
|
+
await createRelease({
|
|
160
|
+
owner,
|
|
161
|
+
repo,
|
|
162
|
+
body: release.body,
|
|
163
|
+
tagName: release.tagName,
|
|
164
|
+
envPath,
|
|
165
|
+
prerelease: /-(alpha|next|beta)\.\d+$/.test(release.tagName)
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export { createRelease, release };
|
|
171
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +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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"}
|
package/package.json
CHANGED
|
@@ -1,41 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mlaursen/release-script",
|
|
3
|
-
"
|
|
4
|
-
"version": "0.0.6",
|
|
3
|
+
"version": "0.0.7",
|
|
5
4
|
"description": "The release script I normally use for packages I publish to npm",
|
|
6
|
-
"
|
|
7
|
-
"author": "Mikkel Laursen <mlaursen03@gmail.com>",
|
|
8
|
-
"license": "MIT",
|
|
9
|
-
"files": [
|
|
10
|
-
"dist/"
|
|
11
|
-
],
|
|
5
|
+
"type": "module",
|
|
12
6
|
"exports": {
|
|
13
|
-
".": "./dist/index.
|
|
7
|
+
".": "./dist/index.mjs",
|
|
14
8
|
"./package.json": "./package.json"
|
|
15
9
|
},
|
|
10
|
+
"author": "Mikkel Laursen <mlaursen03@gmail.com>",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/mlaursen/npm-packages.git",
|
|
14
|
+
"directory": "packages/release-script"
|
|
15
|
+
},
|
|
16
16
|
"bugs": {
|
|
17
|
-
"url": "https://github.com/mlaursen/
|
|
17
|
+
"url": "https://github.com/mlaursen/npm-packages/issues"
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
20
20
|
"release",
|
|
21
21
|
"script",
|
|
22
22
|
"npm"
|
|
23
23
|
],
|
|
24
|
+
"license": "MIT",
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"@changesets/cli": "^2.29.
|
|
26
|
-
"@inquirer/confirm": "^
|
|
27
|
-
"@inquirer/input": "^
|
|
28
|
-
"@inquirer/rawlist": "^
|
|
26
|
+
"@changesets/cli": "^2.29.8",
|
|
27
|
+
"@inquirer/confirm": "^6.0.2",
|
|
28
|
+
"@inquirer/input": "^5.0.2",
|
|
29
|
+
"@inquirer/rawlist": "^5.0.2",
|
|
29
30
|
"@octokit/core": "^7.0.6",
|
|
30
31
|
"dotenv": "^17.2.3"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
|
-
"@
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
34
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
35
|
+
"@trivago/prettier-plugin-sort-imports": "^6.0.0",
|
|
36
|
+
"@types/node": "^24.10.1",
|
|
37
|
+
"concurrently": "^9.2.1",
|
|
38
|
+
"eslint": "^9.39.1",
|
|
39
|
+
"prettier": "^3.7.4",
|
|
40
|
+
"rollup": "^4.53.3",
|
|
41
|
+
"rollup-plugin-dts": "^6.3.0",
|
|
42
|
+
"rollup-plugin-swc3": "^0.12.1",
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"@mlaursen/eslint-config": "11.0.1"
|
|
39
45
|
},
|
|
40
46
|
"publishConfig": {
|
|
41
47
|
"access": "public"
|
|
@@ -50,11 +56,20 @@
|
|
|
50
56
|
"pnpm": "10.20.0"
|
|
51
57
|
},
|
|
52
58
|
"scripts": {
|
|
53
|
-
"
|
|
54
|
-
"
|
|
59
|
+
"clean-dist": "rm -rf dist",
|
|
60
|
+
"clean-cache": "rm -rf .turbo node_modules",
|
|
61
|
+
"clean": "concurrently 'pnpm clean-dist' 'pnpm clean-cache'",
|
|
55
62
|
"format": "prettier --write .",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
63
|
+
"check-format": "prettier --check .",
|
|
64
|
+
"lint": "eslint .",
|
|
65
|
+
"lint-fix": "pnpm lint --fix",
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"typecheck-watch": "tsc --noEmit --watch",
|
|
68
|
+
"build-dist": "rollup -c rollup.config.ts",
|
|
69
|
+
"build-dist-watch": "pnpm build-dist --watch",
|
|
70
|
+
"build-types": "tsc -p tsconfig.types.json",
|
|
71
|
+
"build-types-watch": "pnpm build-types --watch",
|
|
72
|
+
"build": "pnpm build-types && pnpm build-dist",
|
|
73
|
+
"dev": "concurrently 'pnpm build-types-watch' 'pnpm build-dist-watch'"
|
|
59
74
|
}
|
|
60
75
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import confirm from "@inquirer/confirm";
|
|
2
|
+
import { Octokit } from "@octokit/core";
|
|
3
|
+
import dotenv from "dotenv";
|
|
4
|
+
|
|
5
|
+
export interface ConfigurableCreateReleaseOptions {
|
|
6
|
+
repo: string;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @defaultValue `"mlaursen"`
|
|
10
|
+
*/
|
|
11
|
+
owner?: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The `.env` file to load to get the {@link tokenName} environment variable.
|
|
15
|
+
*
|
|
16
|
+
* @defaultValue `".env.local"`
|
|
17
|
+
*/
|
|
18
|
+
envPath?: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @defaultValue `"GITHUB_RELEASE_TOKEN"`
|
|
22
|
+
*/
|
|
23
|
+
tokenName?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface CreateReleaseOptions extends ConfigurableCreateReleaseOptions {
|
|
27
|
+
body: string;
|
|
28
|
+
override?: boolean;
|
|
29
|
+
tagName: string;
|
|
30
|
+
prerelease: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function createRelease(
|
|
34
|
+
options: CreateReleaseOptions
|
|
35
|
+
): Promise<void> {
|
|
36
|
+
const {
|
|
37
|
+
body,
|
|
38
|
+
override,
|
|
39
|
+
owner = "mlaursen",
|
|
40
|
+
repo,
|
|
41
|
+
prerelease,
|
|
42
|
+
envPath = ".env.local",
|
|
43
|
+
tagName,
|
|
44
|
+
tokenName = "GITHUB_RELEASE_TOKEN",
|
|
45
|
+
} = options;
|
|
46
|
+
|
|
47
|
+
dotenv.config({ path: envPath, override, quiet: true });
|
|
48
|
+
const octokit = new Octokit({ auth: process.env[tokenName] });
|
|
49
|
+
try {
|
|
50
|
+
const response = await octokit.request(
|
|
51
|
+
"POST /repos/{owner}/{repo}/releases",
|
|
52
|
+
{
|
|
53
|
+
owner,
|
|
54
|
+
repo,
|
|
55
|
+
tag_name: tagName,
|
|
56
|
+
body,
|
|
57
|
+
prerelease,
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
console.log(`Created release: ${response.data.html_url}`);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(error);
|
|
64
|
+
|
|
65
|
+
console.log();
|
|
66
|
+
console.log(
|
|
67
|
+
"The npm token is most likely expired or never created. Update the `.env.local` to include the latest GITHUB_TOKEN"
|
|
68
|
+
);
|
|
69
|
+
console.log(
|
|
70
|
+
"Regenerate the token: https://github.com/settings/personal-access-tokens"
|
|
71
|
+
);
|
|
72
|
+
if (
|
|
73
|
+
!(await confirm({ message: "Try creating the Github release again?" }))
|
|
74
|
+
) {
|
|
75
|
+
throw new Error("Unable to create a Github release");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return createRelease({ ...options, override: true });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import confirm from "@inquirer/confirm";
|
|
2
|
+
import rawlist from "@inquirer/rawlist";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
export async function getCurrentChangeset(): Promise<string> {
|
|
8
|
+
let changesetName = execSync(
|
|
9
|
+
"git diff --name-only @{upstream} .changeset/*.md"
|
|
10
|
+
)
|
|
11
|
+
.toString()
|
|
12
|
+
.trim();
|
|
13
|
+
|
|
14
|
+
if (
|
|
15
|
+
!changesetName ||
|
|
16
|
+
!(await confirm({
|
|
17
|
+
message: `Is "${changesetName}" the correct changeset path?`,
|
|
18
|
+
}))
|
|
19
|
+
) {
|
|
20
|
+
const changesetNames = await readdir(".changeset");
|
|
21
|
+
changesetName = await rawlist({
|
|
22
|
+
message: "Select the changeset path",
|
|
23
|
+
choices: changesetNames
|
|
24
|
+
.filter((changeset) => changeset.endsWith(".md"))
|
|
25
|
+
.map((changeset) => ({
|
|
26
|
+
value: changeset,
|
|
27
|
+
})),
|
|
28
|
+
});
|
|
29
|
+
changesetName = join(".changeset", changesetName);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return await readFile(changesetName, "utf8");
|
|
33
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
export type PackageManager = "npm" | "yarn" | "pnpm";
|
|
5
|
+
|
|
6
|
+
export async function getPackageManager(): Promise<PackageManager> {
|
|
7
|
+
const rawPackageJson = await readFile(
|
|
8
|
+
resolve(process.cwd(), "package.json"),
|
|
9
|
+
"utf8"
|
|
10
|
+
);
|
|
11
|
+
const packageJson = JSON.parse(rawPackageJson);
|
|
12
|
+
|
|
13
|
+
if (typeof packageJson.volta === "object" && packageJson.volta) {
|
|
14
|
+
const { volta } = packageJson;
|
|
15
|
+
if ("pnpm" in volta) {
|
|
16
|
+
return "pnpm";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if ("yarn" in volta) {
|
|
20
|
+
return "yarn";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return "npm";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (typeof packageJson.packageManager === "string") {
|
|
27
|
+
const mgr = packageJson.packageManagerreplace(/@.+/, "");
|
|
28
|
+
|
|
29
|
+
if (mgr === "pnpm" || mgr === "yarn" || mgr === "npm") {
|
|
30
|
+
return mgr;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
throw new Error(`Unsupported package mananger "${mgr}" in package.json`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
throw new Error("Unable to find a package manager");
|
|
37
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import confirm from "@inquirer/confirm";
|
|
2
|
+
import input from "@inquirer/input";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { getUnpushedTags } from "./getUnpushedTags.js";
|
|
7
|
+
|
|
8
|
+
export interface GetPendingReleasesOptions {
|
|
9
|
+
/**
|
|
10
|
+
* This should be a record of package names to paths for monorepos.
|
|
11
|
+
*
|
|
12
|
+
* @example Monorepo Setup
|
|
13
|
+
* ```tsx
|
|
14
|
+
* packagePaths: {
|
|
15
|
+
* "@react-md/core": "./packages/core",
|
|
16
|
+
* "docs": "./apps/docs"
|
|
17
|
+
* },
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* If this is omitted or not matched, it will default to `"."`
|
|
21
|
+
*
|
|
22
|
+
* @defaultValue `{}`
|
|
23
|
+
*/
|
|
24
|
+
packagePaths?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PendingRelease {
|
|
28
|
+
tagName: string;
|
|
29
|
+
body: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function getPendingReleases(
|
|
33
|
+
options: GetPendingReleasesOptions
|
|
34
|
+
): Promise<readonly PendingRelease[]> {
|
|
35
|
+
const { packagePaths = {} } = options;
|
|
36
|
+
const unpushedTags = getUnpushedTags();
|
|
37
|
+
if (unpushedTags.length === 0) {
|
|
38
|
+
throw new Error("Unable to find any pending releases");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const pending: PendingRelease[] = [];
|
|
42
|
+
for (const unpushedTag of unpushedTags) {
|
|
43
|
+
if (
|
|
44
|
+
!(await confirm({ message: `Include ${unpushedTag} in the release?` }))
|
|
45
|
+
) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const name = unpushedTag.replace(/@\d+.+$/, "");
|
|
50
|
+
const path = await input({
|
|
51
|
+
message: `${name} CHANGELOG exists at:`,
|
|
52
|
+
default: packagePaths[name] ?? ".",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const changelog = await readFile(
|
|
56
|
+
resolve(process.cwd(), path, "CHANGELOG.md"),
|
|
57
|
+
"utf8"
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
let body = "";
|
|
61
|
+
let isTracking = false;
|
|
62
|
+
const lines = changelog.split(/\r?\n/);
|
|
63
|
+
for (const line of lines) {
|
|
64
|
+
if (line.startsWith("## ")) {
|
|
65
|
+
if (isTracking) {
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
isTracking = true;
|
|
70
|
+
body = line;
|
|
71
|
+
} else if (isTracking) {
|
|
72
|
+
body += `\n${line}`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
pending.push({
|
|
77
|
+
body,
|
|
78
|
+
tagName: unpushedTag,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return pending;
|
|
83
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
function getTags(local: boolean): Set<string> {
|
|
4
|
+
const command = local
|
|
5
|
+
? "git tag --sort=-creatordate"
|
|
6
|
+
: "git ls-remote --tags origin";
|
|
7
|
+
const tags = execSync(command).toString().trim();
|
|
8
|
+
const lines = tags.split(/\r?\n/);
|
|
9
|
+
if (local) {
|
|
10
|
+
return new Set(lines);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return new Set(
|
|
14
|
+
lines.map((line) => line.replace(/^.+refs\/tags\//, "").replace("^{}", ""))
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getUnpushedTags(): readonly string[] {
|
|
19
|
+
const localTags = getTags(true);
|
|
20
|
+
const pushedTags = getTags(false);
|
|
21
|
+
|
|
22
|
+
return [...localTags.difference(pushedTags)];
|
|
23
|
+
}
|
package/src/index.ts
ADDED
package/src/release.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type ExecSyncOptions, execSync } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
import { continueRelease } from "./continueRelease.js";
|
|
4
|
+
import {
|
|
5
|
+
type ConfigurableCreateReleaseOptions,
|
|
6
|
+
createRelease,
|
|
7
|
+
} from "./createRelease.js";
|
|
8
|
+
import { getPackageManager } from "./getPackageManager.js";
|
|
9
|
+
import {
|
|
10
|
+
type GetPendingReleasesOptions,
|
|
11
|
+
getPendingReleases,
|
|
12
|
+
} from "./getPendingReleases.js";
|
|
13
|
+
|
|
14
|
+
const exec = (command: string, opts?: ExecSyncOptions): void => {
|
|
15
|
+
console.log(command);
|
|
16
|
+
execSync(command, opts);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export interface ReleaseOptions
|
|
20
|
+
extends ConfigurableCreateReleaseOptions, GetPendingReleasesOptions {
|
|
21
|
+
/**
|
|
22
|
+
* @defaultValue `!buildCommand`
|
|
23
|
+
*/
|
|
24
|
+
skipBuild?: boolean;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @defaultValue `"clean"`
|
|
28
|
+
*/
|
|
29
|
+
cleanCommand?: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @defaultValue `"build"`
|
|
33
|
+
*/
|
|
34
|
+
buildCommand?: string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @defaultValue `"build(version): version package"`
|
|
38
|
+
*/
|
|
39
|
+
versionMessage?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function release(options: ReleaseOptions): Promise<void> {
|
|
43
|
+
const {
|
|
44
|
+
owner,
|
|
45
|
+
repo,
|
|
46
|
+
envPath,
|
|
47
|
+
cleanCommand = "clean",
|
|
48
|
+
buildCommand = "build",
|
|
49
|
+
skipBuild = !buildCommand,
|
|
50
|
+
versionMessage = "build(version): version package",
|
|
51
|
+
} = options;
|
|
52
|
+
|
|
53
|
+
const pkgManager = await getPackageManager();
|
|
54
|
+
|
|
55
|
+
if (!skipBuild) {
|
|
56
|
+
exec(`${pkgManager} ${cleanCommand}`);
|
|
57
|
+
exec(`${pkgManager} ${buildCommand}`);
|
|
58
|
+
}
|
|
59
|
+
await continueRelease();
|
|
60
|
+
|
|
61
|
+
exec("pnpm changeset version", { stdio: "inherit" });
|
|
62
|
+
exec("git add -u");
|
|
63
|
+
await continueRelease();
|
|
64
|
+
|
|
65
|
+
exec(`git commit -m "${versionMessage}"`);
|
|
66
|
+
exec(`${pkgManager} changeset publish`, { stdio: "inherit" });
|
|
67
|
+
const pendingReleases = await getPendingReleases(options);
|
|
68
|
+
|
|
69
|
+
exec("git push --follow-tags");
|
|
70
|
+
|
|
71
|
+
for (const release of pendingReleases) {
|
|
72
|
+
await createRelease({
|
|
73
|
+
owner,
|
|
74
|
+
repo,
|
|
75
|
+
body: release.body,
|
|
76
|
+
tagName: release.tagName,
|
|
77
|
+
envPath,
|
|
78
|
+
prerelease: /-(alpha|next|beta)\.\d+$/.test(release.tagName),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function continueRelease(): Promise<void>;
|
package/dist/continueRelease.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function createGetTagName(mainPackage: string | undefined): () => Promise<string>;
|
package/dist/createGetTagName.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import confirm from "@inquirer/confirm";
|
|
2
|
-
import input from "@inquirer/input";
|
|
3
|
-
import { getLatestTag } from "./getLatestTag.js";
|
|
4
|
-
export function createGetTagName(mainPackage) {
|
|
5
|
-
return async function getTagName() {
|
|
6
|
-
const latestTag = getLatestTag();
|
|
7
|
-
let tagName = mainPackage && /@\d/.test(latestTag)
|
|
8
|
-
? // most likely a monorepo
|
|
9
|
-
latestTag.replace(/.+(@\d)/, `${mainPackage}$1`)
|
|
10
|
-
: latestTag;
|
|
11
|
-
while (!tagName ||
|
|
12
|
-
!(await confirm({ message: `Use "${tagName}" for the next tag name?` }))) {
|
|
13
|
-
tagName = await input({
|
|
14
|
-
message: "Enter the tag name",
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return tagName;
|
|
18
|
-
};
|
|
19
|
-
}
|
package/dist/createRelease.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface ConfigurableCreateReleaseOptions {
|
|
2
|
-
repo: string;
|
|
3
|
-
/**
|
|
4
|
-
* @defaultValue `"mlaursen"`
|
|
5
|
-
*/
|
|
6
|
-
owner?: string;
|
|
7
|
-
/**
|
|
8
|
-
* The `.env` file to load to get the {@link tokenName} environment variable.
|
|
9
|
-
*
|
|
10
|
-
* @defaultValue `".env.local"`
|
|
11
|
-
*/
|
|
12
|
-
envPath?: string;
|
|
13
|
-
/**
|
|
14
|
-
* @defaultValue `"GITHUB_RELEASE_TOKEN"`
|
|
15
|
-
*/
|
|
16
|
-
tokenName?: string;
|
|
17
|
-
}
|
|
18
|
-
export interface CreateReleaseOptions extends ConfigurableCreateReleaseOptions {
|
|
19
|
-
body: string;
|
|
20
|
-
override?: boolean;
|
|
21
|
-
tagName: string;
|
|
22
|
-
prerelease: boolean;
|
|
23
|
-
}
|
|
24
|
-
export declare function createRelease(options: CreateReleaseOptions): Promise<void>;
|
package/dist/createRelease.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import confirm from "@inquirer/confirm";
|
|
2
|
-
import { Octokit } from "@octokit/core";
|
|
3
|
-
import dotenv from "dotenv";
|
|
4
|
-
export async function createRelease(options) {
|
|
5
|
-
const { body, override, owner = "mlaursen", repo, prerelease, envPath = ".env.local", tagName, tokenName = "GITHUB_RELEASE_TOKEN", } = options;
|
|
6
|
-
dotenv.config({ path: envPath, override, quiet: true });
|
|
7
|
-
const octokit = new Octokit({ auth: process.env[tokenName] });
|
|
8
|
-
try {
|
|
9
|
-
const response = await octokit.request("POST /repos/{owner}/{repo}/releases", {
|
|
10
|
-
owner,
|
|
11
|
-
repo,
|
|
12
|
-
tag_name: tagName,
|
|
13
|
-
body,
|
|
14
|
-
prerelease,
|
|
15
|
-
});
|
|
16
|
-
console.log(`Created release: ${response.data.html_url}`);
|
|
17
|
-
}
|
|
18
|
-
catch (e) {
|
|
19
|
-
console.error(e);
|
|
20
|
-
console.log();
|
|
21
|
-
console.log("The npm token is most likely expired or never created. Update the `.env.local` to include the latest GITHUB_TOKEN");
|
|
22
|
-
console.log("Regenerate the token: https://github.com/settings/personal-access-tokens");
|
|
23
|
-
if (!(await confirm({ message: "Try creating the Github release again?" }))) {
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
return createRelease({ ...options, override: true });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getCurrentChangeset(): Promise<string>;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import confirm from "@inquirer/confirm";
|
|
2
|
-
import rawlist from "@inquirer/rawlist";
|
|
3
|
-
import { execSync } from "node:child_process";
|
|
4
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
export async function getCurrentChangeset() {
|
|
7
|
-
let changesetName = execSync("git diff --name-only @{upstream} .changeset/*.md")
|
|
8
|
-
.toString()
|
|
9
|
-
.trim();
|
|
10
|
-
if (!changesetName ||
|
|
11
|
-
!(await confirm({
|
|
12
|
-
message: `Is "${changesetName}" the correct changeset path?`,
|
|
13
|
-
}))) {
|
|
14
|
-
const changesetNames = await readdir(".changeset");
|
|
15
|
-
changesetName = await rawlist({
|
|
16
|
-
message: "Select the changeset path",
|
|
17
|
-
choices: changesetNames
|
|
18
|
-
.filter((changeset) => changeset.endsWith(".md"))
|
|
19
|
-
.map((changeset) => ({
|
|
20
|
-
value: changeset,
|
|
21
|
-
})),
|
|
22
|
-
});
|
|
23
|
-
changesetName = join(".changeset", changesetName);
|
|
24
|
-
}
|
|
25
|
-
return await readFile(changesetName, "utf8");
|
|
26
|
-
}
|
package/dist/getLatestTag.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getLatestTag(): string;
|
package/dist/getLatestTag.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
export async function getPackageManager() {
|
|
4
|
-
const rawPackageJson = await readFile(resolve(process.cwd(), "package.json"), "utf8");
|
|
5
|
-
const packageJson = JSON.parse(rawPackageJson);
|
|
6
|
-
if (typeof packageJson.volta === "object" && packageJson.volta) {
|
|
7
|
-
const { volta } = packageJson;
|
|
8
|
-
if ("pnpm" in volta) {
|
|
9
|
-
return "pnpm";
|
|
10
|
-
}
|
|
11
|
-
if ("yarn" in volta) {
|
|
12
|
-
return "yarn";
|
|
13
|
-
}
|
|
14
|
-
return "npm";
|
|
15
|
-
}
|
|
16
|
-
if (typeof packageJson.packageManager === "string") {
|
|
17
|
-
const mgr = packageJson.packageManagerreplace(/@.+/, "");
|
|
18
|
-
if (mgr === "pnpm" || mgr === "yarn" || mgr === "npm") {
|
|
19
|
-
return mgr;
|
|
20
|
-
}
|
|
21
|
-
throw new Error(`Unsupported package mananger "${mgr}" in package.json`);
|
|
22
|
-
}
|
|
23
|
-
throw new Error("Unable to find a package manager");
|
|
24
|
-
}
|
package/dist/index.js
DELETED
package/dist/release.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { ConfigurableCreateReleaseOptions } from "./createRelease.js";
|
|
2
|
-
export interface ReleaseOptions extends ConfigurableCreateReleaseOptions {
|
|
3
|
-
/**
|
|
4
|
-
* @defaultValue `!buildCommand`
|
|
5
|
-
*/
|
|
6
|
-
skipBuild?: boolean;
|
|
7
|
-
/**
|
|
8
|
-
* @defaultValue `"clean"`
|
|
9
|
-
*/
|
|
10
|
-
cleanCommand?: string;
|
|
11
|
-
/**
|
|
12
|
-
* @defaultValue `"build"`
|
|
13
|
-
*/
|
|
14
|
-
buildCommand?: string;
|
|
15
|
-
mainPackage?: string;
|
|
16
|
-
/**
|
|
17
|
-
* @defaultValue `"build(version): version package"`
|
|
18
|
-
*/
|
|
19
|
-
versionMessage?: string;
|
|
20
|
-
getTagName?: () => Promise<string>;
|
|
21
|
-
}
|
|
22
|
-
export declare function release(options: ReleaseOptions): Promise<void>;
|
package/dist/release.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
2
|
-
import { continueRelease } from "./continueRelease.js";
|
|
3
|
-
import { createGetTagName } from "./createGetTagName.js";
|
|
4
|
-
import { createRelease, } from "./createRelease.js";
|
|
5
|
-
import { getCurrentChangeset } from "./getCurrentChangeset.js";
|
|
6
|
-
import { getPackageManager } from "./getPackageManager.js";
|
|
7
|
-
const exec = (command, opts) => {
|
|
8
|
-
console.log(command);
|
|
9
|
-
execSync(command, opts);
|
|
10
|
-
};
|
|
11
|
-
export async function release(options) {
|
|
12
|
-
const { owner, repo, envPath, cleanCommand = "clean", buildCommand = "build", skipBuild = !buildCommand, mainPackage, getTagName = createGetTagName(mainPackage), versionMessage = "build(version): version package", } = options;
|
|
13
|
-
const pkgManager = await getPackageManager();
|
|
14
|
-
if (!skipBuild) {
|
|
15
|
-
exec(`${pkgManager} ${cleanCommand}`);
|
|
16
|
-
exec(`${pkgManager} ${buildCommand}`);
|
|
17
|
-
}
|
|
18
|
-
exec(`${pkgManager} changeset`, { stdio: "inherit" });
|
|
19
|
-
await continueRelease();
|
|
20
|
-
exec("git add -u");
|
|
21
|
-
exec("git add .changeset");
|
|
22
|
-
const changeset = await getCurrentChangeset();
|
|
23
|
-
exec("pnpm changeset version", { stdio: "inherit" });
|
|
24
|
-
exec("git add -u");
|
|
25
|
-
await continueRelease();
|
|
26
|
-
exec(`git commit -m "${versionMessage}"`);
|
|
27
|
-
exec(`${pkgManager} changeset publish`, { stdio: "inherit" });
|
|
28
|
-
const tagName = await getTagName();
|
|
29
|
-
await continueRelease();
|
|
30
|
-
exec("git push --follow-tags");
|
|
31
|
-
await createRelease({
|
|
32
|
-
owner,
|
|
33
|
-
repo,
|
|
34
|
-
body: changeset,
|
|
35
|
-
tagName,
|
|
36
|
-
envPath,
|
|
37
|
-
prerelease: /-(alpha|next|beta)\.\d+$/.test(tagName),
|
|
38
|
-
});
|
|
39
|
-
}
|