relizy 0.2.5-beta.9 → 0.2.5
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/cli.mjs +9 -7
- package/dist/index.d.mts +44 -9
- package/dist/index.d.ts +44 -9
- package/dist/index.mjs +6 -6
- package/dist/shared/{relizy.DXsVzrS_.mjs → relizy.CU6Hj4K0.mjs} +1320 -1184
- package/package.json +23 -21
|
@@ -1,564 +1,1018 @@
|
|
|
1
1
|
import { logger, execPromise } from '@maz-ui/node';
|
|
2
|
-
import
|
|
3
|
-
import { execSync } from 'node:child_process';
|
|
4
|
-
import { existsSync, readFileSync, writeFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
5
3
|
import path, { join, relative } from 'node:path';
|
|
6
|
-
import {
|
|
7
|
-
import { setupDotenv, loadConfig } from 'c12';
|
|
8
|
-
import { formatCompareChanges, formatReference, resolveRepoConfig, getRepoConfig, createGithubRelease, getGitDiff, parseCommits } from 'changelogen';
|
|
9
|
-
import { defu } from 'defu';
|
|
4
|
+
import { getGitDiff, parseCommits, formatCompareChanges, formatReference, resolveRepoConfig, getRepoConfig, createGithubRelease } from 'changelogen';
|
|
10
5
|
import fastGlob from 'fast-glob';
|
|
11
6
|
import { confirm, input } from '@inquirer/prompts';
|
|
7
|
+
import { upperFirst, formatJson } from '@maz-ui/utils';
|
|
12
8
|
import * as semver from 'semver';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
import process$1, { exit } from 'node:process';
|
|
11
|
+
import { setupDotenv, loadConfig } from 'c12';
|
|
12
|
+
import { defu } from 'defu';
|
|
13
13
|
import { convert } from 'convert-gitmoji';
|
|
14
14
|
import { fetch as fetch$1 } from 'node-fetch-native';
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
const result = await hookInput(config, dryRun, params);
|
|
25
|
-
if (result)
|
|
26
|
-
logger.debug(`Hook ${hook} returned: ${result}`);
|
|
27
|
-
logger.info(`Hook ${hook} executed`);
|
|
28
|
-
return result;
|
|
16
|
+
function getPackageDependencies({
|
|
17
|
+
packagePath,
|
|
18
|
+
allPackageNames,
|
|
19
|
+
dependencyTypes
|
|
20
|
+
}) {
|
|
21
|
+
const packageJsonPath = join(packagePath, "package.json");
|
|
22
|
+
if (!existsSync(packageJsonPath)) {
|
|
23
|
+
return [];
|
|
29
24
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return result;
|
|
25
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
26
|
+
const deps = [];
|
|
27
|
+
const allDeps = {
|
|
28
|
+
...dependencyTypes?.includes("dependencies") ? packageJson.dependencies : {},
|
|
29
|
+
...dependencyTypes?.includes("peerDependencies") ? packageJson.peerDependencies : {},
|
|
30
|
+
...dependencyTypes?.includes("devDependencies") ? packageJson.devDependencies : {}
|
|
31
|
+
};
|
|
32
|
+
for (const depName of Object.keys(allDeps)) {
|
|
33
|
+
if (allPackageNames.has(depName)) {
|
|
34
|
+
deps.push(depName);
|
|
35
|
+
}
|
|
42
36
|
}
|
|
37
|
+
return deps;
|
|
43
38
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
function getDependentsOf({
|
|
40
|
+
allPackages,
|
|
41
|
+
packageName
|
|
42
|
+
}) {
|
|
43
|
+
return allPackages.filter(
|
|
44
|
+
(pkg) => pkg.dependencies.includes(packageName)
|
|
47
45
|
);
|
|
48
46
|
}
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (process.env.GITLAB_CI === "true")
|
|
53
|
-
return "GitLab CI";
|
|
54
|
-
if (process.env.CIRCLECI === "true")
|
|
55
|
-
return "CircleCI";
|
|
56
|
-
if (process.env.TRAVIS === "true")
|
|
57
|
-
return "Travis CI";
|
|
58
|
-
if (process.env.JENKINS_HOME || process.env.JENKINS_URL)
|
|
59
|
-
return "Jenkins";
|
|
60
|
-
if (process.env.TF_BUILD === "True")
|
|
61
|
-
return "Azure Pipelines";
|
|
62
|
-
if (process.env.TEAMCITY_VERSION)
|
|
63
|
-
return "TeamCity";
|
|
64
|
-
if (process.env.BITBUCKET_BUILD_NUMBER)
|
|
65
|
-
return "Bitbucket Pipelines";
|
|
66
|
-
if (process.env.DRONE === "true")
|
|
67
|
-
return "Drone";
|
|
68
|
-
if (process.env.APPVEYOR)
|
|
69
|
-
return "AppVeyor";
|
|
70
|
-
if (process.env.BUILDKITE === "true")
|
|
71
|
-
return "Buildkite";
|
|
72
|
-
if (process.env.CODEBUILD_BUILD_ID)
|
|
73
|
-
return "AWS CodeBuild";
|
|
74
|
-
if (process.env.NETLIFY === "true")
|
|
75
|
-
return "Netlify";
|
|
76
|
-
if (process.env.VERCEL === "1")
|
|
77
|
-
return "Vercel";
|
|
78
|
-
if (process.env.HEROKU_TEST_RUN_ID)
|
|
79
|
-
return "Heroku CI";
|
|
80
|
-
if (process.env.BUDDY === "true")
|
|
81
|
-
return "Buddy";
|
|
82
|
-
if (process.env.SEMAPHORE === "true")
|
|
83
|
-
return "Semaphore";
|
|
84
|
-
if (process.env.CF_BUILD_ID)
|
|
85
|
-
return "Codefresh";
|
|
86
|
-
if (process.env.bamboo_buildKey)
|
|
87
|
-
return "Bamboo";
|
|
88
|
-
if (process.env.BUILD_ID && process.env.PROJECT_ID)
|
|
89
|
-
return "Google Cloud Build";
|
|
90
|
-
if (process.env.SCREWDRIVER === "true")
|
|
91
|
-
return "Screwdriver";
|
|
92
|
-
if (process.env.STRIDER === "true")
|
|
93
|
-
return "Strider";
|
|
94
|
-
if (process.env.CI === "true")
|
|
95
|
-
return "Unknown CI";
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
async function executeFormatCmd({
|
|
99
|
-
config,
|
|
100
|
-
dryRun
|
|
47
|
+
function expandPackagesToBumpWithDependents({
|
|
48
|
+
allPackages,
|
|
49
|
+
packagesWithCommits
|
|
101
50
|
}) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
51
|
+
const result = /* @__PURE__ */ new Map();
|
|
52
|
+
logger.debug(`Expanding packages to bump: ${packagesWithCommits.length} packages with commits, ${allPackages.length} total packages`);
|
|
53
|
+
for (const pkg of packagesWithCommits) {
|
|
54
|
+
const packageToBump = {
|
|
55
|
+
...pkg,
|
|
56
|
+
reason: "commits"
|
|
57
|
+
};
|
|
58
|
+
result.set(pkg.name, packageToBump);
|
|
59
|
+
}
|
|
60
|
+
const toProcess = [...packagesWithCommits.map((p) => p.name)];
|
|
61
|
+
const processed = /* @__PURE__ */ new Set();
|
|
62
|
+
while (toProcess.length > 0) {
|
|
63
|
+
const currentPkgName = toProcess.shift();
|
|
64
|
+
if (!currentPkgName || processed.has(currentPkgName)) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
processed.add(currentPkgName);
|
|
68
|
+
const dependents = getDependentsOf({
|
|
69
|
+
packageName: currentPkgName,
|
|
70
|
+
allPackages
|
|
71
|
+
});
|
|
72
|
+
for (const dependent of dependents) {
|
|
73
|
+
if (!result.has(dependent.name)) {
|
|
74
|
+
const currentChain = result.get(currentPkgName)?.dependencyChain || [];
|
|
75
|
+
const chain = [...currentChain, currentPkgName];
|
|
76
|
+
const packageBase = allPackages.find((p) => p.name === dependent.name);
|
|
77
|
+
if (packageBase) {
|
|
78
|
+
const packageToBump = {
|
|
79
|
+
...packageBase,
|
|
80
|
+
reason: "dependency",
|
|
81
|
+
dependencyChain: chain
|
|
82
|
+
};
|
|
83
|
+
result.set(dependent.name, packageToBump);
|
|
84
|
+
toProcess.push(dependent.name);
|
|
85
|
+
logger.debug(`${dependent.name} will be bumped (depends on ${chain.join(" \u2192 ")})`);
|
|
86
|
+
}
|
|
116
87
|
}
|
|
117
|
-
} catch (error) {
|
|
118
|
-
throw new Error(`Format command failed: ${error}`);
|
|
119
88
|
}
|
|
120
|
-
} else {
|
|
121
|
-
logger.debug("No format command specified");
|
|
122
89
|
}
|
|
90
|
+
return Array.from(result.values());
|
|
123
91
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
logger.info("Build completed");
|
|
139
|
-
} else {
|
|
140
|
-
logger.log("[dry-run] exec build command: ", config.publish.buildCmd);
|
|
92
|
+
function topologicalSort(packages) {
|
|
93
|
+
const sorted = [];
|
|
94
|
+
const visited = /* @__PURE__ */ new Set();
|
|
95
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
96
|
+
const packageMap = /* @__PURE__ */ new Map();
|
|
97
|
+
for (const pkg of packages) {
|
|
98
|
+
packageMap.set(pkg.name, pkg);
|
|
99
|
+
}
|
|
100
|
+
function visit(pkgName, path = []) {
|
|
101
|
+
logger.debug(`Visiting ${pkgName}, path: ${path.join(" \u2192 ")}, visiting: ${Array.from(visiting).join(", ")}`);
|
|
102
|
+
if (visiting.has(pkgName)) {
|
|
103
|
+
const cycle = [...path, pkgName];
|
|
104
|
+
logger.warn(`Circular dependency detected: ${cycle.join(" \u2192 ")}`);
|
|
105
|
+
return;
|
|
141
106
|
}
|
|
142
|
-
|
|
143
|
-
|
|
107
|
+
if (visited.has(pkgName)) {
|
|
108
|
+
logger.debug(`${pkgName} already visited globally, skipping`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
visiting.add(pkgName);
|
|
112
|
+
logger.debug(`Added ${pkgName} to visiting set`);
|
|
113
|
+
const pkg = packageMap.get(pkgName);
|
|
114
|
+
if (!pkg) {
|
|
115
|
+
logger.debug(`Package ${pkgName} not found in packageMap`);
|
|
116
|
+
visiting.delete(pkgName);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
logger.debug(`${pkgName} has dependencies: ${pkg.dependencies.join(", ")}`);
|
|
120
|
+
for (const depName of pkg.dependencies) {
|
|
121
|
+
visit(depName, [...path, pkgName]);
|
|
122
|
+
}
|
|
123
|
+
visiting.delete(pkgName);
|
|
124
|
+
visited.add(pkgName);
|
|
125
|
+
sorted.push(pkg);
|
|
126
|
+
logger.debug(`Finished visiting ${pkgName}`);
|
|
144
127
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
128
|
+
for (const pkg of packages) {
|
|
129
|
+
visit(pkg.name);
|
|
130
|
+
}
|
|
131
|
+
return sorted;
|
|
148
132
|
}
|
|
149
133
|
|
|
150
|
-
function
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
134
|
+
function readPackageJson(packagePath) {
|
|
135
|
+
const packageJsonPath = join(packagePath, "package.json");
|
|
136
|
+
if (!existsSync(packageJsonPath)) {
|
|
137
|
+
logger.fail(`package.json not found at ${packageJsonPath}`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (!statSync(packagePath).isDirectory()) {
|
|
141
|
+
logger.fail(`Not a directory: ${packagePath}`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
145
|
+
if (!packageJson.name || !packageJson.version) {
|
|
146
|
+
throw new Error(`Invalid package.json at ${packagePath} - missing name or version`);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
name: packageJson.name,
|
|
150
|
+
version: packageJson.version,
|
|
151
|
+
private: packageJson.private || false,
|
|
152
|
+
path: packagePath
|
|
153
|
+
};
|
|
155
154
|
}
|
|
156
|
-
function
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
Please commit or stash your changes before bumping or use --no-clean flag.
|
|
165
|
-
|
|
166
|
-
Unstaged files:
|
|
167
|
-
|
|
168
|
-
${dirty.trim()}`;
|
|
169
|
-
throw new Error(error);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
async function fetchGitTags(cwd) {
|
|
173
|
-
logger.debug("Fetching git tags from remote");
|
|
155
|
+
async function getRootPackage({
|
|
156
|
+
config,
|
|
157
|
+
force,
|
|
158
|
+
from,
|
|
159
|
+
to,
|
|
160
|
+
suffix,
|
|
161
|
+
changelog
|
|
162
|
+
}) {
|
|
174
163
|
try {
|
|
175
|
-
|
|
176
|
-
|
|
164
|
+
const packageJson = readPackageJson(config.cwd);
|
|
165
|
+
if (!packageJson) {
|
|
166
|
+
throw new Error("Failed to read root package.json");
|
|
167
|
+
}
|
|
168
|
+
const commits = await getPackageCommits({
|
|
169
|
+
pkg: packageJson,
|
|
170
|
+
from,
|
|
171
|
+
to,
|
|
172
|
+
config,
|
|
173
|
+
changelog
|
|
174
|
+
});
|
|
175
|
+
let newVersion;
|
|
176
|
+
if (config.monorepo?.versionMode !== "independent") {
|
|
177
|
+
const releaseType = determineReleaseType({
|
|
178
|
+
currentVersion: packageJson.version,
|
|
179
|
+
commits,
|
|
180
|
+
releaseType: config.bump.type,
|
|
181
|
+
preid: config.bump.preid,
|
|
182
|
+
types: config.types,
|
|
183
|
+
force
|
|
184
|
+
});
|
|
185
|
+
if (!releaseType) {
|
|
186
|
+
logger.fail("No commits require a version bump");
|
|
187
|
+
process.exit(0);
|
|
188
|
+
}
|
|
189
|
+
newVersion = getPackageNewVersion({
|
|
190
|
+
name: packageJson.name,
|
|
191
|
+
currentVersion: packageJson.version,
|
|
192
|
+
releaseType,
|
|
193
|
+
preid: config.bump.preid,
|
|
194
|
+
suffix
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
...packageJson,
|
|
199
|
+
path: config.cwd,
|
|
200
|
+
fromTag: from,
|
|
201
|
+
commits,
|
|
202
|
+
newVersion
|
|
203
|
+
};
|
|
177
204
|
} catch (error) {
|
|
178
|
-
|
|
179
|
-
|
|
205
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
206
|
+
throw new Error(errorMessage);
|
|
180
207
|
}
|
|
181
208
|
}
|
|
182
|
-
function
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
209
|
+
function readPackages({
|
|
210
|
+
cwd,
|
|
211
|
+
patterns,
|
|
212
|
+
ignorePackageNames
|
|
213
|
+
}) {
|
|
214
|
+
const packages = [];
|
|
215
|
+
const foundPaths = /* @__PURE__ */ new Set();
|
|
216
|
+
const patternsSet = new Set(patterns);
|
|
217
|
+
if (!patterns)
|
|
218
|
+
patternsSet.add(".");
|
|
219
|
+
logger.debug(`Read package.json files from patterns: ${patternsSet.values()}`);
|
|
220
|
+
for (const pattern of patternsSet) {
|
|
221
|
+
try {
|
|
222
|
+
const matches = fastGlob.sync(pattern, {
|
|
223
|
+
cwd,
|
|
224
|
+
onlyDirectories: true,
|
|
225
|
+
absolute: true,
|
|
226
|
+
ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"]
|
|
227
|
+
});
|
|
228
|
+
for (const matchPath of matches) {
|
|
229
|
+
if (foundPaths.has(matchPath))
|
|
230
|
+
continue;
|
|
231
|
+
const packageBase = readPackageJson(matchPath);
|
|
232
|
+
if (!packageBase || packageBase.private || ignorePackageNames?.includes(packageBase.name))
|
|
233
|
+
continue;
|
|
234
|
+
foundPaths.add(matchPath);
|
|
235
|
+
packages.push({
|
|
236
|
+
...packageBase,
|
|
237
|
+
path: matchPath
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
} catch (error) {
|
|
241
|
+
logger.error(error);
|
|
193
242
|
}
|
|
194
|
-
return null;
|
|
195
|
-
} catch {
|
|
196
|
-
return null;
|
|
197
243
|
}
|
|
244
|
+
return packages;
|
|
198
245
|
}
|
|
199
|
-
function
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
246
|
+
function getPackageReleaseType({
|
|
247
|
+
pkg,
|
|
248
|
+
config,
|
|
249
|
+
force
|
|
250
|
+
}) {
|
|
251
|
+
const releaseType = config.bump.type;
|
|
252
|
+
if (force) {
|
|
253
|
+
return determineReleaseType({
|
|
254
|
+
currentVersion: pkg.version,
|
|
255
|
+
commits: pkg.commits,
|
|
256
|
+
releaseType,
|
|
257
|
+
preid: config.bump.preid,
|
|
258
|
+
types: config.types,
|
|
259
|
+
force
|
|
260
|
+
});
|
|
208
261
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
262
|
+
if (pkg.reason === "dependency") {
|
|
263
|
+
if (isStableReleaseType(releaseType))
|
|
264
|
+
return "patch";
|
|
265
|
+
if (isPrerelease(pkg.version))
|
|
266
|
+
return "prerelease";
|
|
267
|
+
return "prepatch";
|
|
215
268
|
}
|
|
216
|
-
return
|
|
269
|
+
return determineReleaseType({
|
|
270
|
+
currentVersion: pkg.version,
|
|
271
|
+
commits: pkg.commits,
|
|
272
|
+
releaseType,
|
|
273
|
+
preid: config.bump.preid,
|
|
274
|
+
types: config.types,
|
|
275
|
+
force
|
|
276
|
+
});
|
|
217
277
|
}
|
|
218
|
-
async function
|
|
278
|
+
async function getPackages({
|
|
279
|
+
patterns,
|
|
219
280
|
config,
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
newVersion,
|
|
223
|
-
dryRun,
|
|
224
|
-
logLevel
|
|
281
|
+
suffix,
|
|
282
|
+
force
|
|
225
283
|
}) {
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
284
|
+
const readedPackages = readPackages({
|
|
285
|
+
cwd: config.cwd,
|
|
286
|
+
patterns,
|
|
287
|
+
ignorePackageNames: config.monorepo?.ignorePackageNames
|
|
288
|
+
});
|
|
289
|
+
const packages = /* @__PURE__ */ new Map();
|
|
290
|
+
const foundPaths = /* @__PURE__ */ new Set();
|
|
291
|
+
const patternsSet = new Set(patterns);
|
|
292
|
+
if (!patterns)
|
|
293
|
+
patternsSet.add(".");
|
|
294
|
+
logger.debug(`Getting packages from patterns: ${patternsSet.values()}`);
|
|
295
|
+
for (const pattern of patternsSet) {
|
|
296
|
+
const matches = fastGlob.sync(pattern, {
|
|
297
|
+
cwd: config.cwd,
|
|
298
|
+
onlyDirectories: true,
|
|
299
|
+
absolute: true,
|
|
300
|
+
ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"]
|
|
301
|
+
});
|
|
302
|
+
for (const matchPath of matches) {
|
|
303
|
+
if (foundPaths.has(matchPath))
|
|
304
|
+
continue;
|
|
305
|
+
const packageBase = readPackageJson(matchPath);
|
|
306
|
+
if (!packageBase) {
|
|
307
|
+
logger.debug(`Failed to read package.json at ${matchPath} - ignored`);
|
|
241
308
|
continue;
|
|
242
309
|
}
|
|
243
|
-
if (
|
|
244
|
-
logger.
|
|
310
|
+
if (packageBase.private) {
|
|
311
|
+
logger.debug(`${packageBase.name} is private and will be ignored`);
|
|
245
312
|
continue;
|
|
246
313
|
}
|
|
247
|
-
if (
|
|
248
|
-
logger.
|
|
314
|
+
if (config.monorepo?.ignorePackageNames?.includes(packageBase.name)) {
|
|
315
|
+
logger.debug(`${packageBase.name} ignored by config (monorepo.ignorePackageNames)`);
|
|
249
316
|
continue;
|
|
250
317
|
}
|
|
251
|
-
|
|
252
|
-
logger.
|
|
253
|
-
|
|
254
|
-
} catch {
|
|
318
|
+
if (!packageBase.version) {
|
|
319
|
+
logger.warn(`${packageBase.name} has no version and will be ignored`);
|
|
320
|
+
continue;
|
|
255
321
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
322
|
+
const { from, to } = await resolveTags({
|
|
323
|
+
config,
|
|
324
|
+
step: "bump",
|
|
325
|
+
pkg: packageBase,
|
|
326
|
+
newVersion: void 0
|
|
327
|
+
});
|
|
328
|
+
const commits = await getPackageCommits({
|
|
329
|
+
pkg: packageBase,
|
|
330
|
+
from,
|
|
331
|
+
to,
|
|
332
|
+
config,
|
|
333
|
+
changelog: false
|
|
334
|
+
});
|
|
335
|
+
foundPaths.add(matchPath);
|
|
336
|
+
const dependencies = getPackageDependencies({
|
|
337
|
+
packagePath: matchPath,
|
|
338
|
+
allPackageNames: new Set(readedPackages.map((p) => p.name)),
|
|
339
|
+
dependencyTypes: config.bump?.dependencyTypes
|
|
340
|
+
});
|
|
341
|
+
packages.set(packageBase.name, {
|
|
342
|
+
...packageBase,
|
|
343
|
+
path: matchPath,
|
|
344
|
+
fromTag: from,
|
|
345
|
+
dependencies,
|
|
346
|
+
commits,
|
|
347
|
+
reason: commits.length > 0 ? "commits" : void 0,
|
|
348
|
+
dependencyChain: void 0,
|
|
349
|
+
newVersion: void 0
|
|
272
350
|
});
|
|
273
|
-
logger.success(`Committed: ${commitMessage}${noVerify ? " (--no-verify)" : ""}`);
|
|
274
|
-
}
|
|
275
|
-
const signTags = internalConfig.signTags ? "-s" : "";
|
|
276
|
-
logger.debug(`Sign tags: ${internalConfig.signTags}`);
|
|
277
|
-
const createdTags = [];
|
|
278
|
-
if (internalConfig.monorepo?.versionMode === "independent" && bumpedPackages && bumpedPackages.length > 0 && internalConfig.release.gitTag) {
|
|
279
|
-
logger.debug(`Creating ${bumpedPackages.length} independent package tags`);
|
|
280
|
-
for (const pkg of bumpedPackages) {
|
|
281
|
-
if (!pkg.newVersion) {
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
const tagName = getIndependentTag({ version: pkg.newVersion, name: pkg.name });
|
|
285
|
-
const tagMessage = internalConfig.templates?.tagMessage?.replaceAll("{{newVersion}}", pkg.newVersion) || tagName;
|
|
286
|
-
if (dryRun) {
|
|
287
|
-
logger.info(`[dry-run] git tag ${signTags} -a ${tagName} -m "${tagMessage}"`);
|
|
288
|
-
} else {
|
|
289
|
-
const cmd = `git tag ${signTags} -a ${tagName} -m "${tagMessage}"`;
|
|
290
|
-
logger.debug(`Executing: ${cmd}`);
|
|
291
|
-
try {
|
|
292
|
-
await execPromise(cmd, {
|
|
293
|
-
logLevel,
|
|
294
|
-
noStderr: true,
|
|
295
|
-
noStdout: true,
|
|
296
|
-
cwd: internalConfig.cwd
|
|
297
|
-
});
|
|
298
|
-
logger.debug(`Tag created: ${tagName}`);
|
|
299
|
-
} catch (error) {
|
|
300
|
-
logger.error(`Failed to create tag ${tagName}:`, error);
|
|
301
|
-
throw error;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
createdTags.push(tagName);
|
|
305
|
-
}
|
|
306
|
-
logger.success(`Created ${createdTags.length} tags for independent packages, ${createdTags.join(", ")}`);
|
|
307
|
-
} else if (internalConfig.release.gitTag) {
|
|
308
|
-
const tagName = internalConfig.templates.tagBody?.replaceAll("{{newVersion}}", newVersion);
|
|
309
|
-
const tagMessage = internalConfig.templates?.tagMessage?.replaceAll("{{newVersion}}", newVersion) || tagName;
|
|
310
|
-
if (dryRun) {
|
|
311
|
-
logger.info(`[dry-run] git tag ${signTags} -a ${tagName} -m "${tagMessage}"`);
|
|
312
|
-
} else {
|
|
313
|
-
const cmd = `git tag ${signTags} -a ${tagName} -m "${tagMessage}"`;
|
|
314
|
-
logger.debug(`Executing: ${cmd}`);
|
|
315
|
-
try {
|
|
316
|
-
await execPromise(cmd, {
|
|
317
|
-
logLevel,
|
|
318
|
-
noStderr: true,
|
|
319
|
-
noStdout: true,
|
|
320
|
-
cwd: internalConfig.cwd
|
|
321
|
-
});
|
|
322
|
-
logger.debug(`Tag created: ${tagName}`);
|
|
323
|
-
} catch (error) {
|
|
324
|
-
logger.error(`Failed to create tag ${tagName}:`, error);
|
|
325
|
-
throw error;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
createdTags.push(tagName);
|
|
329
351
|
}
|
|
330
|
-
logger.debug("Created Tags:", createdTags.join(", "));
|
|
331
|
-
logger.success("Commit and tag completed!");
|
|
332
|
-
await executeHook("success:commit-and-tag", internalConfig, dryRun ?? false);
|
|
333
|
-
return createdTags;
|
|
334
|
-
} catch (error) {
|
|
335
|
-
logger.error("Error committing and tagging:", error);
|
|
336
|
-
await executeHook("error:commit-and-tag", internalConfig, dryRun ?? false);
|
|
337
|
-
throw error;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
async function pushCommitAndTags({ config, dryRun, logLevel, cwd }) {
|
|
341
|
-
logger.start("Start push changes and tags");
|
|
342
|
-
const command = config.release.gitTag ? "git push --follow-tags" : "git push";
|
|
343
|
-
if (dryRun) {
|
|
344
|
-
logger.info(`[dry-run] ${command}`);
|
|
345
|
-
} else {
|
|
346
|
-
logger.debug(`Executing: ${command}`);
|
|
347
|
-
await execPromise(command, { noStderr: true, noStdout: true, logLevel, cwd });
|
|
348
352
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
{
|
|
355
|
-
cwd,
|
|
356
|
-
encoding: "utf8"
|
|
357
|
-
}
|
|
358
|
-
);
|
|
359
|
-
return result.trim();
|
|
360
|
-
}
|
|
361
|
-
function getCurrentGitBranch(cwd) {
|
|
362
|
-
const result = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
363
|
-
cwd,
|
|
364
|
-
encoding: "utf8"
|
|
353
|
+
const packagesArray = Array.from(packages.values());
|
|
354
|
+
const packagesWithCommits = packagesArray.filter((p) => p.commits.length > 0);
|
|
355
|
+
const expandedPackages = expandPackagesToBumpWithDependents({
|
|
356
|
+
allPackages: packagesArray,
|
|
357
|
+
packagesWithCommits
|
|
365
358
|
});
|
|
366
|
-
|
|
359
|
+
for (const pkg of expandedPackages) {
|
|
360
|
+
packages.set(pkg.name, pkg);
|
|
361
|
+
}
|
|
362
|
+
for (const pkg of Array.from(packages.values())) {
|
|
363
|
+
const releaseType = getPackageReleaseType({
|
|
364
|
+
pkg,
|
|
365
|
+
config,
|
|
366
|
+
force
|
|
367
|
+
});
|
|
368
|
+
const newVersion = releaseType ? getPackageNewVersion({
|
|
369
|
+
name: pkg.name,
|
|
370
|
+
currentVersion: pkg.version,
|
|
371
|
+
releaseType,
|
|
372
|
+
preid: config.bump.preid,
|
|
373
|
+
suffix
|
|
374
|
+
}) : void 0;
|
|
375
|
+
const graduating = releaseType && isGraduating(pkg.version, releaseType) || isChangedPreid(pkg.version, config.bump.preid);
|
|
376
|
+
packages.set(pkg.name, {
|
|
377
|
+
...pkg,
|
|
378
|
+
newVersion,
|
|
379
|
+
reason: pkg.reason || releaseType && graduating && "graduation" || void 0
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
const packagesToBump = Array.from(packages.values()).filter((p) => p.reason || force);
|
|
383
|
+
if (packagesToBump.length === 0) {
|
|
384
|
+
logger.debug("No packages to bump");
|
|
385
|
+
return [];
|
|
386
|
+
}
|
|
387
|
+
return packagesToBump;
|
|
367
388
|
}
|
|
368
|
-
function
|
|
369
|
-
|
|
370
|
-
|
|
389
|
+
function isAllowedCommit({
|
|
390
|
+
commit,
|
|
391
|
+
type,
|
|
392
|
+
changelog
|
|
393
|
+
}) {
|
|
394
|
+
if (commit.type === "chore" && ["deps", "release"].includes(commit.scope) && !commit.isBreaking) {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
if (typeof type === "object") {
|
|
398
|
+
return !!type.semver || changelog && !!type.title;
|
|
399
|
+
}
|
|
400
|
+
if (typeof type === "boolean") {
|
|
401
|
+
return type;
|
|
402
|
+
}
|
|
403
|
+
return false;
|
|
371
404
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
commits,
|
|
375
|
-
config,
|
|
405
|
+
async function getPackageCommits({
|
|
406
|
+
pkg,
|
|
376
407
|
from,
|
|
377
408
|
to,
|
|
378
|
-
|
|
409
|
+
config,
|
|
410
|
+
changelog
|
|
379
411
|
}) {
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
const breakingChanges = [];
|
|
383
|
-
const updatedConfig = {
|
|
412
|
+
logger.debug(`Analyzing commits for ${pkg.name} since ${from} to ${to}`);
|
|
413
|
+
const changelogConfig = {
|
|
384
414
|
...config,
|
|
385
415
|
from,
|
|
386
416
|
to
|
|
387
417
|
};
|
|
388
|
-
const
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
});
|
|
396
|
-
markdown.push(formattedCompareLink);
|
|
418
|
+
const rawCommits = await getGitDiff(from, to, changelogConfig.cwd);
|
|
419
|
+
const allCommits = parseCommits(rawCommits, changelogConfig);
|
|
420
|
+
const hasBreakingChanges = allCommits.some((commit) => commit.isBreaking);
|
|
421
|
+
logger.debug(`Has breaking changes: ${hasBreakingChanges}`);
|
|
422
|
+
const rootPackage = readPackageJson(changelogConfig.cwd);
|
|
423
|
+
if (!rootPackage) {
|
|
424
|
+
throw new Error("Failed to read root package.json");
|
|
397
425
|
}
|
|
398
|
-
|
|
399
|
-
const
|
|
400
|
-
if (!
|
|
401
|
-
|
|
402
|
-
}
|
|
403
|
-
if (typeof updatedConfig.types[type] === "boolean") {
|
|
404
|
-
continue;
|
|
426
|
+
const commits = allCommits.filter((commit) => {
|
|
427
|
+
const type = changelogConfig?.types[commit.type];
|
|
428
|
+
if (!isAllowedCommit({ commit, type, changelog })) {
|
|
429
|
+
return false;
|
|
405
430
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const line = formatCommit(commit, updatedConfig);
|
|
409
|
-
markdown.push(line);
|
|
410
|
-
if (commit.isBreaking) {
|
|
411
|
-
breakingChanges.push(line);
|
|
412
|
-
}
|
|
431
|
+
if (pkg.path === changelogConfig.cwd || pkg.name === rootPackage.name) {
|
|
432
|
+
return true;
|
|
413
433
|
}
|
|
434
|
+
const packageRelativePath = relative(changelogConfig.cwd, pkg.path);
|
|
435
|
+
const scopeMatches = commit.scope === pkg.name;
|
|
436
|
+
const bodyContainsPath = commit.body.includes(packageRelativePath);
|
|
437
|
+
return scopeMatches || bodyContainsPath;
|
|
438
|
+
});
|
|
439
|
+
logger.debug(`Found ${commits.length} commit(s) for ${pkg.name} from ${from} to ${to}`);
|
|
440
|
+
if (commits.length > 0) {
|
|
441
|
+
logger.debug(`${pkg.name}: ${commits.length} commit(s) found`);
|
|
442
|
+
} else {
|
|
443
|
+
logger.debug(`${pkg.name}: No commits found`);
|
|
414
444
|
}
|
|
415
|
-
|
|
416
|
-
|
|
445
|
+
return commits;
|
|
446
|
+
}
|
|
447
|
+
function hasLernaJson(rootDir) {
|
|
448
|
+
const lernaJsonPath = join(rootDir, "lerna.json");
|
|
449
|
+
return existsSync(lernaJsonPath);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
async function executeHook(hook, config, dryRun, params) {
|
|
453
|
+
const hookInput = config.hooks?.[hook];
|
|
454
|
+
if (!hookInput) {
|
|
455
|
+
logger.debug(`Hook ${hook} not found`);
|
|
456
|
+
return;
|
|
417
457
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
continue;
|
|
426
|
-
}
|
|
427
|
-
if (updatedConfig.excludeAuthors && updatedConfig.excludeAuthors.some(
|
|
428
|
-
(v) => name.includes(v) || commit.author.email?.includes(v)
|
|
429
|
-
)) {
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
if (_authors.has(name)) {
|
|
433
|
-
const entry = _authors.get(name);
|
|
434
|
-
entry?.email.add(commit.author.email);
|
|
435
|
-
} else {
|
|
436
|
-
_authors.set(name, { email: /* @__PURE__ */ new Set([commit.author.email]), name });
|
|
437
|
-
}
|
|
458
|
+
if (typeof hookInput === "function") {
|
|
459
|
+
logger.info(`Executing hook ${hook}`);
|
|
460
|
+
const result = await hookInput(config, dryRun, params);
|
|
461
|
+
if (result)
|
|
462
|
+
logger.debug(`Hook ${hook} returned: ${result}`);
|
|
463
|
+
logger.info(`Hook ${hook} executed`);
|
|
464
|
+
return result;
|
|
438
465
|
}
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
})
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
|
-
const authors = [..._authors.entries()].map((e) => ({
|
|
457
|
-
name: e[0],
|
|
458
|
-
...e[1]
|
|
459
|
-
}));
|
|
460
|
-
if (authors.length > 0 && !updatedConfig.noAuthors) {
|
|
461
|
-
markdown.push(
|
|
462
|
-
"",
|
|
463
|
-
"### \u2764\uFE0F Contributors",
|
|
464
|
-
"",
|
|
465
|
-
...authors.map((i) => {
|
|
466
|
-
const _email = [...i.email].find(
|
|
467
|
-
(e) => !e.includes("noreply.github.com")
|
|
468
|
-
);
|
|
469
|
-
const email = updatedConfig.hideAuthorEmail !== true && _email ? ` <${_email}>` : "";
|
|
470
|
-
const github = i.github ? ` ([@${i.github}](https://github.com/${i.github}))` : "";
|
|
471
|
-
return `- ${i.name}${github || email || ""}`;
|
|
472
|
-
})
|
|
473
|
-
);
|
|
466
|
+
if (typeof hookInput === "string") {
|
|
467
|
+
logger.info(`Executing hook ${hook}`);
|
|
468
|
+
const result = await execPromise(hookInput, {
|
|
469
|
+
logLevel: config.logLevel,
|
|
470
|
+
cwd: config.cwd,
|
|
471
|
+
noStderr: true,
|
|
472
|
+
noStdout: true
|
|
473
|
+
});
|
|
474
|
+
if (result)
|
|
475
|
+
logger.debug(`Hook ${hook} returned: ${result}`);
|
|
476
|
+
logger.info(`Hook ${hook} executed`);
|
|
477
|
+
return result;
|
|
474
478
|
}
|
|
475
|
-
const result = convert(markdown.join("\n").trim(), true);
|
|
476
|
-
return result;
|
|
477
479
|
}
|
|
478
|
-
function
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const lines = commit.body.split("\n");
|
|
483
|
-
const contentLines = lines.filter((line) => {
|
|
484
|
-
const trimmedLine = line.trim();
|
|
485
|
-
if (!trimmedLine) {
|
|
486
|
-
return false;
|
|
487
|
-
}
|
|
488
|
-
const isFileLine = /^[AMDTUXB](?:\d{3})?\s+/.test(trimmedLine) || /^[RCM]\d{3}\s+/.test(trimmedLine);
|
|
489
|
-
return !isFileLine;
|
|
490
|
-
});
|
|
491
|
-
if (contentLines.length === 0) {
|
|
492
|
-
return "";
|
|
493
|
-
}
|
|
494
|
-
const indentedBody = contentLines.map((line) => ` ${line}`).join("\n");
|
|
495
|
-
return `
|
|
496
|
-
|
|
497
|
-
${indentedBody}
|
|
498
|
-
`;
|
|
480
|
+
function isInCI() {
|
|
481
|
+
return Boolean(
|
|
482
|
+
process.env.CI === "true" || process.env.CONTINUOUS_INTEGRATION === "true" || process.env.GITHUB_ACTIONS === "true" || process.env.GITHUB_WORKFLOW || process.env.GITLAB_CI === "true" || process.env.CIRCLECI === "true" || process.env.TRAVIS === "true" || process.env.JENKINS_HOME || process.env.JENKINS_URL || process.env.BUILD_ID || process.env.TF_BUILD === "True" || process.env.AZURE_PIPELINES === "true" || process.env.TEAMCITY_VERSION || process.env.BITBUCKET_BUILD_NUMBER || process.env.DRONE === "true" || process.env.APPVEYOR === "True" || process.env.APPVEYOR === "true" || process.env.BUILDKITE === "true" || process.env.CODEBUILD_BUILD_ID || process.env.NETLIFY === "true" || process.env.VERCEL === "1" || process.env.HEROKU_TEST_RUN_ID || process.env.BUDDY === "true" || process.env.SEMAPHORE === "true" || process.env.CF_BUILD_ID || process.env.bamboo_buildKey || process.env.BUILD_ID && process.env.PROJECT_ID || process.env.SCREWDRIVER === "true" || process.env.STRIDER === "true"
|
|
483
|
+
);
|
|
499
484
|
}
|
|
500
|
-
function
|
|
501
|
-
|
|
502
|
-
|
|
485
|
+
function getCIName() {
|
|
486
|
+
if (process.env.GITHUB_ACTIONS === "true")
|
|
487
|
+
return "GitHub Actions";
|
|
488
|
+
if (process.env.GITLAB_CI === "true")
|
|
489
|
+
return "GitLab CI";
|
|
490
|
+
if (process.env.CIRCLECI === "true")
|
|
491
|
+
return "CircleCI";
|
|
492
|
+
if (process.env.TRAVIS === "true")
|
|
493
|
+
return "Travis CI";
|
|
494
|
+
if (process.env.JENKINS_HOME || process.env.JENKINS_URL)
|
|
495
|
+
return "Jenkins";
|
|
496
|
+
if (process.env.TF_BUILD === "True")
|
|
497
|
+
return "Azure Pipelines";
|
|
498
|
+
if (process.env.TEAMCITY_VERSION)
|
|
499
|
+
return "TeamCity";
|
|
500
|
+
if (process.env.BITBUCKET_BUILD_NUMBER)
|
|
501
|
+
return "Bitbucket Pipelines";
|
|
502
|
+
if (process.env.DRONE === "true")
|
|
503
|
+
return "Drone";
|
|
504
|
+
if (process.env.APPVEYOR)
|
|
505
|
+
return "AppVeyor";
|
|
506
|
+
if (process.env.BUILDKITE === "true")
|
|
507
|
+
return "Buildkite";
|
|
508
|
+
if (process.env.CODEBUILD_BUILD_ID)
|
|
509
|
+
return "AWS CodeBuild";
|
|
510
|
+
if (process.env.NETLIFY === "true")
|
|
511
|
+
return "Netlify";
|
|
512
|
+
if (process.env.VERCEL === "1")
|
|
513
|
+
return "Vercel";
|
|
514
|
+
if (process.env.HEROKU_TEST_RUN_ID)
|
|
515
|
+
return "Heroku CI";
|
|
516
|
+
if (process.env.BUDDY === "true")
|
|
517
|
+
return "Buddy";
|
|
518
|
+
if (process.env.SEMAPHORE === "true")
|
|
519
|
+
return "Semaphore";
|
|
520
|
+
if (process.env.CF_BUILD_ID)
|
|
521
|
+
return "Codefresh";
|
|
522
|
+
if (process.env.bamboo_buildKey)
|
|
523
|
+
return "Bamboo";
|
|
524
|
+
if (process.env.BUILD_ID && process.env.PROJECT_ID)
|
|
525
|
+
return "Google Cloud Build";
|
|
526
|
+
if (process.env.SCREWDRIVER === "true")
|
|
527
|
+
return "Screwdriver";
|
|
528
|
+
if (process.env.STRIDER === "true")
|
|
529
|
+
return "Strider";
|
|
530
|
+
if (process.env.CI === "true")
|
|
531
|
+
return "Unknown CI";
|
|
532
|
+
return null;
|
|
503
533
|
}
|
|
504
|
-
function
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
534
|
+
async function executeFormatCmd({
|
|
535
|
+
config,
|
|
536
|
+
dryRun
|
|
537
|
+
}) {
|
|
538
|
+
if (config.changelog?.formatCmd) {
|
|
539
|
+
logger.info("Running format command");
|
|
540
|
+
logger.debug(`Running format command: ${config.changelog.formatCmd}`);
|
|
541
|
+
try {
|
|
542
|
+
if (!dryRun) {
|
|
543
|
+
await execPromise(config.changelog.formatCmd, {
|
|
544
|
+
noStderr: true,
|
|
545
|
+
noStdout: true,
|
|
546
|
+
logLevel: config.logLevel,
|
|
547
|
+
cwd: config.cwd
|
|
548
|
+
});
|
|
549
|
+
logger.info("Format completed");
|
|
550
|
+
} else {
|
|
551
|
+
logger.log("[dry-run] exec format command: ", config.changelog.formatCmd);
|
|
552
|
+
}
|
|
553
|
+
} catch (error) {
|
|
554
|
+
throw new Error(`Format command failed: ${error}`);
|
|
555
|
+
}
|
|
556
|
+
} else {
|
|
557
|
+
logger.debug("No format command specified");
|
|
512
558
|
}
|
|
513
|
-
return "";
|
|
514
|
-
}
|
|
515
|
-
function formatName(name = "") {
|
|
516
|
-
return name.split(" ").map((p) => upperFirst(p.trim())).join(" ");
|
|
517
559
|
}
|
|
518
|
-
function
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
560
|
+
async function executeBuildCmd({
|
|
561
|
+
config,
|
|
562
|
+
dryRun
|
|
563
|
+
}) {
|
|
564
|
+
if (config.publish?.buildCmd) {
|
|
565
|
+
logger.info("Running build command");
|
|
566
|
+
logger.debug(`Running build command: ${config.publish.buildCmd}`);
|
|
567
|
+
if (!dryRun) {
|
|
568
|
+
await execPromise(config.publish.buildCmd, {
|
|
569
|
+
noStderr: true,
|
|
570
|
+
noStdout: true,
|
|
571
|
+
logLevel: config.logLevel,
|
|
572
|
+
cwd: config.cwd
|
|
573
|
+
});
|
|
574
|
+
logger.info("Build completed");
|
|
575
|
+
} else {
|
|
576
|
+
logger.log("[dry-run] exec build command: ", config.publish.buildCmd);
|
|
577
|
+
}
|
|
578
|
+
} else {
|
|
579
|
+
logger.debug("No build command specified");
|
|
523
580
|
}
|
|
524
|
-
return groups;
|
|
525
581
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
return fromTag === getFirstCommit(cwd);
|
|
582
|
+
function isBumpedPackage(pkg) {
|
|
583
|
+
return "oldVersion" in pkg && !!pkg.oldVersion;
|
|
529
584
|
}
|
|
530
|
-
async function
|
|
531
|
-
pkg,
|
|
585
|
+
async function getPackagesOrBumpedPackages({
|
|
532
586
|
config,
|
|
533
|
-
|
|
534
|
-
|
|
587
|
+
bumpResult,
|
|
588
|
+
suffix,
|
|
589
|
+
force
|
|
535
590
|
}) {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
if (isFirstCommit) {
|
|
539
|
-
fromTag = config.monorepo?.versionMode === "independent" ? getIndependentTag({ version: "0.0.0", name: pkg.name }) : config.templates.tagBody.replace("{{newVersion}}", "0.0.0");
|
|
591
|
+
if (bumpResult?.bumpedPackages && bumpResult.bumpedPackages.length > 0) {
|
|
592
|
+
return bumpResult.bumpedPackages;
|
|
540
593
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
594
|
+
return await getPackages({
|
|
595
|
+
config,
|
|
596
|
+
patterns: config.monorepo?.packages,
|
|
597
|
+
suffix,
|
|
598
|
+
force
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function getGitStatus(cwd) {
|
|
603
|
+
return execSync("git status --porcelain", {
|
|
604
|
+
cwd,
|
|
605
|
+
encoding: "utf8"
|
|
606
|
+
}).trim();
|
|
607
|
+
}
|
|
608
|
+
function checkGitStatusIfDirty() {
|
|
609
|
+
logger.debug("Checking git status");
|
|
610
|
+
const dirty = getGitStatus();
|
|
611
|
+
if (dirty) {
|
|
612
|
+
logger.debug("git status:", `
|
|
613
|
+
${dirty.trim().split("\n").map((line) => line.trim()).join("\n")}`);
|
|
614
|
+
const error = `Git status is dirty!
|
|
615
|
+
|
|
616
|
+
Please commit or stash your changes before bumping or use --no-clean flag.
|
|
617
|
+
|
|
618
|
+
Unstaged files:
|
|
619
|
+
|
|
620
|
+
${dirty.trim()}`;
|
|
621
|
+
throw new Error(error);
|
|
545
622
|
}
|
|
546
|
-
|
|
547
|
-
|
|
623
|
+
}
|
|
624
|
+
async function fetchGitTags(cwd) {
|
|
625
|
+
logger.debug("Fetching git tags from remote");
|
|
626
|
+
try {
|
|
627
|
+
await execPromise("git fetch --tags", { cwd, noStderr: true, noStdout: true, noSuccess: true });
|
|
628
|
+
logger.debug("Git tags fetched successfully");
|
|
629
|
+
} catch (error) {
|
|
630
|
+
logger.fail("Failed to fetch some git tags from remote (tags might already exist locally)", error);
|
|
631
|
+
logger.info("Continuing with local tags");
|
|
548
632
|
}
|
|
549
|
-
|
|
633
|
+
}
|
|
634
|
+
function detectGitProvider(cwd = process.cwd()) {
|
|
550
635
|
try {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
636
|
+
const remoteUrl = execSync("git remote get-url origin", {
|
|
637
|
+
cwd,
|
|
638
|
+
encoding: "utf8"
|
|
639
|
+
}).trim();
|
|
640
|
+
if (remoteUrl.includes("github.com")) {
|
|
641
|
+
return "github";
|
|
642
|
+
}
|
|
643
|
+
if (remoteUrl.includes("gitlab.com") || remoteUrl.includes("gitlab")) {
|
|
644
|
+
return "gitlab";
|
|
645
|
+
}
|
|
646
|
+
return null;
|
|
647
|
+
} catch {
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
function parseGitRemoteUrl(remoteUrl) {
|
|
652
|
+
const sshRegex = /git@[\w.-]+:([\w.-]+)\/([\w.-]+?)(?:\.git)?$/;
|
|
653
|
+
const httpsRegex = /https?:\/\/[\w.-]+\/([\w.-]+)\/([\w.-]+?)(?:\.git)?$/;
|
|
654
|
+
const sshMatch = remoteUrl.match(sshRegex);
|
|
655
|
+
if (sshMatch) {
|
|
656
|
+
return {
|
|
657
|
+
owner: sshMatch[1],
|
|
658
|
+
repo: sshMatch[2]
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
const httpsMatch = remoteUrl.match(httpsRegex);
|
|
662
|
+
if (httpsMatch) {
|
|
663
|
+
return {
|
|
664
|
+
owner: httpsMatch[1],
|
|
665
|
+
repo: httpsMatch[2]
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
async function createCommitAndTags({
|
|
671
|
+
config,
|
|
672
|
+
noVerify,
|
|
673
|
+
bumpedPackages,
|
|
674
|
+
newVersion,
|
|
675
|
+
dryRun,
|
|
676
|
+
logLevel
|
|
677
|
+
}) {
|
|
678
|
+
const internalConfig = config || await loadRelizyConfig();
|
|
679
|
+
try {
|
|
680
|
+
await executeHook("before:commit-and-tag", internalConfig, dryRun ?? false);
|
|
681
|
+
const filePatternsToAdd = [
|
|
682
|
+
"package.json",
|
|
683
|
+
"lerna.json",
|
|
684
|
+
"CHANGELOG.md",
|
|
685
|
+
"**/CHANGELOG.md",
|
|
686
|
+
"**/package.json"
|
|
687
|
+
];
|
|
688
|
+
logger.start("Start commit and tag");
|
|
689
|
+
logger.debug("Adding files to git staging area...");
|
|
690
|
+
for (const pattern of filePatternsToAdd) {
|
|
691
|
+
if (pattern === "lerna.json" && !hasLernaJson(internalConfig.cwd)) {
|
|
692
|
+
logger.verbose(`Skipping lerna.json as it doesn't exist`);
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
if ((pattern === "lerna.json" || pattern === "CHANGELOG.md") && !existsSync(join(internalConfig.cwd, pattern))) {
|
|
696
|
+
logger.verbose(`Skipping ${pattern} as it doesn't exist`);
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
if (dryRun) {
|
|
700
|
+
logger.info(`[dry-run] git add ${pattern}`);
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
try {
|
|
704
|
+
logger.debug(`git add ${pattern}`);
|
|
705
|
+
execSync(`git add ${pattern}`);
|
|
706
|
+
} catch {
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
const rootPackage = readPackageJson(internalConfig.cwd);
|
|
710
|
+
if (!rootPackage) {
|
|
711
|
+
throw new Error("Failed to read root package.json");
|
|
712
|
+
}
|
|
713
|
+
newVersion = newVersion || rootPackage.version;
|
|
714
|
+
const versionForMessage = internalConfig.monorepo?.versionMode === "independent" ? bumpedPackages?.map((pkg) => getIndependentTag({ name: pkg.name, version: pkg.newVersion || pkg.version })).join(", ") || "unknown" : newVersion || "unknown";
|
|
715
|
+
const commitMessage = internalConfig.templates.commitMessage?.replaceAll("{{newVersion}}", versionForMessage) || `chore(release): bump version to ${versionForMessage}`;
|
|
716
|
+
const noVerifyFlag = noVerify ? "--no-verify " : "";
|
|
717
|
+
logger.debug(`No verify: ${noVerify}`);
|
|
718
|
+
if (dryRun) {
|
|
719
|
+
logger.info(`[dry-run] git commit ${noVerifyFlag}-m "${commitMessage}"`);
|
|
720
|
+
} else {
|
|
721
|
+
logger.debug(`Executing: git commit ${noVerifyFlag}-m "${commitMessage}"`);
|
|
722
|
+
await execPromise(`git commit ${noVerifyFlag}-m "${commitMessage}"`, {
|
|
723
|
+
logLevel,
|
|
724
|
+
noStderr: true,
|
|
725
|
+
noStdout: true,
|
|
726
|
+
cwd: internalConfig.cwd
|
|
727
|
+
});
|
|
728
|
+
logger.success(`Committed: ${commitMessage}${noVerify ? " (--no-verify)" : ""}`);
|
|
729
|
+
}
|
|
730
|
+
const signTags = internalConfig.signTags ? "-s" : "";
|
|
731
|
+
logger.debug(`Sign tags: ${internalConfig.signTags}`);
|
|
732
|
+
const createdTags = [];
|
|
733
|
+
if (internalConfig.monorepo?.versionMode === "independent" && bumpedPackages && bumpedPackages.length > 0 && internalConfig.release.gitTag) {
|
|
734
|
+
logger.debug(`Creating ${bumpedPackages.length} independent package tags`);
|
|
735
|
+
for (const pkg of bumpedPackages) {
|
|
736
|
+
if (!pkg.newVersion) {
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
const tagName = getIndependentTag({ version: pkg.newVersion, name: pkg.name });
|
|
740
|
+
const tagMessage = internalConfig.templates?.tagMessage?.replaceAll("{{newVersion}}", pkg.newVersion) || tagName;
|
|
741
|
+
if (dryRun) {
|
|
742
|
+
logger.info(`[dry-run] git tag ${signTags} -a ${tagName} -m "${tagMessage}"`);
|
|
743
|
+
} else {
|
|
744
|
+
const cmd = `git tag ${signTags} -a ${tagName} -m "${tagMessage}"`;
|
|
745
|
+
logger.debug(`Executing: ${cmd}`);
|
|
746
|
+
try {
|
|
747
|
+
await execPromise(cmd, {
|
|
748
|
+
logLevel,
|
|
749
|
+
noStderr: true,
|
|
750
|
+
noStdout: true,
|
|
751
|
+
cwd: internalConfig.cwd
|
|
752
|
+
});
|
|
753
|
+
logger.debug(`Tag created: ${tagName}`);
|
|
754
|
+
} catch (error) {
|
|
755
|
+
logger.error(`Failed to create tag ${tagName}:`, error);
|
|
756
|
+
throw error;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
createdTags.push(tagName);
|
|
760
|
+
}
|
|
761
|
+
logger.success(`Created ${createdTags.length} tags for independent packages, ${createdTags.join(", ")}`);
|
|
762
|
+
} else if (internalConfig.release.gitTag) {
|
|
763
|
+
const tagName = internalConfig.templates.tagBody?.replaceAll("{{newVersion}}", newVersion);
|
|
764
|
+
const tagMessage = internalConfig.templates?.tagMessage?.replaceAll("{{newVersion}}", newVersion) || tagName;
|
|
765
|
+
if (dryRun) {
|
|
766
|
+
logger.info(`[dry-run] git tag ${signTags} -a ${tagName} -m "${tagMessage}"`);
|
|
767
|
+
} else {
|
|
768
|
+
const cmd = `git tag ${signTags} -a ${tagName} -m "${tagMessage}"`;
|
|
769
|
+
logger.debug(`Executing: ${cmd}`);
|
|
770
|
+
try {
|
|
771
|
+
await execPromise(cmd, {
|
|
772
|
+
logLevel,
|
|
773
|
+
noStderr: true,
|
|
774
|
+
noStdout: true,
|
|
775
|
+
cwd: internalConfig.cwd
|
|
776
|
+
});
|
|
777
|
+
logger.debug(`Tag created: ${tagName}`);
|
|
778
|
+
} catch (error) {
|
|
779
|
+
logger.error(`Failed to create tag ${tagName}:`, error);
|
|
780
|
+
throw error;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
createdTags.push(tagName);
|
|
784
|
+
}
|
|
785
|
+
logger.debug("Created Tags:", createdTags.join(", "));
|
|
786
|
+
logger.success("Commit and tag completed!");
|
|
787
|
+
await executeHook("success:commit-and-tag", internalConfig, dryRun ?? false);
|
|
788
|
+
return createdTags;
|
|
789
|
+
} catch (error) {
|
|
790
|
+
logger.error("Error committing and tagging:", error);
|
|
791
|
+
await executeHook("error:commit-and-tag", internalConfig, dryRun ?? false);
|
|
792
|
+
throw error;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
async function pushCommitAndTags({ config, dryRun, logLevel, cwd }) {
|
|
796
|
+
logger.start("Start push changes and tags");
|
|
797
|
+
const command = config.release.gitTag ? "git push --follow-tags" : "git push";
|
|
798
|
+
if (dryRun) {
|
|
799
|
+
logger.info(`[dry-run] ${command}`);
|
|
800
|
+
} else {
|
|
801
|
+
logger.debug(`Executing: ${command}`);
|
|
802
|
+
await execPromise(command, { noStderr: true, noStdout: true, logLevel, cwd });
|
|
803
|
+
}
|
|
804
|
+
logger.success("Pushing changes and tags completed!");
|
|
805
|
+
}
|
|
806
|
+
function getFirstCommit(cwd) {
|
|
807
|
+
const result = execSync(
|
|
808
|
+
"git rev-list --max-parents=0 HEAD",
|
|
809
|
+
{
|
|
810
|
+
cwd,
|
|
811
|
+
encoding: "utf8"
|
|
812
|
+
}
|
|
813
|
+
);
|
|
814
|
+
return result.trim();
|
|
815
|
+
}
|
|
816
|
+
function getCurrentGitBranch(cwd) {
|
|
817
|
+
const result = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
818
|
+
cwd,
|
|
819
|
+
encoding: "utf8"
|
|
820
|
+
});
|
|
821
|
+
return result.trim();
|
|
822
|
+
}
|
|
823
|
+
function getCurrentGitRef(cwd) {
|
|
824
|
+
const branch = getCurrentGitBranch(cwd);
|
|
825
|
+
return branch || "HEAD";
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
async function generateMarkDown({
|
|
829
|
+
commits,
|
|
830
|
+
config,
|
|
831
|
+
from,
|
|
832
|
+
to,
|
|
833
|
+
isFirstCommit
|
|
834
|
+
}) {
|
|
835
|
+
const typeGroups = groupBy(commits, "type");
|
|
836
|
+
const markdown = [];
|
|
837
|
+
const breakingChanges = [];
|
|
838
|
+
const updatedConfig = {
|
|
839
|
+
...config,
|
|
840
|
+
from,
|
|
841
|
+
to
|
|
842
|
+
};
|
|
843
|
+
const versionTitle = updatedConfig.to;
|
|
844
|
+
const changelogTitle = `${updatedConfig.from}...${updatedConfig.to}`;
|
|
845
|
+
markdown.push("", `## ${changelogTitle}`, "");
|
|
846
|
+
if (updatedConfig.repo && updatedConfig.from && versionTitle) {
|
|
847
|
+
const formattedCompareLink = formatCompareChanges(versionTitle, {
|
|
848
|
+
...updatedConfig,
|
|
849
|
+
from: isFirstCommit ? getFirstCommit(updatedConfig.cwd) : updatedConfig.from
|
|
850
|
+
});
|
|
851
|
+
markdown.push(formattedCompareLink);
|
|
852
|
+
}
|
|
853
|
+
for (const type in updatedConfig.types) {
|
|
854
|
+
const group = typeGroups[type];
|
|
855
|
+
if (!group || group.length === 0) {
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
858
|
+
if (typeof updatedConfig.types[type] === "boolean") {
|
|
859
|
+
continue;
|
|
860
|
+
}
|
|
861
|
+
markdown.push("", `### ${updatedConfig.types[type]?.title}`, "");
|
|
862
|
+
for (const commit of group.reverse()) {
|
|
863
|
+
const line = formatCommit(commit, updatedConfig);
|
|
864
|
+
markdown.push(line);
|
|
865
|
+
if (commit.isBreaking) {
|
|
866
|
+
breakingChanges.push(line);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
if (breakingChanges.length > 0) {
|
|
871
|
+
markdown.push("", "#### \u26A0\uFE0F Breaking Changes", "", ...breakingChanges);
|
|
872
|
+
}
|
|
873
|
+
const _authors = /* @__PURE__ */ new Map();
|
|
874
|
+
for (const commit of commits) {
|
|
875
|
+
if (!commit.author) {
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
const name = formatName(commit.author.name);
|
|
879
|
+
if (!name || name.includes("[bot]")) {
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
if (updatedConfig.excludeAuthors && updatedConfig.excludeAuthors.some(
|
|
883
|
+
(v) => name.includes(v) || commit.author.email?.includes(v)
|
|
884
|
+
)) {
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
if (_authors.has(name)) {
|
|
888
|
+
const entry = _authors.get(name);
|
|
889
|
+
entry?.email.add(commit.author.email);
|
|
890
|
+
} else {
|
|
891
|
+
_authors.set(name, { email: /* @__PURE__ */ new Set([commit.author.email]), name });
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
if (updatedConfig.repo?.provider === "github") {
|
|
895
|
+
await Promise.all(
|
|
896
|
+
[..._authors.keys()].map(async (authorName) => {
|
|
897
|
+
const meta = _authors.get(authorName);
|
|
898
|
+
if (!meta) {
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
for (const data of [...meta.email, meta.name]) {
|
|
902
|
+
const { user } = await fetch$1(`https://ungh.cc/users/find/${data}`).then((r) => r.json()).catch(() => ({ user: null }));
|
|
903
|
+
if (user) {
|
|
904
|
+
meta.github = user.username;
|
|
905
|
+
break;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
})
|
|
909
|
+
);
|
|
910
|
+
}
|
|
911
|
+
const authors = [..._authors.entries()].map((e) => ({
|
|
912
|
+
name: e[0],
|
|
913
|
+
...e[1]
|
|
914
|
+
}));
|
|
915
|
+
if (authors.length > 0 && !updatedConfig.noAuthors) {
|
|
916
|
+
markdown.push(
|
|
917
|
+
"",
|
|
918
|
+
"### \u2764\uFE0F Contributors",
|
|
919
|
+
"",
|
|
920
|
+
...authors.map((i) => {
|
|
921
|
+
const _email = [...i.email].find(
|
|
922
|
+
(e) => !e.includes("noreply.github.com")
|
|
923
|
+
);
|
|
924
|
+
const email = updatedConfig.hideAuthorEmail !== true && _email ? ` <${_email}>` : "";
|
|
925
|
+
const github = i.github ? ` ([@${i.github}](https://github.com/${i.github}))` : "";
|
|
926
|
+
return `- ${i.name}${github || email || ""}`;
|
|
927
|
+
})
|
|
928
|
+
);
|
|
929
|
+
}
|
|
930
|
+
const result = convert(markdown.join("\n").trim(), true);
|
|
931
|
+
return result;
|
|
932
|
+
}
|
|
933
|
+
function getCommitBody(commit) {
|
|
934
|
+
if (!commit.body) {
|
|
935
|
+
return "";
|
|
936
|
+
}
|
|
937
|
+
const lines = commit.body.split("\n");
|
|
938
|
+
const contentLines = lines.filter((line) => {
|
|
939
|
+
const trimmedLine = line.trim();
|
|
940
|
+
if (!trimmedLine) {
|
|
941
|
+
return false;
|
|
942
|
+
}
|
|
943
|
+
const isFileLine = /^[AMDTUXB](?:\d{3})?\s+/.test(trimmedLine) || /^[RCM]\d{3}\s+/.test(trimmedLine);
|
|
944
|
+
return !isFileLine;
|
|
945
|
+
});
|
|
946
|
+
if (contentLines.length === 0) {
|
|
947
|
+
return "";
|
|
948
|
+
}
|
|
949
|
+
const indentedBody = contentLines.map((line) => ` ${line}`).join("\n");
|
|
950
|
+
return `
|
|
951
|
+
|
|
952
|
+
${indentedBody}
|
|
953
|
+
`;
|
|
954
|
+
}
|
|
955
|
+
function formatCommit(commit, config) {
|
|
956
|
+
const body = config.changelog.includeCommitBody ? getCommitBody(commit) : "";
|
|
957
|
+
return `- ${commit.scope ? `**${commit.scope.trim()}:** ` : ""}${commit.isBreaking ? "\u26A0\uFE0F " : ""}${upperFirst(commit.description)}${formatReferences(commit.references, config)}${body}`;
|
|
958
|
+
}
|
|
959
|
+
function formatReferences(references, config) {
|
|
960
|
+
const pr = references.filter((ref) => ref.type === "pull-request");
|
|
961
|
+
const issue = references.filter((ref) => ref.type === "issue");
|
|
962
|
+
if (pr.length > 0 || issue.length > 0) {
|
|
963
|
+
return ` (${[...pr, ...issue].map((ref) => formatReference(ref, config.repo)).join(", ")})`;
|
|
964
|
+
}
|
|
965
|
+
if (references.length > 0) {
|
|
966
|
+
return ` (${formatReference(references[0], config.repo)})`;
|
|
967
|
+
}
|
|
968
|
+
return "";
|
|
969
|
+
}
|
|
970
|
+
function formatName(name = "") {
|
|
971
|
+
return name.split(" ").map((p) => upperFirst(p.trim())).join(" ");
|
|
972
|
+
}
|
|
973
|
+
function groupBy(items, key) {
|
|
974
|
+
const groups = {};
|
|
975
|
+
for (const item of items) {
|
|
976
|
+
groups[item[key]] = groups[item[key]] || [];
|
|
977
|
+
groups[item[key]]?.push(item);
|
|
978
|
+
}
|
|
979
|
+
return groups;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function fromTagIsFirstCommit(fromTag, cwd) {
|
|
983
|
+
return fromTag === getFirstCommit(cwd);
|
|
984
|
+
}
|
|
985
|
+
async function generateChangelog({
|
|
986
|
+
pkg,
|
|
987
|
+
config,
|
|
988
|
+
dryRun,
|
|
989
|
+
newVersion
|
|
990
|
+
}) {
|
|
991
|
+
let fromTag = config.from || pkg.fromTag || getFirstCommit(config.cwd);
|
|
992
|
+
const isFirstCommit = fromTagIsFirstCommit(fromTag, config.cwd);
|
|
993
|
+
if (isFirstCommit) {
|
|
994
|
+
fromTag = config.monorepo?.versionMode === "independent" ? getIndependentTag({ version: "0.0.0", name: pkg.name }) : config.templates.tagBody.replace("{{newVersion}}", "0.0.0");
|
|
995
|
+
}
|
|
996
|
+
let toTag = config.to;
|
|
997
|
+
if (!toTag) {
|
|
998
|
+
toTag = config.monorepo?.versionMode === "independent" ? getIndependentTag({ version: newVersion, name: pkg.name }) : config.templates.tagBody.replace("{{newVersion}}", newVersion);
|
|
999
|
+
}
|
|
1000
|
+
if (!toTag) {
|
|
1001
|
+
throw new Error(`No tag found for ${pkg.name}`);
|
|
1002
|
+
}
|
|
1003
|
+
logger.debug(`Generating changelog for ${pkg.name} - from ${fromTag} to ${toTag}`);
|
|
1004
|
+
try {
|
|
1005
|
+
config = {
|
|
1006
|
+
...config,
|
|
1007
|
+
from: fromTag,
|
|
1008
|
+
to: toTag
|
|
1009
|
+
};
|
|
1010
|
+
const generatedChangelog = await generateMarkDown({
|
|
1011
|
+
commits: pkg.commits,
|
|
1012
|
+
config,
|
|
1013
|
+
from: fromTag,
|
|
1014
|
+
isFirstCommit,
|
|
1015
|
+
to: toTag
|
|
562
1016
|
});
|
|
563
1017
|
let changelog = generatedChangelog;
|
|
564
1018
|
if (pkg.commits.length === 0) {
|
|
@@ -658,7 +1112,8 @@ function getDefaultConfig() {
|
|
|
658
1112
|
},
|
|
659
1113
|
publish: {
|
|
660
1114
|
private: false,
|
|
661
|
-
args: []
|
|
1115
|
+
args: [],
|
|
1116
|
+
safetyCheck: false
|
|
662
1117
|
},
|
|
663
1118
|
tokens: {
|
|
664
1119
|
gitlab: process$1.env.RELIZY_GITLAB_TOKEN || process$1.env.GITLAB_TOKEN || process$1.env.GITLAB_API_TOKEN || process$1.env.CI_JOB_TOKEN,
|
|
@@ -672,7 +1127,8 @@ function getDefaultConfig() {
|
|
|
672
1127
|
push: true,
|
|
673
1128
|
clean: true,
|
|
674
1129
|
providerRelease: true,
|
|
675
|
-
noVerify: false
|
|
1130
|
+
noVerify: false,
|
|
1131
|
+
gitTag: true
|
|
676
1132
|
},
|
|
677
1133
|
logLevel: "default",
|
|
678
1134
|
safetyCheck: true
|
|
@@ -721,132 +1177,14 @@ async function loadRelizyConfig(options) {
|
|
|
721
1177
|
process$1.exit(1);
|
|
722
1178
|
}
|
|
723
1179
|
}
|
|
724
|
-
setupLogger(options?.overrides?.logLevel || results.config.logLevel);
|
|
725
|
-
logger.verbose("User config:", formatJson(results.config.changelog));
|
|
726
|
-
const resolvedConfig = await resolveConfig(results.config, cwd);
|
|
727
|
-
logger.debug("Resolved config:", formatJson(resolvedConfig));
|
|
728
|
-
return resolvedConfig;
|
|
729
|
-
}
|
|
730
|
-
function defineConfig(config) {
|
|
731
|
-
return config;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
function getPackageDependencies({
|
|
735
|
-
packagePath,
|
|
736
|
-
allPackageNames,
|
|
737
|
-
dependencyTypes
|
|
738
|
-
}) {
|
|
739
|
-
const packageJsonPath = join(packagePath, "package.json");
|
|
740
|
-
if (!existsSync(packageJsonPath)) {
|
|
741
|
-
return [];
|
|
742
|
-
}
|
|
743
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
744
|
-
const deps = [];
|
|
745
|
-
const allDeps = {
|
|
746
|
-
...dependencyTypes?.includes("dependencies") ? packageJson.dependencies : {},
|
|
747
|
-
...dependencyTypes?.includes("peerDependencies") ? packageJson.peerDependencies : {},
|
|
748
|
-
...dependencyTypes?.includes("devDependencies") ? packageJson.devDependencies : {}
|
|
749
|
-
};
|
|
750
|
-
for (const depName of Object.keys(allDeps)) {
|
|
751
|
-
if (allPackageNames.has(depName)) {
|
|
752
|
-
deps.push(depName);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
return deps;
|
|
756
|
-
}
|
|
757
|
-
function getDependentsOf({
|
|
758
|
-
allPackages,
|
|
759
|
-
packageName
|
|
760
|
-
}) {
|
|
761
|
-
return allPackages.filter(
|
|
762
|
-
(pkg) => pkg.dependencies.includes(packageName)
|
|
763
|
-
);
|
|
764
|
-
}
|
|
765
|
-
function expandPackagesToBumpWithDependents({
|
|
766
|
-
allPackages,
|
|
767
|
-
packagesWithCommits
|
|
768
|
-
}) {
|
|
769
|
-
const result = /* @__PURE__ */ new Map();
|
|
770
|
-
logger.debug(`Expanding packages to bump: ${packagesWithCommits.length} packages with commits, ${allPackages.length} total packages`);
|
|
771
|
-
for (const pkg of packagesWithCommits) {
|
|
772
|
-
const packageToBump = {
|
|
773
|
-
...pkg,
|
|
774
|
-
reason: "commits"
|
|
775
|
-
};
|
|
776
|
-
result.set(pkg.name, packageToBump);
|
|
777
|
-
}
|
|
778
|
-
const toProcess = [...packagesWithCommits.map((p) => p.name)];
|
|
779
|
-
const processed = /* @__PURE__ */ new Set();
|
|
780
|
-
while (toProcess.length > 0) {
|
|
781
|
-
const currentPkgName = toProcess.shift();
|
|
782
|
-
if (!currentPkgName || processed.has(currentPkgName)) {
|
|
783
|
-
continue;
|
|
784
|
-
}
|
|
785
|
-
processed.add(currentPkgName);
|
|
786
|
-
const dependents = getDependentsOf({
|
|
787
|
-
packageName: currentPkgName,
|
|
788
|
-
allPackages
|
|
789
|
-
});
|
|
790
|
-
for (const dependent of dependents) {
|
|
791
|
-
if (!result.has(dependent.name)) {
|
|
792
|
-
const currentChain = result.get(currentPkgName)?.dependencyChain || [];
|
|
793
|
-
const chain = [...currentChain, currentPkgName];
|
|
794
|
-
const packageBase = allPackages.find((p) => p.name === dependent.name);
|
|
795
|
-
if (packageBase) {
|
|
796
|
-
const packageToBump = {
|
|
797
|
-
...packageBase,
|
|
798
|
-
reason: "dependency",
|
|
799
|
-
dependencyChain: chain
|
|
800
|
-
};
|
|
801
|
-
result.set(dependent.name, packageToBump);
|
|
802
|
-
toProcess.push(dependent.name);
|
|
803
|
-
logger.debug(`${dependent.name} will be bumped (depends on ${chain.join(" \u2192 ")})`);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
return Array.from(result.values());
|
|
809
|
-
}
|
|
810
|
-
function topologicalSort(packages) {
|
|
811
|
-
const sorted = [];
|
|
812
|
-
const visited = /* @__PURE__ */ new Set();
|
|
813
|
-
const visiting = /* @__PURE__ */ new Set();
|
|
814
|
-
const packageMap = /* @__PURE__ */ new Map();
|
|
815
|
-
for (const pkg of packages) {
|
|
816
|
-
packageMap.set(pkg.name, pkg);
|
|
817
|
-
}
|
|
818
|
-
function visit(pkgName, path = []) {
|
|
819
|
-
logger.debug(`Visiting ${pkgName}, path: ${path.join(" \u2192 ")}, visiting: ${Array.from(visiting).join(", ")}`);
|
|
820
|
-
if (visiting.has(pkgName)) {
|
|
821
|
-
const cycle = [...path, pkgName];
|
|
822
|
-
logger.warn(`Circular dependency detected: ${cycle.join(" \u2192 ")}`);
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
|
-
if (visited.has(pkgName)) {
|
|
826
|
-
logger.debug(`${pkgName} already visited globally, skipping`);
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
|
-
visiting.add(pkgName);
|
|
830
|
-
logger.debug(`Added ${pkgName} to visiting set`);
|
|
831
|
-
const pkg = packageMap.get(pkgName);
|
|
832
|
-
if (!pkg) {
|
|
833
|
-
logger.debug(`Package ${pkgName} not found in packageMap`);
|
|
834
|
-
visiting.delete(pkgName);
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
logger.debug(`${pkgName} has dependencies: ${pkg.dependencies.join(", ")}`);
|
|
838
|
-
for (const depName of pkg.dependencies) {
|
|
839
|
-
visit(depName, [...path, pkgName]);
|
|
840
|
-
}
|
|
841
|
-
visiting.delete(pkgName);
|
|
842
|
-
visited.add(pkgName);
|
|
843
|
-
sorted.push(pkg);
|
|
844
|
-
logger.debug(`Finished visiting ${pkgName}`);
|
|
845
|
-
}
|
|
846
|
-
for (const pkg of packages) {
|
|
847
|
-
visit(pkg.name);
|
|
848
|
-
}
|
|
849
|
-
return sorted;
|
|
1180
|
+
setupLogger(options?.overrides?.logLevel || results.config.logLevel);
|
|
1181
|
+
logger.verbose("User config:", formatJson(results.config.changelog));
|
|
1182
|
+
const resolvedConfig = await resolveConfig(results.config, cwd);
|
|
1183
|
+
logger.debug("Resolved config:", formatJson(resolvedConfig));
|
|
1184
|
+
return resolvedConfig;
|
|
1185
|
+
}
|
|
1186
|
+
function defineConfig(config) {
|
|
1187
|
+
return config;
|
|
850
1188
|
}
|
|
851
1189
|
|
|
852
1190
|
async function githubIndependentMode({
|
|
@@ -864,10 +1202,10 @@ async function githubIndependentMode({
|
|
|
864
1202
|
if (!config.tokens.github && !config.repo?.token) {
|
|
865
1203
|
throw new Error("No GitHub token specified. Set GITHUB_TOKEN or GH_TOKEN environment variable.");
|
|
866
1204
|
}
|
|
867
|
-
const packages =
|
|
868
|
-
suffix,
|
|
869
|
-
patterns: config.monorepo?.packages,
|
|
1205
|
+
const packages = await getPackagesOrBumpedPackages({
|
|
870
1206
|
config,
|
|
1207
|
+
bumpResult,
|
|
1208
|
+
suffix,
|
|
871
1209
|
force
|
|
872
1210
|
});
|
|
873
1211
|
logger.info(`Creating ${packages.length} GitHub release(s)`);
|
|
@@ -941,12 +1279,13 @@ async function githubUnified({
|
|
|
941
1279
|
if (!config.tokens.github && !config.repo?.token) {
|
|
942
1280
|
throw new Error("No GitHub token specified. Set GITHUB_TOKEN or GH_TOKEN environment variable.");
|
|
943
1281
|
}
|
|
944
|
-
const
|
|
1282
|
+
const newVersion = bumpResult?.newVersion || rootPackage.version;
|
|
1283
|
+
const to = config.to || config.templates.tagBody.replace("{{newVersion}}", newVersion);
|
|
945
1284
|
const changelog = await generateChangelog({
|
|
946
1285
|
pkg: rootPackage,
|
|
947
1286
|
config,
|
|
948
1287
|
dryRun,
|
|
949
|
-
newVersion
|
|
1288
|
+
newVersion
|
|
950
1289
|
});
|
|
951
1290
|
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
952
1291
|
const release = {
|
|
@@ -1006,10 +1345,14 @@ async function github(options) {
|
|
|
1006
1345
|
});
|
|
1007
1346
|
}
|
|
1008
1347
|
const rootPackageBase = readPackageJson(config.cwd);
|
|
1348
|
+
if (!rootPackageBase) {
|
|
1349
|
+
throw new Error("Failed to read root package.json");
|
|
1350
|
+
}
|
|
1351
|
+
const newVersion = options.bumpResult?.newVersion || rootPackageBase.version;
|
|
1009
1352
|
const { from, to } = await resolveTags({
|
|
1010
1353
|
config,
|
|
1011
1354
|
step: "provider-release",
|
|
1012
|
-
newVersion
|
|
1355
|
+
newVersion,
|
|
1013
1356
|
pkg: rootPackageBase
|
|
1014
1357
|
});
|
|
1015
1358
|
const rootPackage = options.bumpResult?.rootPackage || await getRootPackage({
|
|
@@ -1101,9 +1444,9 @@ async function gitlabIndependentMode({
|
|
|
1101
1444
|
force
|
|
1102
1445
|
}) {
|
|
1103
1446
|
logger.debug(`GitLab token: ${config.tokens.gitlab || config.repo?.token ? "\u2713 provided" : "\u2717 missing"}`);
|
|
1104
|
-
const packages =
|
|
1105
|
-
patterns: config.monorepo?.packages,
|
|
1447
|
+
const packages = await getPackagesOrBumpedPackages({
|
|
1106
1448
|
config,
|
|
1449
|
+
bumpResult,
|
|
1107
1450
|
suffix,
|
|
1108
1451
|
force
|
|
1109
1452
|
});
|
|
@@ -1174,12 +1517,13 @@ async function gitlabUnified({
|
|
|
1174
1517
|
bumpResult
|
|
1175
1518
|
}) {
|
|
1176
1519
|
logger.debug(`GitLab token: ${config.tokens.gitlab || config.repo?.token ? "\u2713 provided" : "\u2717 missing"}`);
|
|
1177
|
-
const
|
|
1520
|
+
const newVersion = bumpResult?.newVersion || rootPackage.newVersion || rootPackage.version;
|
|
1521
|
+
const to = config.templates.tagBody.replace("{{newVersion}}", newVersion);
|
|
1178
1522
|
const changelog = await generateChangelog({
|
|
1179
1523
|
pkg: rootPackage,
|
|
1180
1524
|
config,
|
|
1181
1525
|
dryRun,
|
|
1182
|
-
newVersion
|
|
1526
|
+
newVersion
|
|
1183
1527
|
});
|
|
1184
1528
|
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
1185
1529
|
logger.debug("Getting current branch...");
|
|
@@ -1216,7 +1560,7 @@ async function gitlabUnified({
|
|
|
1216
1560
|
name: to,
|
|
1217
1561
|
tag: to,
|
|
1218
1562
|
version: to,
|
|
1219
|
-
prerelease: isPrerelease(
|
|
1563
|
+
prerelease: isPrerelease(newVersion)
|
|
1220
1564
|
}];
|
|
1221
1565
|
}
|
|
1222
1566
|
async function gitlab(options = {}) {
|
|
@@ -1245,10 +1589,14 @@ async function gitlab(options = {}) {
|
|
|
1245
1589
|
});
|
|
1246
1590
|
}
|
|
1247
1591
|
const rootPackageBase = readPackageJson(config.cwd);
|
|
1592
|
+
if (!rootPackageBase) {
|
|
1593
|
+
throw new Error("Failed to read root package.json");
|
|
1594
|
+
}
|
|
1595
|
+
const newVersion = options.bumpResult?.newVersion || rootPackageBase.version;
|
|
1248
1596
|
const { from, to } = await resolveTags({
|
|
1249
1597
|
config,
|
|
1250
1598
|
step: "provider-release",
|
|
1251
|
-
newVersion
|
|
1599
|
+
newVersion,
|
|
1252
1600
|
pkg: rootPackageBase
|
|
1253
1601
|
});
|
|
1254
1602
|
const rootPackage = options.bumpResult?.rootPackage || await getRootPackage({
|
|
@@ -1259,7 +1607,7 @@ async function gitlab(options = {}) {
|
|
|
1259
1607
|
from,
|
|
1260
1608
|
to
|
|
1261
1609
|
});
|
|
1262
|
-
logger.debug(`Root package: ${getIndependentTag({ name: rootPackage.name, version:
|
|
1610
|
+
logger.debug(`Root package: ${getIndependentTag({ name: rootPackage.name, version: newVersion })}`);
|
|
1263
1611
|
return await gitlabUnified({
|
|
1264
1612
|
config,
|
|
1265
1613
|
dryRun,
|
|
@@ -1272,6 +1620,12 @@ async function gitlab(options = {}) {
|
|
|
1272
1620
|
}
|
|
1273
1621
|
}
|
|
1274
1622
|
|
|
1623
|
+
function isGraduatingToStableBetweenVersion(version, newVersion) {
|
|
1624
|
+
const isSameBase = semver.major(version) === semver.major(newVersion) && semver.minor(version) === semver.minor(newVersion) && semver.patch(version) === semver.patch(newVersion);
|
|
1625
|
+
const fromPrerelease = semver.prerelease(version) !== null;
|
|
1626
|
+
const toStable = semver.prerelease(newVersion) === null;
|
|
1627
|
+
return isSameBase && fromPrerelease && toStable;
|
|
1628
|
+
}
|
|
1275
1629
|
function determineSemverChange(commits, types) {
|
|
1276
1630
|
let [hasMajor, hasMinor, hasPatch] = [false, false, false];
|
|
1277
1631
|
for (const commit of commits) {
|
|
@@ -1402,26 +1756,27 @@ function determineReleaseType({
|
|
|
1402
1756
|
}
|
|
1403
1757
|
return handleExplicitReleaseType({ releaseType, currentVersion });
|
|
1404
1758
|
}
|
|
1405
|
-
function writeVersion(pkgPath,
|
|
1759
|
+
function writeVersion(pkgPath, newVersion, dryRun = false) {
|
|
1406
1760
|
const packageJsonPath = join(pkgPath, "package.json");
|
|
1407
1761
|
try {
|
|
1408
|
-
logger.debug(`Writing ${
|
|
1762
|
+
logger.debug(`Writing ${newVersion} to ${pkgPath}`);
|
|
1409
1763
|
const content = readFileSync(packageJsonPath, "utf8");
|
|
1410
1764
|
const packageJson = JSON.parse(content);
|
|
1411
1765
|
const oldVersion = packageJson.version;
|
|
1412
|
-
packageJson.version =
|
|
1766
|
+
packageJson.version = newVersion;
|
|
1413
1767
|
if (dryRun) {
|
|
1414
|
-
logger.info(`[dry-run] Updated ${packageJson.name}: ${oldVersion} \u2192 ${
|
|
1768
|
+
logger.info(`[dry-run] Updated ${packageJson.name}: ${oldVersion} \u2192 ${newVersion}`);
|
|
1415
1769
|
return;
|
|
1416
1770
|
}
|
|
1417
1771
|
writeFileSync(packageJsonPath, `${formatJson(packageJson)}
|
|
1418
1772
|
`, "utf8");
|
|
1419
|
-
logger.info(`Updated ${packageJson.name}: ${oldVersion} \u2192 ${
|
|
1773
|
+
logger.info(`Updated ${packageJson.name}: ${oldVersion} \u2192 ${newVersion}`);
|
|
1420
1774
|
} catch (error) {
|
|
1421
1775
|
throw new Error(`Unable to write version to ${packageJsonPath}: ${error}`);
|
|
1422
1776
|
}
|
|
1423
1777
|
}
|
|
1424
1778
|
function getPackageNewVersion({
|
|
1779
|
+
name,
|
|
1425
1780
|
currentVersion,
|
|
1426
1781
|
releaseType,
|
|
1427
1782
|
preid,
|
|
@@ -1429,7 +1784,7 @@ function getPackageNewVersion({
|
|
|
1429
1784
|
}) {
|
|
1430
1785
|
let newVersion = semver.inc(currentVersion, releaseType, preid);
|
|
1431
1786
|
if (!newVersion) {
|
|
1432
|
-
throw new Error(`Unable to bump version "${currentVersion}" with release type "${releaseType}"
|
|
1787
|
+
throw new Error(`Unable to bump "${name}" version "${currentVersion}" with release type "${releaseType}"
|
|
1433
1788
|
|
|
1434
1789
|
You should use an explicit release type (use flag: --major, --minor, --patch, --premajor, --preminor, --prepatch, --prerelease)`);
|
|
1435
1790
|
}
|
|
@@ -1438,13 +1793,13 @@ You should use an explicit release type (use flag: --major, --minor, --patch, --
|
|
|
1438
1793
|
}
|
|
1439
1794
|
const isValidVersion = semver.gt(newVersion, currentVersion);
|
|
1440
1795
|
if (!isValidVersion) {
|
|
1441
|
-
throw new Error(`Unable to bump version "${currentVersion}" to "${newVersion}", new version is not greater than current version`);
|
|
1796
|
+
throw new Error(`Unable to bump "${name}" version "${currentVersion}" to "${newVersion}", new version is not greater than current version`);
|
|
1442
1797
|
}
|
|
1443
1798
|
if (isGraduating(currentVersion, releaseType)) {
|
|
1444
|
-
logger.info(`Graduating from prerelease ${currentVersion} to stable ${newVersion}`);
|
|
1799
|
+
logger.info(`Graduating "${name}" from prerelease ${currentVersion} to stable ${newVersion}`);
|
|
1445
1800
|
}
|
|
1446
1801
|
if (isChangedPreid(currentVersion, preid)) {
|
|
1447
|
-
logger.debug(`Graduating from ${getPreid(currentVersion)} to ${preid}`);
|
|
1802
|
+
logger.debug(`Graduating "${name}" from ${getPreid(currentVersion)} to ${preid}`);
|
|
1448
1803
|
}
|
|
1449
1804
|
return newVersion;
|
|
1450
1805
|
}
|
|
@@ -1668,14 +2023,12 @@ async function confirmBump({
|
|
|
1668
2023
|
});
|
|
1669
2024
|
if (versionMode === "unified") {
|
|
1670
2025
|
if (!newVersion) {
|
|
1671
|
-
|
|
1672
|
-
process.exit(1);
|
|
2026
|
+
throw new Error("Cannot confirm bump in unified mode without a new version");
|
|
1673
2027
|
}
|
|
1674
2028
|
displayUnifiedModePackages({ packages, newVersion, force });
|
|
1675
2029
|
} else if (versionMode === "selective") {
|
|
1676
2030
|
if (!newVersion) {
|
|
1677
|
-
|
|
1678
|
-
process.exit(1);
|
|
2031
|
+
throw new Error("Cannot confirm bump in selective mode without a new version");
|
|
1679
2032
|
}
|
|
1680
2033
|
displaySelectiveModePackages({ packages, newVersion, force });
|
|
1681
2034
|
} else if (versionMode === "independent") {
|
|
@@ -1878,12 +2231,13 @@ async function resolveTags({
|
|
|
1878
2231
|
const logLevel = config.logLevel;
|
|
1879
2232
|
logger.debug(`[${versionMode}](${step}) Resolving tags`);
|
|
1880
2233
|
const releaseType = config.bump.type;
|
|
2234
|
+
const graduating = typeof newVersion === "string" ? isGraduatingToStableBetweenVersion(pkg.version, newVersion) : isGraduating(pkg.version, releaseType);
|
|
1881
2235
|
const from = await resolveFromTag({
|
|
1882
2236
|
config,
|
|
1883
2237
|
versionMode,
|
|
1884
2238
|
step,
|
|
1885
2239
|
packageName: pkg.name,
|
|
1886
|
-
graduating
|
|
2240
|
+
graduating,
|
|
1887
2241
|
logLevel
|
|
1888
2242
|
});
|
|
1889
2243
|
const to = resolveToTag({
|
|
@@ -1891,541 +2245,284 @@ async function resolveTags({
|
|
|
1891
2245
|
versionMode,
|
|
1892
2246
|
newVersion,
|
|
1893
2247
|
step,
|
|
1894
|
-
packageName: pkg.name
|
|
1895
|
-
});
|
|
1896
|
-
logger.debug(`[${versionMode}](${step}) Using tags: ${from} \u2192 ${to}`);
|
|
1897
|
-
return { from, to };
|
|
1898
|
-
}
|
|
1899
|
-
|
|
1900
|
-
let sessionOtp;
|
|
1901
|
-
function detectPackageManager(cwd = process.cwd()) {
|
|
1902
|
-
try {
|
|
1903
|
-
const packageJsonPath = join(cwd, "package.json");
|
|
1904
|
-
if (existsSync(packageJsonPath)) {
|
|
1905
|
-
try {
|
|
1906
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
1907
|
-
const pmField = packageJson.packageManager;
|
|
1908
|
-
if (typeof pmField === "string") {
|
|
1909
|
-
const pmName = pmField.split("@")[0];
|
|
1910
|
-
if (["npm", "pnpm", "yarn", "bun"].includes(pmName)) {
|
|
1911
|
-
logger.debug(`Detected package manager from package.json: ${pmName}`);
|
|
1912
|
-
return pmName;
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
} catch (e) {
|
|
1916
|
-
const errorString = e instanceof Error ? e.message : String(e);
|
|
1917
|
-
logger.debug(`Failed to parse package.json: ${errorString}`);
|
|
1918
|
-
}
|
|
1919
|
-
}
|
|
1920
|
-
const lockFiles = {
|
|
1921
|
-
pnpm: "pnpm-lock.yaml",
|
|
1922
|
-
yarn: "yarn.lock",
|
|
1923
|
-
npm: "package-lock.json",
|
|
1924
|
-
bun: "bun.lockb"
|
|
1925
|
-
};
|
|
1926
|
-
for (const [manager, file] of Object.entries(lockFiles)) {
|
|
1927
|
-
if (existsSync(join(cwd, file))) {
|
|
1928
|
-
logger.debug(`Detected package manager from lockfile: ${manager}`);
|
|
1929
|
-
return manager;
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
const ua = process.env.npm_config_user_agent;
|
|
1933
|
-
if (ua) {
|
|
1934
|
-
const match = /(pnpm|yarn|npm|bun)/.exec(ua);
|
|
1935
|
-
if (match) {
|
|
1936
|
-
logger.debug(`Detected package manager from user agent: ${match[1]}`);
|
|
1937
|
-
return match[1];
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
logger.debug("No package manager detected, defaulting to npm");
|
|
1941
|
-
return "npm";
|
|
1942
|
-
} catch (error) {
|
|
1943
|
-
logger.fail(`Error detecting package manager: ${error}, defaulting to npm`);
|
|
1944
|
-
return "npm";
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
function determinePublishTag(version, configTag) {
|
|
1948
|
-
let tag = "latest";
|
|
1949
|
-
if (configTag) {
|
|
1950
|
-
tag = configTag;
|
|
1951
|
-
}
|
|
1952
|
-
if (isPrerelease(version) && !configTag) {
|
|
1953
|
-
logger.warn('You are about to publish a "prerelease" version with the "latest" tag. To avoid mistake, the tag is set to "next"');
|
|
1954
|
-
tag = "next";
|
|
1955
|
-
}
|
|
1956
|
-
if (isPrerelease(version) && configTag === "latest") {
|
|
1957
|
-
logger.warn('Please note, you are about to publish a "prerelease" version with the "latest" tag.');
|
|
1958
|
-
}
|
|
1959
|
-
return tag;
|
|
1960
|
-
}
|
|
1961
|
-
function getPackagesToPublishInSelectiveMode(sortedPackages, rootVersion) {
|
|
1962
|
-
const packagesToPublish = [];
|
|
1963
|
-
for (const pkg of sortedPackages) {
|
|
1964
|
-
const pkgJsonPath = join(pkg.path, "package.json");
|
|
1965
|
-
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
1966
|
-
if (pkgJson.version === rootVersion) {
|
|
1967
|
-
packagesToPublish.push(pkg);
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
return packagesToPublish;
|
|
1971
|
-
}
|
|
1972
|
-
async function getPackagesToPublishInIndependentMode(sortedPackages, config) {
|
|
1973
|
-
const packagesToPublish = [];
|
|
1974
|
-
for (const pkg of sortedPackages) {
|
|
1975
|
-
const { from, to } = await resolveTags({
|
|
1976
|
-
config,
|
|
1977
|
-
step: "publish",
|
|
1978
|
-
pkg,
|
|
1979
|
-
newVersion: pkg.version
|
|
1980
|
-
});
|
|
1981
|
-
if (pkg.commits.length > 0) {
|
|
1982
|
-
packagesToPublish.push(pkg);
|
|
1983
|
-
logger.debug(`${pkg.name}: ${pkg.commits.length} commit(s) since ${from} \u2192 ${to}`);
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
return packagesToPublish;
|
|
1987
|
-
}
|
|
1988
|
-
function isYarnBerry() {
|
|
1989
|
-
return existsSync(path.join(process.cwd(), ".yarnrc.yml"));
|
|
1990
|
-
}
|
|
1991
|
-
function getCommandArgs({
|
|
1992
|
-
packageManager,
|
|
1993
|
-
tag,
|
|
1994
|
-
config,
|
|
1995
|
-
otp
|
|
1996
|
-
}) {
|
|
1997
|
-
const args = ["publish", "--tag", tag];
|
|
1998
|
-
if (packageManager === "pnpm") {
|
|
1999
|
-
args.push("--no-git-checks");
|
|
2000
|
-
} else if (packageManager === "yarn") {
|
|
2001
|
-
args.push("--non-interactive");
|
|
2002
|
-
if (isYarnBerry())
|
|
2003
|
-
args.push("--no-git-checks");
|
|
2004
|
-
} else if (packageManager === "npm") {
|
|
2005
|
-
args.push("--yes");
|
|
2006
|
-
}
|
|
2007
|
-
const registry = config.publish.registry;
|
|
2008
|
-
if (registry) {
|
|
2009
|
-
args.push("--registry", registry);
|
|
2010
|
-
}
|
|
2011
|
-
const access = config.publish.access;
|
|
2012
|
-
if (access) {
|
|
2013
|
-
args.push("--access", access);
|
|
2014
|
-
}
|
|
2015
|
-
const finalOtp = otp ?? sessionOtp ?? config.publish.otp;
|
|
2016
|
-
if (finalOtp) {
|
|
2017
|
-
args.push("--otp", finalOtp);
|
|
2018
|
-
}
|
|
2019
|
-
return args;
|
|
2020
|
-
}
|
|
2021
|
-
function isOtpError(error) {
|
|
2022
|
-
if (typeof error !== "object" || error === null)
|
|
2023
|
-
return false;
|
|
2024
|
-
const errorMessage = "message" in error && typeof error.message === "string" ? error.message.toLowerCase() : "";
|
|
2025
|
-
return errorMessage.includes("otp") || errorMessage.includes("one-time password") || errorMessage.includes("eotp");
|
|
2026
|
-
}
|
|
2027
|
-
function promptOtpWithTimeout(timeout = 9e4) {
|
|
2028
|
-
return new Promise((resolve, reject) => {
|
|
2029
|
-
const timer = setTimeout(() => {
|
|
2030
|
-
reject(new Error("OTP input timeout"));
|
|
2031
|
-
}, timeout);
|
|
2032
|
-
input({
|
|
2033
|
-
message: "This operation requires a one-time password (OTP). Please enter your OTP:"
|
|
2034
|
-
}).then((otp) => {
|
|
2035
|
-
clearTimeout(timer);
|
|
2036
|
-
resolve(otp);
|
|
2037
|
-
}).catch((error) => {
|
|
2038
|
-
clearTimeout(timer);
|
|
2039
|
-
reject(error);
|
|
2040
|
-
});
|
|
2041
|
-
});
|
|
2042
|
-
}
|
|
2043
|
-
async function handleOtpError() {
|
|
2044
|
-
if (isInCI()) {
|
|
2045
|
-
logger.error("OTP required but running in CI environment. Please provide OTP via config or `--otp` flag");
|
|
2046
|
-
throw new Error("OTP required in CI environment");
|
|
2047
|
-
}
|
|
2048
|
-
logger.warn("Publish failed: OTP required");
|
|
2049
|
-
try {
|
|
2050
|
-
const otp = await promptOtpWithTimeout();
|
|
2051
|
-
logger.debug("OTP received, retrying publish...");
|
|
2052
|
-
return otp;
|
|
2053
|
-
} catch (promptError) {
|
|
2054
|
-
logger.error("Failed to get OTP:", promptError);
|
|
2055
|
-
throw promptError;
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
async function executePublishCommand({
|
|
2059
|
-
command,
|
|
2060
|
-
packageNameAndVersion,
|
|
2061
|
-
pkg,
|
|
2062
|
-
config,
|
|
2063
|
-
dryRun
|
|
2064
|
-
}) {
|
|
2065
|
-
logger.debug(`Executing publish command (${command}) in ${pkg.path}`);
|
|
2066
|
-
if (dryRun) {
|
|
2067
|
-
logger.info(`[dry-run] ${packageNameAndVersion}: Run ${command}`);
|
|
2068
|
-
return;
|
|
2069
|
-
}
|
|
2070
|
-
const { stdout } = await execPromise(command, {
|
|
2071
|
-
noStderr: true,
|
|
2072
|
-
noStdout: true,
|
|
2073
|
-
logLevel: config.logLevel,
|
|
2074
|
-
cwd: pkg.path
|
|
2075
|
-
});
|
|
2076
|
-
if (stdout) {
|
|
2077
|
-
logger.debug(stdout);
|
|
2078
|
-
}
|
|
2079
|
-
logger.info(`Published ${packageNameAndVersion}`);
|
|
2080
|
-
}
|
|
2081
|
-
async function publishPackage({
|
|
2082
|
-
pkg,
|
|
2083
|
-
config,
|
|
2084
|
-
packageManager,
|
|
2085
|
-
dryRun
|
|
2086
|
-
}) {
|
|
2087
|
-
const tag = determinePublishTag(pkg.version, config.publish.tag);
|
|
2088
|
-
const packageNameAndVersion = getIndependentTag({ name: pkg.name, version: pkg.newVersion || pkg.version });
|
|
2089
|
-
const baseCommand = packageManager === "yarn" && isYarnBerry() ? "yarn npm" : packageManager;
|
|
2090
|
-
logger.debug(`Building publish command for ${pkg.name}`);
|
|
2091
|
-
let dynamicOtp;
|
|
2092
|
-
const maxAttempts = 2;
|
|
2093
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
2094
|
-
try {
|
|
2095
|
-
const args = getCommandArgs({
|
|
2096
|
-
packageManager,
|
|
2097
|
-
tag,
|
|
2098
|
-
config,
|
|
2099
|
-
otp: dynamicOtp
|
|
2100
|
-
});
|
|
2101
|
-
const command = `${baseCommand} ${args.join(" ")}`;
|
|
2102
|
-
logger.debug(`Publishing ${packageNameAndVersion} with tag '${tag}' with command: ${command}`);
|
|
2103
|
-
process.chdir(pkg.path);
|
|
2104
|
-
await executePublishCommand({
|
|
2105
|
-
command,
|
|
2106
|
-
packageNameAndVersion,
|
|
2107
|
-
pkg,
|
|
2108
|
-
config,
|
|
2109
|
-
dryRun
|
|
2110
|
-
});
|
|
2111
|
-
if (dynamicOtp && !sessionOtp) {
|
|
2112
|
-
sessionOtp = dynamicOtp;
|
|
2113
|
-
logger.debug("OTP stored for session");
|
|
2114
|
-
}
|
|
2115
|
-
return;
|
|
2116
|
-
} catch (error) {
|
|
2117
|
-
if (isOtpError(error) && attempt < maxAttempts - 1) {
|
|
2118
|
-
dynamicOtp = await handleOtpError();
|
|
2119
|
-
} else {
|
|
2120
|
-
logger.error(`Failed to publish ${packageNameAndVersion}:`, error);
|
|
2121
|
-
throw error;
|
|
2122
|
-
}
|
|
2123
|
-
} finally {
|
|
2124
|
-
process.chdir(config.cwd);
|
|
2125
|
-
}
|
|
2126
|
-
}
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
function readPackageJson(packagePath) {
|
|
2130
|
-
const packageJsonPath = join(packagePath, "package.json");
|
|
2131
|
-
if (!existsSync(packageJsonPath))
|
|
2132
|
-
throw new Error(`package.json not found at ${packageJsonPath}`);
|
|
2133
|
-
if (!statSync(packagePath).isDirectory())
|
|
2134
|
-
throw new Error(`Not a directory: ${packagePath}`);
|
|
2135
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
2136
|
-
if (!packageJson.name || !packageJson.version) {
|
|
2137
|
-
throw new Error(`Invalid package.json at ${packagePath}`);
|
|
2138
|
-
}
|
|
2139
|
-
return {
|
|
2140
|
-
name: packageJson.name,
|
|
2141
|
-
version: packageJson.version,
|
|
2142
|
-
private: packageJson.private || false,
|
|
2143
|
-
path: packagePath
|
|
2144
|
-
};
|
|
2248
|
+
packageName: pkg.name
|
|
2249
|
+
});
|
|
2250
|
+
logger.debug(`[${versionMode}](${step}) Using tags: ${from} \u2192 ${to}`);
|
|
2251
|
+
return { from, to };
|
|
2145
2252
|
}
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
from,
|
|
2150
|
-
to,
|
|
2151
|
-
suffix,
|
|
2152
|
-
changelog
|
|
2153
|
-
}) {
|
|
2253
|
+
|
|
2254
|
+
let sessionOtp;
|
|
2255
|
+
function detectPackageManager(cwd = process.cwd()) {
|
|
2154
2256
|
try {
|
|
2155
|
-
const
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
types: config.types,
|
|
2171
|
-
force
|
|
2172
|
-
});
|
|
2173
|
-
if (!releaseType) {
|
|
2174
|
-
logger.fail("No commits require a version bump");
|
|
2175
|
-
process.exit(1);
|
|
2257
|
+
const packageJsonPath = join(cwd, "package.json");
|
|
2258
|
+
if (existsSync(packageJsonPath)) {
|
|
2259
|
+
try {
|
|
2260
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
2261
|
+
const pmField = packageJson.packageManager;
|
|
2262
|
+
if (typeof pmField === "string") {
|
|
2263
|
+
const pmName = pmField.split("@")[0];
|
|
2264
|
+
if (["npm", "pnpm", "yarn", "bun"].includes(pmName)) {
|
|
2265
|
+
logger.debug(`Detected package manager from package.json: ${pmName}`);
|
|
2266
|
+
return pmName;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
} catch (e) {
|
|
2270
|
+
const errorString = e instanceof Error ? e.message : String(e);
|
|
2271
|
+
logger.debug(`Failed to parse package.json: ${errorString}`);
|
|
2176
2272
|
}
|
|
2177
|
-
newVersion = getPackageNewVersion({
|
|
2178
|
-
currentVersion: packageJson.version,
|
|
2179
|
-
releaseType,
|
|
2180
|
-
preid: config.bump.preid,
|
|
2181
|
-
suffix
|
|
2182
|
-
});
|
|
2183
2273
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
newVersion
|
|
2274
|
+
const lockFiles = {
|
|
2275
|
+
pnpm: "pnpm-lock.yaml",
|
|
2276
|
+
yarn: "yarn.lock",
|
|
2277
|
+
npm: "package-lock.json",
|
|
2278
|
+
bun: "bun.lockb"
|
|
2190
2279
|
};
|
|
2280
|
+
for (const [manager, file] of Object.entries(lockFiles)) {
|
|
2281
|
+
if (existsSync(join(cwd, file))) {
|
|
2282
|
+
logger.debug(`Detected package manager from lockfile: ${manager}`);
|
|
2283
|
+
return manager;
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
const ua = process.env.npm_config_user_agent;
|
|
2287
|
+
if (ua) {
|
|
2288
|
+
const match = /(pnpm|yarn|npm|bun)/.exec(ua);
|
|
2289
|
+
if (match) {
|
|
2290
|
+
logger.debug(`Detected package manager from user agent: ${match[1]}`);
|
|
2291
|
+
return match[1];
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
logger.debug("No package manager detected, defaulting to npm");
|
|
2295
|
+
return "npm";
|
|
2191
2296
|
} catch (error) {
|
|
2192
|
-
|
|
2193
|
-
|
|
2297
|
+
logger.fail(`Error detecting package manager: ${error}, defaulting to npm`);
|
|
2298
|
+
return "npm";
|
|
2194
2299
|
}
|
|
2195
2300
|
}
|
|
2196
|
-
function
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
continue;
|
|
2218
|
-
const packageBase = readPackageJson(matchPath);
|
|
2219
|
-
if (!packageBase || packageBase.private || ignorePackageNames?.includes(packageBase.name))
|
|
2220
|
-
continue;
|
|
2221
|
-
foundPaths.add(matchPath);
|
|
2222
|
-
packages.push({
|
|
2223
|
-
...packageBase,
|
|
2224
|
-
path: matchPath
|
|
2225
|
-
});
|
|
2226
|
-
}
|
|
2227
|
-
} catch (error) {
|
|
2228
|
-
logger.error(error);
|
|
2301
|
+
function determinePublishTag(version, configTag) {
|
|
2302
|
+
let tag = "latest";
|
|
2303
|
+
if (configTag) {
|
|
2304
|
+
tag = configTag;
|
|
2305
|
+
}
|
|
2306
|
+
if (isPrerelease(version) && !configTag) {
|
|
2307
|
+
logger.warn('You are about to publish a "prerelease" version with the "latest" tag. To avoid mistake, the tag is set to "next"');
|
|
2308
|
+
tag = "next";
|
|
2309
|
+
}
|
|
2310
|
+
if (isPrerelease(version) && configTag === "latest") {
|
|
2311
|
+
logger.warn('Please note, you are about to publish a "prerelease" version with the "latest" tag.');
|
|
2312
|
+
}
|
|
2313
|
+
return tag;
|
|
2314
|
+
}
|
|
2315
|
+
function getPackagesToPublishInSelectiveMode(sortedPackages, rootVersion) {
|
|
2316
|
+
const packagesToPublish = [];
|
|
2317
|
+
for (const pkg of sortedPackages) {
|
|
2318
|
+
const pkgJsonPath = join(pkg.path, "package.json");
|
|
2319
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
2320
|
+
if (pkgJson.version === rootVersion) {
|
|
2321
|
+
packagesToPublish.push(pkg);
|
|
2229
2322
|
}
|
|
2230
2323
|
}
|
|
2231
|
-
return
|
|
2324
|
+
return packagesToPublish;
|
|
2232
2325
|
}
|
|
2233
|
-
function
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
currentVersion: pkg.version,
|
|
2242
|
-
commits: pkg.commits,
|
|
2243
|
-
releaseType,
|
|
2244
|
-
preid: config.bump.preid,
|
|
2245
|
-
types: config.types,
|
|
2246
|
-
force
|
|
2326
|
+
async function getPackagesToPublishInIndependentMode(sortedPackages, config) {
|
|
2327
|
+
const packagesToPublish = [];
|
|
2328
|
+
for (const pkg of sortedPackages) {
|
|
2329
|
+
const { from, to } = await resolveTags({
|
|
2330
|
+
config,
|
|
2331
|
+
step: "publish",
|
|
2332
|
+
pkg,
|
|
2333
|
+
newVersion: pkg.newVersion || pkg.version
|
|
2247
2334
|
});
|
|
2335
|
+
if (pkg.commits.length > 0) {
|
|
2336
|
+
packagesToPublish.push(pkg);
|
|
2337
|
+
logger.debug(`${pkg.name}: ${pkg.commits.length} commit(s) since ${from} \u2192 ${to}`);
|
|
2338
|
+
}
|
|
2248
2339
|
}
|
|
2249
|
-
|
|
2250
|
-
if (isStableReleaseType(releaseType))
|
|
2251
|
-
return "patch";
|
|
2252
|
-
if (isPrerelease(pkg.version))
|
|
2253
|
-
return "prerelease";
|
|
2254
|
-
return "prepatch";
|
|
2255
|
-
}
|
|
2256
|
-
return determineReleaseType({
|
|
2257
|
-
currentVersion: pkg.version,
|
|
2258
|
-
commits: pkg.commits,
|
|
2259
|
-
releaseType,
|
|
2260
|
-
preid: config.bump.preid,
|
|
2261
|
-
types: config.types,
|
|
2262
|
-
force
|
|
2263
|
-
});
|
|
2340
|
+
return packagesToPublish;
|
|
2264
2341
|
}
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
const
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
continue;
|
|
2292
|
-
const packageBase = readPackageJson(matchPath);
|
|
2293
|
-
if (packageBase.private) {
|
|
2294
|
-
logger.debug(`${packageBase.name} is private and will be ignored`);
|
|
2295
|
-
continue;
|
|
2296
|
-
}
|
|
2297
|
-
if (config.monorepo?.ignorePackageNames?.includes(packageBase.name)) {
|
|
2298
|
-
logger.debug(`${packageBase.name} ignored by config (monorepo.ignorePackageNames)`);
|
|
2299
|
-
continue;
|
|
2300
|
-
}
|
|
2301
|
-
if (!packageBase.version) {
|
|
2302
|
-
logger.warn(`${packageBase.name} has no version and will be ignored`);
|
|
2303
|
-
continue;
|
|
2304
|
-
}
|
|
2305
|
-
const { from, to } = await resolveTags({
|
|
2306
|
-
config,
|
|
2307
|
-
step: "bump",
|
|
2308
|
-
pkg: packageBase,
|
|
2309
|
-
newVersion: void 0
|
|
2310
|
-
});
|
|
2311
|
-
const commits = await getPackageCommits({
|
|
2312
|
-
pkg: packageBase,
|
|
2313
|
-
from,
|
|
2314
|
-
to,
|
|
2315
|
-
config,
|
|
2316
|
-
changelog: false
|
|
2317
|
-
});
|
|
2318
|
-
foundPaths.add(matchPath);
|
|
2319
|
-
const dependencies = getPackageDependencies({
|
|
2320
|
-
packagePath: matchPath,
|
|
2321
|
-
allPackageNames: new Set(readedPackages.map((p) => p.name)),
|
|
2322
|
-
dependencyTypes: config.bump?.dependencyTypes
|
|
2323
|
-
});
|
|
2324
|
-
packages.set(packageBase.name, {
|
|
2325
|
-
...packageBase,
|
|
2326
|
-
path: matchPath,
|
|
2327
|
-
fromTag: from,
|
|
2328
|
-
dependencies,
|
|
2329
|
-
commits,
|
|
2330
|
-
reason: commits.length > 0 ? "commits" : void 0,
|
|
2331
|
-
dependencyChain: void 0,
|
|
2332
|
-
newVersion: void 0
|
|
2333
|
-
});
|
|
2342
|
+
function isYarnBerry() {
|
|
2343
|
+
return existsSync(path.join(process.cwd(), ".yarnrc.yml"));
|
|
2344
|
+
}
|
|
2345
|
+
function getCommandArgs({
|
|
2346
|
+
packageManager,
|
|
2347
|
+
tag,
|
|
2348
|
+
config,
|
|
2349
|
+
otp,
|
|
2350
|
+
type
|
|
2351
|
+
}) {
|
|
2352
|
+
const args = type === "publish" ? ["publish", "--tag", tag] : ["whoami"];
|
|
2353
|
+
const registry = config.publish.registry;
|
|
2354
|
+
if (registry) {
|
|
2355
|
+
args.push("--registry", registry);
|
|
2356
|
+
}
|
|
2357
|
+
const isPnpmOrNpm = packageManager === "pnpm" || packageManager === "npm";
|
|
2358
|
+
const publishToken = config.publish.token;
|
|
2359
|
+
if (publishToken) {
|
|
2360
|
+
if (!registry) {
|
|
2361
|
+
logger.warn("Publish token provided but no registry specified");
|
|
2362
|
+
} else if (!isPnpmOrNpm) {
|
|
2363
|
+
logger.warn("Publish token only supported for pnpm and npm");
|
|
2364
|
+
} else {
|
|
2365
|
+
const registryUrl = new URL(registry);
|
|
2366
|
+
const authTokenKey = `--//${registryUrl.host}${registryUrl.pathname}:_authToken=${publishToken}`;
|
|
2367
|
+
args.push(authTokenKey);
|
|
2334
2368
|
}
|
|
2335
2369
|
}
|
|
2336
|
-
const
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
allPackages: packagesArray,
|
|
2340
|
-
packagesWithCommits
|
|
2341
|
-
});
|
|
2342
|
-
for (const pkg of expandedPackages) {
|
|
2343
|
-
packages.set(pkg.name, pkg);
|
|
2370
|
+
const finalOtp = otp ?? sessionOtp ?? config.publish.otp;
|
|
2371
|
+
if (finalOtp) {
|
|
2372
|
+
args.push("--otp", finalOtp);
|
|
2344
2373
|
}
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
pkg,
|
|
2348
|
-
config,
|
|
2349
|
-
force
|
|
2350
|
-
});
|
|
2351
|
-
const newVersion = releaseType ? getPackageNewVersion({
|
|
2352
|
-
currentVersion: pkg.version,
|
|
2353
|
-
releaseType,
|
|
2354
|
-
preid: config.bump.preid,
|
|
2355
|
-
suffix
|
|
2356
|
-
}) : void 0;
|
|
2357
|
-
const graduating = releaseType && isGraduating(pkg.version, releaseType) || isChangedPreid(pkg.version, config.bump.preid);
|
|
2358
|
-
packages.set(pkg.name, {
|
|
2359
|
-
...pkg,
|
|
2360
|
-
newVersion,
|
|
2361
|
-
reason: pkg.reason || releaseType && graduating && "graduation" || void 0
|
|
2362
|
-
});
|
|
2374
|
+
if (type === "auth") {
|
|
2375
|
+
return args;
|
|
2363
2376
|
}
|
|
2364
|
-
const
|
|
2365
|
-
if (
|
|
2366
|
-
|
|
2367
|
-
return [];
|
|
2377
|
+
const access = config.publish.access;
|
|
2378
|
+
if (access) {
|
|
2379
|
+
args.push("--access", access);
|
|
2368
2380
|
}
|
|
2369
|
-
|
|
2381
|
+
if (packageManager === "pnpm") {
|
|
2382
|
+
args.push("--no-git-checks");
|
|
2383
|
+
} else if (packageManager === "yarn") {
|
|
2384
|
+
args.push("--non-interactive");
|
|
2385
|
+
if (isYarnBerry())
|
|
2386
|
+
args.push("--no-git-checks");
|
|
2387
|
+
} else if (packageManager === "npm") {
|
|
2388
|
+
args.push("--yes");
|
|
2389
|
+
}
|
|
2390
|
+
return args;
|
|
2370
2391
|
}
|
|
2371
|
-
function
|
|
2372
|
-
|
|
2373
|
-
type,
|
|
2374
|
-
changelog
|
|
2375
|
-
}) {
|
|
2376
|
-
if (commit.type === "chore" && ["deps", "release"].includes(commit.scope) && !commit.isBreaking) {
|
|
2392
|
+
function isOtpError(error) {
|
|
2393
|
+
if (typeof error !== "object" || error === null)
|
|
2377
2394
|
return false;
|
|
2395
|
+
const errorMessage = "message" in error && typeof error.message === "string" ? error.message.toLowerCase() : "";
|
|
2396
|
+
return errorMessage.includes("otp") || errorMessage.includes("one-time password") || errorMessage.includes("eotp");
|
|
2397
|
+
}
|
|
2398
|
+
function promptOtpWithTimeout(timeout = 9e4) {
|
|
2399
|
+
return new Promise((resolve, reject) => {
|
|
2400
|
+
const timer = setTimeout(() => {
|
|
2401
|
+
reject(new Error("OTP input timeout"));
|
|
2402
|
+
}, timeout);
|
|
2403
|
+
input({
|
|
2404
|
+
message: "This operation requires a one-time password (OTP). Please enter your OTP:"
|
|
2405
|
+
}).then((otp) => {
|
|
2406
|
+
clearTimeout(timer);
|
|
2407
|
+
resolve(otp);
|
|
2408
|
+
}).catch((error) => {
|
|
2409
|
+
clearTimeout(timer);
|
|
2410
|
+
reject(error);
|
|
2411
|
+
});
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
async function handleOtpError() {
|
|
2415
|
+
if (isInCI()) {
|
|
2416
|
+
logger.error("OTP required but running in CI environment. Please provide OTP via config or `--otp` flag");
|
|
2417
|
+
throw new Error("OTP required in CI environment");
|
|
2378
2418
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
return
|
|
2419
|
+
logger.warn("Publish failed: OTP required");
|
|
2420
|
+
try {
|
|
2421
|
+
const otp = await promptOtpWithTimeout();
|
|
2422
|
+
logger.debug("OTP received, retrying publish...");
|
|
2423
|
+
return otp;
|
|
2424
|
+
} catch (promptError) {
|
|
2425
|
+
logger.error("Failed to get OTP:", promptError);
|
|
2426
|
+
throw promptError;
|
|
2384
2427
|
}
|
|
2385
|
-
return false;
|
|
2386
2428
|
}
|
|
2387
|
-
async function
|
|
2429
|
+
async function executePublishCommand({
|
|
2430
|
+
command,
|
|
2431
|
+
packageNameAndVersion,
|
|
2388
2432
|
pkg,
|
|
2389
|
-
from,
|
|
2390
|
-
to,
|
|
2391
2433
|
config,
|
|
2392
|
-
|
|
2434
|
+
tag,
|
|
2435
|
+
dryRun
|
|
2393
2436
|
}) {
|
|
2394
|
-
logger.
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
const commits = allCommits.filter((commit) => {
|
|
2406
|
-
const type = changelogConfig?.types[commit.type];
|
|
2407
|
-
if (!isAllowedCommit({ commit, type, changelog })) {
|
|
2408
|
-
return false;
|
|
2409
|
-
}
|
|
2410
|
-
if (pkg.path === changelogConfig.cwd || pkg.name === rootPackage.name) {
|
|
2411
|
-
return true;
|
|
2437
|
+
logger.info(`${dryRun ? "[dry-run] " : ""}Publishing ${packageNameAndVersion} with tag "${tag}"`);
|
|
2438
|
+
if (!dryRun) {
|
|
2439
|
+
const { stdout } = await execPromise(command, {
|
|
2440
|
+
noStderr: true,
|
|
2441
|
+
noStdout: true,
|
|
2442
|
+
noSuccess: true,
|
|
2443
|
+
logLevel: config.logLevel,
|
|
2444
|
+
cwd: pkg.path
|
|
2445
|
+
});
|
|
2446
|
+
if (stdout) {
|
|
2447
|
+
logger.debug(stdout);
|
|
2412
2448
|
}
|
|
2413
|
-
const packageRelativePath = relative(changelogConfig.cwd, pkg.path);
|
|
2414
|
-
const scopeMatches = commit.scope === pkg.name;
|
|
2415
|
-
const bodyContainsPath = commit.body.includes(packageRelativePath);
|
|
2416
|
-
return scopeMatches || bodyContainsPath;
|
|
2417
|
-
});
|
|
2418
|
-
logger.debug(`Found ${commits.length} commit(s) for ${pkg.name} from ${from} to ${to}`);
|
|
2419
|
-
if (commits.length > 0) {
|
|
2420
|
-
logger.debug(`${pkg.name}: ${commits.length} commit(s) found`);
|
|
2421
|
-
} else {
|
|
2422
|
-
logger.debug(`${pkg.name}: No commits found`);
|
|
2423
2449
|
}
|
|
2424
|
-
|
|
2450
|
+
logger.info(`${dryRun ? "[dry-run] " : ""}Published ${packageNameAndVersion}`);
|
|
2425
2451
|
}
|
|
2426
|
-
function
|
|
2427
|
-
|
|
2428
|
-
|
|
2452
|
+
function getAuthCommand({
|
|
2453
|
+
packageManager,
|
|
2454
|
+
config,
|
|
2455
|
+
otp
|
|
2456
|
+
}) {
|
|
2457
|
+
const args = getCommandArgs({
|
|
2458
|
+
packageManager,
|
|
2459
|
+
tag: void 0,
|
|
2460
|
+
config,
|
|
2461
|
+
otp,
|
|
2462
|
+
type: "auth"
|
|
2463
|
+
});
|
|
2464
|
+
return `${packageManager} ${args.join(" ")}`;
|
|
2465
|
+
}
|
|
2466
|
+
function getPublishCommand({
|
|
2467
|
+
packageManager,
|
|
2468
|
+
tag,
|
|
2469
|
+
config,
|
|
2470
|
+
otp
|
|
2471
|
+
}) {
|
|
2472
|
+
const args = getCommandArgs({
|
|
2473
|
+
packageManager,
|
|
2474
|
+
tag,
|
|
2475
|
+
config,
|
|
2476
|
+
otp,
|
|
2477
|
+
type: "publish"
|
|
2478
|
+
});
|
|
2479
|
+
const baseCommand = packageManager === "yarn" && isYarnBerry() ? "yarn npm" : packageManager;
|
|
2480
|
+
return `${baseCommand} ${args.join(" ")}`;
|
|
2481
|
+
}
|
|
2482
|
+
async function publishPackage({
|
|
2483
|
+
pkg,
|
|
2484
|
+
config,
|
|
2485
|
+
packageManager,
|
|
2486
|
+
dryRun
|
|
2487
|
+
}) {
|
|
2488
|
+
const tag = determinePublishTag(pkg.newVersion || pkg.version, config.publish.tag);
|
|
2489
|
+
const packageNameAndVersion = getIndependentTag({ name: pkg.name, version: pkg.newVersion || pkg.version });
|
|
2490
|
+
logger.debug(`Building publish command for ${pkg.name}`);
|
|
2491
|
+
let dynamicOtp;
|
|
2492
|
+
const maxAttempts = 2;
|
|
2493
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
2494
|
+
try {
|
|
2495
|
+
const command = getPublishCommand({
|
|
2496
|
+
packageManager,
|
|
2497
|
+
tag,
|
|
2498
|
+
config,
|
|
2499
|
+
otp: dynamicOtp
|
|
2500
|
+
});
|
|
2501
|
+
process.chdir(pkg.path);
|
|
2502
|
+
await executePublishCommand({
|
|
2503
|
+
command,
|
|
2504
|
+
packageNameAndVersion,
|
|
2505
|
+
pkg,
|
|
2506
|
+
config,
|
|
2507
|
+
dryRun,
|
|
2508
|
+
tag
|
|
2509
|
+
});
|
|
2510
|
+
if (dynamicOtp && !sessionOtp) {
|
|
2511
|
+
sessionOtp = dynamicOtp;
|
|
2512
|
+
logger.debug("OTP stored for session");
|
|
2513
|
+
}
|
|
2514
|
+
return;
|
|
2515
|
+
} catch (error) {
|
|
2516
|
+
if (isOtpError(error) && attempt < maxAttempts - 1) {
|
|
2517
|
+
dynamicOtp = await handleOtpError();
|
|
2518
|
+
} else {
|
|
2519
|
+
logger.error(`Failed to publish ${packageNameAndVersion}:`, error);
|
|
2520
|
+
throw error;
|
|
2521
|
+
}
|
|
2522
|
+
} finally {
|
|
2523
|
+
process.chdir(config.cwd);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2429
2526
|
}
|
|
2430
2527
|
|
|
2431
2528
|
async function bumpUnifiedMode({
|
|
@@ -2436,6 +2533,9 @@ async function bumpUnifiedMode({
|
|
|
2436
2533
|
}) {
|
|
2437
2534
|
logger.debug("Starting bump in unified mode");
|
|
2438
2535
|
const rootPackageBase = readPackageJson(config.cwd);
|
|
2536
|
+
if (!rootPackageBase) {
|
|
2537
|
+
throw new Error("Failed to read root package.json");
|
|
2538
|
+
}
|
|
2439
2539
|
const { from, to } = await resolveTags({
|
|
2440
2540
|
config,
|
|
2441
2541
|
step: "bump",
|
|
@@ -2515,6 +2615,9 @@ async function bumpSelectiveMode({
|
|
|
2515
2615
|
}) {
|
|
2516
2616
|
logger.debug("Starting bump in selective mode");
|
|
2517
2617
|
const rootPackageBase = readPackageJson(config.cwd);
|
|
2618
|
+
if (!rootPackageBase) {
|
|
2619
|
+
throw new Error("Failed to read root package.json");
|
|
2620
|
+
}
|
|
2518
2621
|
const { from, to } = await resolveTags({
|
|
2519
2622
|
config,
|
|
2520
2623
|
step: "bump",
|
|
@@ -2717,22 +2820,6 @@ async function bump(options = {}) {
|
|
|
2717
2820
|
}
|
|
2718
2821
|
}
|
|
2719
2822
|
|
|
2720
|
-
async function getPackagesToGenerateChangelogFor({
|
|
2721
|
-
config,
|
|
2722
|
-
bumpResult,
|
|
2723
|
-
suffix,
|
|
2724
|
-
force
|
|
2725
|
-
}) {
|
|
2726
|
-
if (bumpResult?.bumpedPackages && bumpResult.bumpedPackages.length > 0) {
|
|
2727
|
-
return bumpResult.bumpedPackages;
|
|
2728
|
-
}
|
|
2729
|
-
return await getPackages({
|
|
2730
|
-
config,
|
|
2731
|
-
patterns: config.monorepo?.packages,
|
|
2732
|
-
suffix,
|
|
2733
|
-
force
|
|
2734
|
-
});
|
|
2735
|
-
}
|
|
2736
2823
|
async function generateIndependentRootChangelog({
|
|
2737
2824
|
packages,
|
|
2738
2825
|
config,
|
|
@@ -2764,10 +2851,13 @@ async function generateIndependentRootChangelog({
|
|
|
2764
2851
|
|
|
2765
2852
|
${packageChangelogs.join("\n\n")}`;
|
|
2766
2853
|
logger.verbose(`Aggregated root changelog: ${aggregatedChangelog}`);
|
|
2767
|
-
const
|
|
2854
|
+
const rootPackageRead = readPackageJson(config.cwd);
|
|
2855
|
+
if (!rootPackageRead) {
|
|
2856
|
+
throw new Error("Failed to read root package.json");
|
|
2857
|
+
}
|
|
2768
2858
|
writeChangelogToFile({
|
|
2769
2859
|
cwd: config.cwd,
|
|
2770
|
-
pkg:
|
|
2860
|
+
pkg: rootPackageRead,
|
|
2771
2861
|
changelog: aggregatedChangelog,
|
|
2772
2862
|
dryRun
|
|
2773
2863
|
});
|
|
@@ -2786,10 +2876,14 @@ async function generateSimpleRootChangelog({
|
|
|
2786
2876
|
}
|
|
2787
2877
|
logger.debug("Generating simple root changelog");
|
|
2788
2878
|
const rootPackageRead = readPackageJson(config.cwd);
|
|
2879
|
+
if (!rootPackageRead) {
|
|
2880
|
+
throw new Error("Failed to read root package.json");
|
|
2881
|
+
}
|
|
2882
|
+
const newVersion = bumpResult?.newVersion || rootPackageRead.version;
|
|
2789
2883
|
const { from, to } = await resolveTags({
|
|
2790
2884
|
config,
|
|
2791
2885
|
step: "changelog",
|
|
2792
|
-
newVersion
|
|
2886
|
+
newVersion,
|
|
2793
2887
|
pkg: rootPackageRead
|
|
2794
2888
|
});
|
|
2795
2889
|
const fromTag = bumpResult?.fromTag || from;
|
|
@@ -2802,7 +2896,6 @@ async function generateSimpleRootChangelog({
|
|
|
2802
2896
|
to
|
|
2803
2897
|
});
|
|
2804
2898
|
logger.debug(`Generating ${rootPackage.name} changelog (${fromTag}...${to})`);
|
|
2805
|
-
const newVersion = bumpResult?.newVersion || rootPackage.version;
|
|
2806
2899
|
const rootChangelog = await generateChangelog({
|
|
2807
2900
|
pkg: rootPackage,
|
|
2808
2901
|
config,
|
|
@@ -2843,7 +2936,7 @@ async function changelog(options = {}) {
|
|
|
2843
2936
|
logger.start("Start generating changelogs");
|
|
2844
2937
|
if (config.changelog?.rootChangelog && config.monorepo) {
|
|
2845
2938
|
if (config.monorepo.versionMode === "independent") {
|
|
2846
|
-
const packages2 = await
|
|
2939
|
+
const packages2 = await getPackagesOrBumpedPackages({
|
|
2847
2940
|
config,
|
|
2848
2941
|
bumpResult: options.bumpResult,
|
|
2849
2942
|
suffix: options.suffix,
|
|
@@ -2867,27 +2960,28 @@ async function changelog(options = {}) {
|
|
|
2867
2960
|
logger.debug("Skipping root changelog generation");
|
|
2868
2961
|
}
|
|
2869
2962
|
logger.debug("Generating package changelogs...");
|
|
2870
|
-
const packages =
|
|
2963
|
+
const packages = await getPackagesOrBumpedPackages({
|
|
2871
2964
|
config,
|
|
2872
|
-
|
|
2965
|
+
bumpResult: options.bumpResult,
|
|
2873
2966
|
suffix: options.suffix,
|
|
2874
2967
|
force: options.force ?? false
|
|
2875
2968
|
});
|
|
2876
2969
|
logger.debug(`Processing ${packages.length} package(s)`);
|
|
2877
2970
|
let generatedCount = 0;
|
|
2878
2971
|
for await (const pkg of packages) {
|
|
2972
|
+
const newVersion = options.bumpResult?.bumpedPackages?.find((p) => p.name === pkg.name)?.newVersion || pkg.newVersion || pkg.version;
|
|
2879
2973
|
const { from, to } = await resolveTags({
|
|
2880
2974
|
config,
|
|
2881
2975
|
step: "changelog",
|
|
2882
2976
|
pkg,
|
|
2883
|
-
newVersion
|
|
2977
|
+
newVersion
|
|
2884
2978
|
});
|
|
2885
2979
|
logger.debug(`Processing ${pkg.name} (${from}...${to})`);
|
|
2886
2980
|
const changelog2 = await generateChangelog({
|
|
2887
2981
|
pkg,
|
|
2888
2982
|
config,
|
|
2889
2983
|
dryRun,
|
|
2890
|
-
newVersion
|
|
2984
|
+
newVersion
|
|
2891
2985
|
});
|
|
2892
2986
|
if (changelog2) {
|
|
2893
2987
|
writeChangelogToFile({
|
|
@@ -2927,11 +3021,11 @@ function providerReleaseSafetyCheck({ config, provider }) {
|
|
|
2927
3021
|
} else if (internalProvider === "gitlab") {
|
|
2928
3022
|
token = config.tokens?.gitlab || config.repo?.token;
|
|
2929
3023
|
} else {
|
|
2930
|
-
logger.error(`Unsupported Git provider: ${internalProvider || "unknown"}`);
|
|
3024
|
+
logger.error(`[provider-release-safety-check] Unsupported Git provider: ${internalProvider || "unknown"}`);
|
|
2931
3025
|
process.exit(1);
|
|
2932
3026
|
}
|
|
2933
3027
|
if (!token) {
|
|
2934
|
-
logger.error(`No token provided for ${internalProvider || "unknown"} - The release will not be published - Please refer to the documentation: https://louismazel.github.io/relizy/guide/installation#environment-setup`);
|
|
3028
|
+
logger.error(`[provider-release-safety-check] No token provided for ${internalProvider || "unknown"} - The release will not be published - Please refer to the documentation: https://louismazel.github.io/relizy/guide/installation#environment-setup`);
|
|
2935
3029
|
process.exit(1);
|
|
2936
3030
|
}
|
|
2937
3031
|
}
|
|
@@ -2998,6 +3092,40 @@ async function providerRelease(options = {}) {
|
|
|
2998
3092
|
}
|
|
2999
3093
|
}
|
|
3000
3094
|
|
|
3095
|
+
async function publishSafetyCheck({ config }) {
|
|
3096
|
+
logger.debug("[publish-safety-check] Running publish safety check");
|
|
3097
|
+
if (!config.safetyCheck || !config.release.publish || !config.publish.safetyCheck) {
|
|
3098
|
+
logger.debug("[publish-safety-check] Safety check disabled or publish disabled");
|
|
3099
|
+
return;
|
|
3100
|
+
}
|
|
3101
|
+
const packageManager = config.publish.packageManager || detectPackageManager(config.cwd);
|
|
3102
|
+
if (!packageManager) {
|
|
3103
|
+
logger.error("[publish-safety-check] Unable to detect package manager");
|
|
3104
|
+
process.exit(1);
|
|
3105
|
+
}
|
|
3106
|
+
const isPnpmOrNpm = packageManager === "pnpm" || packageManager === "npm";
|
|
3107
|
+
if (isPnpmOrNpm) {
|
|
3108
|
+
const authCommand = getAuthCommand({
|
|
3109
|
+
packageManager,
|
|
3110
|
+
config,
|
|
3111
|
+
otp: config.publish.otp
|
|
3112
|
+
});
|
|
3113
|
+
try {
|
|
3114
|
+
logger.debug("[publish-safety-check] Authenticating to package registry...");
|
|
3115
|
+
await execPromise(authCommand, {
|
|
3116
|
+
cwd: config.cwd,
|
|
3117
|
+
noStderr: true,
|
|
3118
|
+
noStdout: true,
|
|
3119
|
+
logLevel: config.logLevel,
|
|
3120
|
+
noSuccess: true
|
|
3121
|
+
});
|
|
3122
|
+
logger.info("[publish-safety-check] Successfully authenticated to package registry");
|
|
3123
|
+
} catch (error) {
|
|
3124
|
+
logger.error("[publish-safety-check] Failed to authenticate to package registry:", error);
|
|
3125
|
+
process.exit(1);
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3001
3129
|
async function publish(options = {}) {
|
|
3002
3130
|
const config = await loadRelizyConfig({
|
|
3003
3131
|
configName: options.configName,
|
|
@@ -3008,14 +3136,16 @@ async function publish(options = {}) {
|
|
|
3008
3136
|
otp: options.otp,
|
|
3009
3137
|
registry: options.registry,
|
|
3010
3138
|
tag: options.tag,
|
|
3011
|
-
buildCmd: options.buildCmd
|
|
3139
|
+
buildCmd: options.buildCmd,
|
|
3140
|
+
token: options.token
|
|
3012
3141
|
},
|
|
3013
|
-
logLevel: options.logLevel
|
|
3142
|
+
logLevel: options.logLevel,
|
|
3143
|
+
safetyCheck: options.safetyCheck
|
|
3014
3144
|
}
|
|
3015
3145
|
});
|
|
3016
3146
|
const dryRun = options.dryRun ?? false;
|
|
3017
3147
|
logger.debug(`Dry run: ${dryRun}`);
|
|
3018
|
-
const packageManager = detectPackageManager(
|
|
3148
|
+
const packageManager = config.publish.packageManager || detectPackageManager(config.cwd);
|
|
3019
3149
|
logger.debug(`Package manager: ${packageManager}`);
|
|
3020
3150
|
logger.info(`Version mode: ${config.monorepo?.versionMode || "standalone"}`);
|
|
3021
3151
|
if (config.publish.registry) {
|
|
@@ -3026,11 +3156,15 @@ async function publish(options = {}) {
|
|
|
3026
3156
|
}
|
|
3027
3157
|
try {
|
|
3028
3158
|
await executeHook("before:publish", config, dryRun);
|
|
3159
|
+
await publishSafetyCheck({ config });
|
|
3029
3160
|
const rootPackage = readPackageJson(config.cwd);
|
|
3161
|
+
if (!rootPackage) {
|
|
3162
|
+
throw new Error("Failed to read root package.json");
|
|
3163
|
+
}
|
|
3030
3164
|
logger.start("Start publishing packages");
|
|
3031
|
-
const packages =
|
|
3165
|
+
const packages = await getPackagesOrBumpedPackages({
|
|
3032
3166
|
config,
|
|
3033
|
-
|
|
3167
|
+
bumpResult: options.bumpResult,
|
|
3034
3168
|
suffix: options.suffix,
|
|
3035
3169
|
force: options.force ?? false
|
|
3036
3170
|
});
|
|
@@ -3114,7 +3248,8 @@ function getReleaseConfig(options = {}) {
|
|
|
3114
3248
|
otp: options.otp,
|
|
3115
3249
|
registry: options.registry,
|
|
3116
3250
|
tag: options.tag,
|
|
3117
|
-
buildCmd: options.buildCmd
|
|
3251
|
+
buildCmd: options.buildCmd,
|
|
3252
|
+
token: options.publishToken
|
|
3118
3253
|
},
|
|
3119
3254
|
release: {
|
|
3120
3255
|
commit: options.commit,
|
|
@@ -3130,7 +3265,7 @@ function getReleaseConfig(options = {}) {
|
|
|
3130
3265
|
}
|
|
3131
3266
|
});
|
|
3132
3267
|
}
|
|
3133
|
-
function releaseSafetyCheck({
|
|
3268
|
+
async function releaseSafetyCheck({
|
|
3134
3269
|
config,
|
|
3135
3270
|
provider
|
|
3136
3271
|
}) {
|
|
@@ -3138,6 +3273,7 @@ function releaseSafetyCheck({
|
|
|
3138
3273
|
return;
|
|
3139
3274
|
}
|
|
3140
3275
|
providerReleaseSafetyCheck({ config, provider });
|
|
3276
|
+
await publishSafetyCheck({ config });
|
|
3141
3277
|
}
|
|
3142
3278
|
async function release(options = {}) {
|
|
3143
3279
|
const dryRun = options.dryRun ?? false;
|
|
@@ -3147,7 +3283,7 @@ async function release(options = {}) {
|
|
|
3147
3283
|
const config = await getReleaseConfig(options);
|
|
3148
3284
|
logger.debug(`Version mode: ${config.monorepo?.versionMode || "standalone"}`);
|
|
3149
3285
|
logger.debug(`Push: ${config.release.push}, Publish: ${config.release.publish}, Provider Release: ${config.release.providerRelease}`);
|
|
3150
|
-
releaseSafetyCheck({ config, provider: options.provider });
|
|
3286
|
+
await releaseSafetyCheck({ config, provider: options.provider });
|
|
3151
3287
|
try {
|
|
3152
3288
|
await executeHook("before:release", config, dryRun);
|
|
3153
3289
|
logger.box("Step 1/6: Bump versions");
|
|
@@ -3223,7 +3359,7 @@ async function release(options = {}) {
|
|
|
3223
3359
|
tag: config.publish.tag,
|
|
3224
3360
|
access: config.publish.access,
|
|
3225
3361
|
otp: config.publish.otp,
|
|
3226
|
-
|
|
3362
|
+
bumpResult,
|
|
3227
3363
|
dryRun,
|
|
3228
3364
|
config,
|
|
3229
3365
|
configName: options.configName,
|
|
@@ -3261,10 +3397,10 @@ async function release(options = {}) {
|
|
|
3261
3397
|
logger.info("Skipping release (--no-provider-release)");
|
|
3262
3398
|
}
|
|
3263
3399
|
const publishedPackageCount = publishResponse?.publishedPackages.length ?? 0;
|
|
3264
|
-
const versionDisplay = config.monorepo?.versionMode === "independent" ? `${bumpResult.bumpedPackages.length} packages bumped independently` : bumpResult.newVersion || readPackageJson(config.cwd)
|
|
3400
|
+
const versionDisplay = config.monorepo?.versionMode === "independent" ? `${bumpResult.bumpedPackages.length} packages bumped independently` : bumpResult.newVersion || readPackageJson(config.cwd)?.version;
|
|
3265
3401
|
logger.box(`Release workflow completed!
|
|
3266
3402
|
|
|
3267
|
-
Version: ${versionDisplay}
|
|
3403
|
+
Version: ${versionDisplay ?? "Unknown"}
|
|
3268
3404
|
Tag(s): ${createdTags.length ? createdTags.join(", ") : "No"}
|
|
3269
3405
|
Pushed: ${config.release.push ? "Yes" : "Disabled"}
|
|
3270
3406
|
Published packages: ${config.release.publish ? publishedPackageCount : "Disabled"}
|
|
@@ -3278,4 +3414,4 @@ Git provider: ${provider}`);
|
|
|
3278
3414
|
}
|
|
3279
3415
|
}
|
|
3280
3416
|
|
|
3281
|
-
export {
|
|
3417
|
+
export { getPackagesOrBumpedPackages as $, github as A, createGitlabRelease as B, gitlab as C, detectPackageManager as D, determinePublishTag as E, getPackagesToPublishInSelectiveMode as F, getPackagesToPublishInIndependentMode as G, getAuthCommand as H, publishPackage as I, readPackageJson as J, getRootPackage as K, readPackages as L, getPackages as M, getPackageCommits as N, hasLernaJson as O, getIndependentTag as P, getLastStableTag as Q, getLastTag as R, getLastRepoTag as S, getLastPackageTag as T, resolveTags as U, executeHook as V, isInCI as W, getCIName as X, executeFormatCmd as Y, executeBuildCmd as Z, isBumpedPackage as _, providerRelease as a, isGraduatingToStableBetweenVersion as a0, determineSemverChange as a1, determineReleaseType as a2, writeVersion as a3, getPackageNewVersion as a4, updateLernaVersion as a5, extractVersionFromPackageTag as a6, isPrerelease as a7, isStableReleaseType as a8, isPrereleaseReleaseType as a9, isGraduating as aa, getPreid as ab, isChangedPreid as ac, getBumpedPackageIndependently as ad, confirmBump as ae, getBumpedIndependentPackages as af, bump as b, changelog as c, publishSafetyCheck as d, publish as e, getDefaultConfig as f, generateChangelog as g, defineConfig as h, getPackageDependencies as i, getDependentsOf as j, expandPackagesToBumpWithDependents as k, loadRelizyConfig as l, getGitStatus as m, checkGitStatusIfDirty as n, fetchGitTags as o, providerReleaseSafetyCheck as p, detectGitProvider as q, release as r, parseGitRemoteUrl as s, topologicalSort as t, createCommitAndTags as u, pushCommitAndTags as v, writeChangelogToFile as w, getFirstCommit as x, getCurrentGitBranch as y, getCurrentGitRef as z };
|