@varlet/release 0.0.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/bin/index.js ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { release, changelog } from '../dist/index.js'
3
+ import { Command } from 'commander'
4
+
5
+ const program = new Command()
6
+
7
+ program
8
+ .command('release')
9
+ .option('-r --remote <remote>', 'Remote name')
10
+ .option('-o --otp <otp>', 'One-time password')
11
+ .description('Release all packages and generate changelogs')
12
+ .action(async (options) => release(options))
13
+
14
+ program
15
+ .command('changelog')
16
+ .option('-rc --releaseCount <releaseCount>', 'Release count')
17
+ .option('-f --file <file>', 'Changelog filename')
18
+ .description('Generate changelog')
19
+ .action(async (options) => changelog(options))
20
+
21
+ program.parse()
package/dist/index.cjs ADDED
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ changelog: () => changelog,
34
+ release: () => release
35
+ });
36
+ module.exports = __toCommonJS(src_exports);
37
+
38
+ // src/release.ts
39
+ var import_nanospinner2 = require("nanospinner");
40
+ var import_fs_extra2 = __toESM(require("fs-extra"), 1);
41
+ var import_execa = require("execa");
42
+ var import_rslog = require("rslog");
43
+ var import_semver = __toESM(require("semver"), 1);
44
+ var import_glob = require("glob");
45
+ var import_inquirer = __toESM(require("inquirer"), 1);
46
+ var import_path2 = require("path");
47
+
48
+ // src/changelog.ts
49
+ var import_conventional_changelog = __toESM(require("conventional-changelog"), 1);
50
+ var import_fs_extra = __toESM(require("fs-extra"), 1);
51
+ var import_nanospinner = require("nanospinner");
52
+ var import_path = require("path");
53
+ var { createWriteStream } = import_fs_extra.default;
54
+ function changelog({ releaseCount = 0, file = "CHANGELOG.md" } = {}) {
55
+ const s = (0, import_nanospinner.createSpinner)("Generating changelog").start();
56
+ return new Promise((resolve2) => {
57
+ (0, import_conventional_changelog.default)({
58
+ preset: "angular",
59
+ releaseCount
60
+ }).pipe(createWriteStream((0, import_path.resolve)(process.cwd(), file))).on("close", () => {
61
+ s.success({ text: "Changelog generated success!" });
62
+ resolve2();
63
+ });
64
+ });
65
+ }
66
+
67
+ // src/release.ts
68
+ var cwd = process.cwd();
69
+ var { writeFileSync, readJSONSync } = import_fs_extra2.default;
70
+ var { prompt } = import_inquirer.default;
71
+ var releaseTypes = ["premajor", "preminor", "prepatch", "major", "minor", "patch"];
72
+ async function isWorktreeEmpty() {
73
+ const ret = await (0, import_execa.execa)("git", ["status", "--porcelain"]);
74
+ return !ret.stdout;
75
+ }
76
+ async function publish(preRelease, otp) {
77
+ const s = (0, import_nanospinner2.createSpinner)("Publishing all packages").start();
78
+ const args = ["-r", "publish", "--no-git-checks", "--access", "public"];
79
+ if (preRelease) {
80
+ args.push("--tag", "alpha");
81
+ }
82
+ if (otp) {
83
+ args.push(`--otp=${otp}`);
84
+ }
85
+ const ret = await (0, import_execa.execa)("pnpm", args);
86
+ if (ret.stderr && ret.stderr.includes("npm ERR!")) {
87
+ throw new Error("\n" + ret.stderr);
88
+ } else {
89
+ s.success({ text: "Publish all packages successfully" });
90
+ ret.stdout && import_rslog.logger.info(ret.stdout);
91
+ }
92
+ }
93
+ async function pushGit(version, remote = "origin") {
94
+ const s = (0, import_nanospinner2.createSpinner)("Pushing to remote git repository").start();
95
+ await (0, import_execa.execa)("git", ["add", "."]);
96
+ await (0, import_execa.execa)("git", ["commit", "-m", `v${version}`]);
97
+ await (0, import_execa.execa)("git", ["tag", `v${version}`]);
98
+ await (0, import_execa.execa)("git", ["push", remote, `v${version}`]);
99
+ const ret = await (0, import_execa.execa)("git", ["push"]);
100
+ s.success({ text: "Push remote repository successfully" });
101
+ ret.stdout && import_rslog.logger.info(ret.stdout);
102
+ }
103
+ function updateVersion(version) {
104
+ const packageJsons = import_glob.glob.sync("packages/*/package.json");
105
+ packageJsons.push("package.json");
106
+ packageJsons.forEach((path) => {
107
+ const file = (0, import_path2.resolve)(cwd, path);
108
+ const config = readJSONSync(file);
109
+ config.version = version;
110
+ writeFileSync(file, JSON.stringify(config, null, 2));
111
+ });
112
+ }
113
+ async function confirmRegistry() {
114
+ const registry = (await (0, import_execa.execa)("npm", ["config", "get", "registry"])).stdout;
115
+ const name = "Registry confirm";
116
+ const ret = await prompt([
117
+ {
118
+ name,
119
+ type: "confirm",
120
+ message: `Current registry is: ${registry}`
121
+ }
122
+ ]);
123
+ return ret[name];
124
+ }
125
+ async function confirmVersion(currentVersion, expectVersion) {
126
+ const name = "Version confirm";
127
+ const ret = await prompt([
128
+ {
129
+ name,
130
+ type: "confirm",
131
+ message: `All packages version ${currentVersion} -> ${expectVersion}:`
132
+ }
133
+ ]);
134
+ return ret[name];
135
+ }
136
+ async function confirmRefs(remote = "origin") {
137
+ const { stdout } = await (0, import_execa.execa)("git", ["remote", "-v"]);
138
+ const reg = new RegExp(`${remote} (.*) \\(push`);
139
+ const repo = stdout.match(reg)?.[1];
140
+ const { stdout: branch } = await (0, import_execa.execa)("git", ["branch", "--show-current"]);
141
+ const name = "Refs confirm";
142
+ const ret = await prompt([
143
+ {
144
+ name,
145
+ type: "confirm",
146
+ message: `Current refs ${repo}:refs/for/${branch}`
147
+ }
148
+ ]);
149
+ return ret[name];
150
+ }
151
+ async function getReleaseType() {
152
+ const name = "Please select release type";
153
+ const ret = await prompt([
154
+ {
155
+ name,
156
+ type: "list",
157
+ choices: releaseTypes
158
+ }
159
+ ]);
160
+ return ret[name];
161
+ }
162
+ async function release(options) {
163
+ try {
164
+ const currentVersion = readJSONSync((0, import_path2.resolve)(cwd, "package.json")).version;
165
+ if (!currentVersion) {
166
+ import_rslog.logger.error("Your package is missing the version field");
167
+ return;
168
+ }
169
+ if (!await isWorktreeEmpty()) {
170
+ import_rslog.logger.error("Git worktree is not empty, please commit changed");
171
+ return;
172
+ }
173
+ if (!await confirmRefs(options.remote)) {
174
+ return;
175
+ }
176
+ if (!await confirmRegistry()) {
177
+ return;
178
+ }
179
+ const type = await getReleaseType();
180
+ const isPreRelease = type.startsWith("pre");
181
+ let expectVersion = import_semver.default.inc(currentVersion, type, `alpha.${Date.now()}`);
182
+ expectVersion = isPreRelease ? expectVersion.slice(0, -2) : expectVersion;
183
+ if (!await confirmVersion(currentVersion, expectVersion)) {
184
+ return;
185
+ }
186
+ updateVersion(expectVersion);
187
+ if (options.task) {
188
+ await options.task();
189
+ }
190
+ await publish(isPreRelease, options.otp);
191
+ if (!isPreRelease) {
192
+ await changelog();
193
+ await pushGit(expectVersion, options.remote);
194
+ }
195
+ import_rslog.logger.success(`Release version ${expectVersion} successfully!`);
196
+ if (isPreRelease) {
197
+ try {
198
+ await (0, import_execa.execa)("git", ["restore", "**/package.json"]);
199
+ await (0, import_execa.execa)("git", ["restore", "package.json"]);
200
+ } catch {
201
+ import_rslog.logger.error("Restore package.json has failed, please restore manually");
202
+ }
203
+ }
204
+ } catch (error) {
205
+ import_rslog.logger.error(error.toString());
206
+ process.exit(1);
207
+ }
208
+ }
209
+ // Annotate the CommonJS export names for ESM import in node:
210
+ 0 && (module.exports = {
211
+ changelog,
212
+ release
213
+ });
@@ -0,0 +1,14 @@
1
+ interface ReleaseCommandOptions {
2
+ remote?: string;
3
+ otp?: string;
4
+ task?(): Promise<void>;
5
+ }
6
+ declare function release(options: ReleaseCommandOptions): Promise<void>;
7
+
8
+ interface ChangelogCommandOptions {
9
+ file?: string;
10
+ releaseCount?: number;
11
+ }
12
+ declare function changelog({ releaseCount, file }?: ChangelogCommandOptions): Promise<void>;
13
+
14
+ export { changelog, release };
@@ -0,0 +1,14 @@
1
+ interface ReleaseCommandOptions {
2
+ remote?: string;
3
+ otp?: string;
4
+ task?(): Promise<void>;
5
+ }
6
+ declare function release(options: ReleaseCommandOptions): Promise<void>;
7
+
8
+ interface ChangelogCommandOptions {
9
+ file?: string;
10
+ releaseCount?: number;
11
+ }
12
+ declare function changelog({ releaseCount, file }?: ChangelogCommandOptions): Promise<void>;
13
+
14
+ export { changelog, release };
package/dist/index.js ADDED
@@ -0,0 +1,175 @@
1
+ // src/release.ts
2
+ import { createSpinner as createSpinner2 } from "nanospinner";
3
+ import fse2 from "fs-extra";
4
+ import { execa } from "execa";
5
+ import { logger } from "rslog";
6
+ import semver from "semver";
7
+ import { glob } from "glob";
8
+ import inquirer from "inquirer";
9
+ import { resolve } from "path";
10
+
11
+ // src/changelog.ts
12
+ import conventionalChangelog from "conventional-changelog";
13
+ import fse from "fs-extra";
14
+ import { createSpinner } from "nanospinner";
15
+ import { resolve as resolvePath } from "path";
16
+ var { createWriteStream } = fse;
17
+ function changelog({ releaseCount = 0, file = "CHANGELOG.md" } = {}) {
18
+ const s = createSpinner("Generating changelog").start();
19
+ return new Promise((resolve2) => {
20
+ conventionalChangelog({
21
+ preset: "angular",
22
+ releaseCount
23
+ }).pipe(createWriteStream(resolvePath(process.cwd(), file))).on("close", () => {
24
+ s.success({ text: "Changelog generated success!" });
25
+ resolve2();
26
+ });
27
+ });
28
+ }
29
+
30
+ // src/release.ts
31
+ var cwd = process.cwd();
32
+ var { writeFileSync, readJSONSync } = fse2;
33
+ var { prompt } = inquirer;
34
+ var releaseTypes = ["premajor", "preminor", "prepatch", "major", "minor", "patch"];
35
+ async function isWorktreeEmpty() {
36
+ const ret = await execa("git", ["status", "--porcelain"]);
37
+ return !ret.stdout;
38
+ }
39
+ async function publish(preRelease, otp) {
40
+ const s = createSpinner2("Publishing all packages").start();
41
+ const args = ["-r", "publish", "--no-git-checks", "--access", "public"];
42
+ if (preRelease) {
43
+ args.push("--tag", "alpha");
44
+ }
45
+ if (otp) {
46
+ args.push(`--otp=${otp}`);
47
+ }
48
+ const ret = await execa("pnpm", args);
49
+ if (ret.stderr && ret.stderr.includes("npm ERR!")) {
50
+ throw new Error("\n" + ret.stderr);
51
+ } else {
52
+ s.success({ text: "Publish all packages successfully" });
53
+ ret.stdout && logger.info(ret.stdout);
54
+ }
55
+ }
56
+ async function pushGit(version, remote = "origin") {
57
+ const s = createSpinner2("Pushing to remote git repository").start();
58
+ await execa("git", ["add", "."]);
59
+ await execa("git", ["commit", "-m", `v${version}`]);
60
+ await execa("git", ["tag", `v${version}`]);
61
+ await execa("git", ["push", remote, `v${version}`]);
62
+ const ret = await execa("git", ["push"]);
63
+ s.success({ text: "Push remote repository successfully" });
64
+ ret.stdout && logger.info(ret.stdout);
65
+ }
66
+ function updateVersion(version) {
67
+ const packageJsons = glob.sync("packages/*/package.json");
68
+ packageJsons.push("package.json");
69
+ packageJsons.forEach((path) => {
70
+ const file = resolve(cwd, path);
71
+ const config = readJSONSync(file);
72
+ config.version = version;
73
+ writeFileSync(file, JSON.stringify(config, null, 2));
74
+ });
75
+ }
76
+ async function confirmRegistry() {
77
+ const registry = (await execa("npm", ["config", "get", "registry"])).stdout;
78
+ const name = "Registry confirm";
79
+ const ret = await prompt([
80
+ {
81
+ name,
82
+ type: "confirm",
83
+ message: `Current registry is: ${registry}`
84
+ }
85
+ ]);
86
+ return ret[name];
87
+ }
88
+ async function confirmVersion(currentVersion, expectVersion) {
89
+ const name = "Version confirm";
90
+ const ret = await prompt([
91
+ {
92
+ name,
93
+ type: "confirm",
94
+ message: `All packages version ${currentVersion} -> ${expectVersion}:`
95
+ }
96
+ ]);
97
+ return ret[name];
98
+ }
99
+ async function confirmRefs(remote = "origin") {
100
+ const { stdout } = await execa("git", ["remote", "-v"]);
101
+ const reg = new RegExp(`${remote} (.*) \\(push`);
102
+ const repo = stdout.match(reg)?.[1];
103
+ const { stdout: branch } = await execa("git", ["branch", "--show-current"]);
104
+ const name = "Refs confirm";
105
+ const ret = await prompt([
106
+ {
107
+ name,
108
+ type: "confirm",
109
+ message: `Current refs ${repo}:refs/for/${branch}`
110
+ }
111
+ ]);
112
+ return ret[name];
113
+ }
114
+ async function getReleaseType() {
115
+ const name = "Please select release type";
116
+ const ret = await prompt([
117
+ {
118
+ name,
119
+ type: "list",
120
+ choices: releaseTypes
121
+ }
122
+ ]);
123
+ return ret[name];
124
+ }
125
+ async function release(options) {
126
+ try {
127
+ const currentVersion = readJSONSync(resolve(cwd, "package.json")).version;
128
+ if (!currentVersion) {
129
+ logger.error("Your package is missing the version field");
130
+ return;
131
+ }
132
+ if (!await isWorktreeEmpty()) {
133
+ logger.error("Git worktree is not empty, please commit changed");
134
+ return;
135
+ }
136
+ if (!await confirmRefs(options.remote)) {
137
+ return;
138
+ }
139
+ if (!await confirmRegistry()) {
140
+ return;
141
+ }
142
+ const type = await getReleaseType();
143
+ const isPreRelease = type.startsWith("pre");
144
+ let expectVersion = semver.inc(currentVersion, type, `alpha.${Date.now()}`);
145
+ expectVersion = isPreRelease ? expectVersion.slice(0, -2) : expectVersion;
146
+ if (!await confirmVersion(currentVersion, expectVersion)) {
147
+ return;
148
+ }
149
+ updateVersion(expectVersion);
150
+ if (options.task) {
151
+ await options.task();
152
+ }
153
+ await publish(isPreRelease, options.otp);
154
+ if (!isPreRelease) {
155
+ await changelog();
156
+ await pushGit(expectVersion, options.remote);
157
+ }
158
+ logger.success(`Release version ${expectVersion} successfully!`);
159
+ if (isPreRelease) {
160
+ try {
161
+ await execa("git", ["restore", "**/package.json"]);
162
+ await execa("git", ["restore", "package.json"]);
163
+ } catch {
164
+ logger.error("Restore package.json has failed, please restore manually");
165
+ }
166
+ }
167
+ } catch (error) {
168
+ logger.error(error.toString());
169
+ process.exit(1);
170
+ }
171
+ }
172
+ export {
173
+ changelog,
174
+ release
175
+ };
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@varlet/release",
3
+ "type": "module",
4
+ "version": "0.0.1",
5
+ "description": "release all packages and generate changelogs",
6
+ "keywords": [
7
+ "varlet",
8
+ "release",
9
+ "changelog"
10
+ ],
11
+ "author": "clencat <2091927351@qq.com>",
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/varletjs/release"
16
+ },
17
+ "bugs": "https://github.com/varletjs/release/issues",
18
+ "main": "./dist/index.js",
19
+ "module": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js",
25
+ "require": "./dist/index.cjs"
26
+ }
27
+ },
28
+ "bin": {
29
+ "vr": "bin/index.js"
30
+ },
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "packageManager": "pnpm@8.7.5",
35
+ "engines": {
36
+ "node": ">=16.0.0",
37
+ "pnpm": ">=8.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/conventional-changelog": "^3.1.5",
41
+ "@types/fs-extra": "^11.0.4",
42
+ "@types/inquirer": "^9.0.7",
43
+ "@types/node": "^20.9.0",
44
+ "@types/semver": "^7.5.5",
45
+ "@varlet/eslint-config": "^2.18.4",
46
+ "eslint": "^8.53.0",
47
+ "prettier": "^3.1.0",
48
+ "typescript": "^5.2.2",
49
+ "unbuild": "^2.0.0"
50
+ },
51
+ "dependencies": {
52
+ "commander": "^11.1.0",
53
+ "conventional-changelog": "^5.1.0",
54
+ "execa": "^8.0.1",
55
+ "fs-extra": "^11.1.1",
56
+ "glob": "^10.3.10",
57
+ "inquirer": "^9.2.12",
58
+ "nanospinner": "^1.1.0",
59
+ "rslog": "^1.1.0",
60
+ "semver": "^7.5.4",
61
+ "tsup": "^7.2.0"
62
+ },
63
+ "scripts": {
64
+ "preinstall": "npx only-allow pnpm",
65
+ "build": "tsc --noEmit && tsup",
66
+ "dev": "node bin/index.js",
67
+ "release": "pnpm run build && pnpm run dev release",
68
+ "checkAll": "tsc --noEmit && eslint --ext .ts,.js"
69
+ }
70
+ }