relizy 0.2.5-beta.8 → 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 +45 -14
- package/dist/index.d.ts +45 -14
- package/dist/index.mjs +6 -6
- package/dist/shared/{relizy.cH6JI7VO.mjs → relizy.CU6Hj4K0.mjs} +2333 -2196
- package/package.json +23 -21
|
@@ -1,2430 +1,2528 @@
|
|
|
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");
|
|
540
|
-
}
|
|
541
|
-
newVersion = newVersion || pkg.newVersion;
|
|
542
|
-
let toTag = config.to;
|
|
543
|
-
if (!toTag && newVersion) {
|
|
544
|
-
toTag = config.monorepo?.versionMode === "independent" ? getIndependentTag({ version: newVersion, name: pkg.name }) : config.templates.tagBody.replace("{{newVersion}}", newVersion);
|
|
545
|
-
}
|
|
546
|
-
if (!toTag) {
|
|
547
|
-
throw new Error(`No tag found for ${pkg.name}`);
|
|
591
|
+
if (bumpResult?.bumpedPackages && bumpResult.bumpedPackages.length > 0) {
|
|
592
|
+
return bumpResult.bumpedPackages;
|
|
548
593
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
config
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const generatedChangelog = await generateMarkDown({
|
|
557
|
-
commits: pkg.commits,
|
|
558
|
-
config,
|
|
559
|
-
from: fromTag,
|
|
560
|
-
isFirstCommit,
|
|
561
|
-
to: toTag
|
|
562
|
-
});
|
|
563
|
-
let changelog = generatedChangelog;
|
|
564
|
-
if (pkg.commits.length === 0) {
|
|
565
|
-
changelog = `${changelog}
|
|
594
|
+
return await getPackages({
|
|
595
|
+
config,
|
|
596
|
+
patterns: config.monorepo?.packages,
|
|
597
|
+
suffix,
|
|
598
|
+
force
|
|
599
|
+
});
|
|
600
|
+
}
|
|
566
601
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
logger.
|
|
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!
|
|
578
615
|
|
|
579
|
-
|
|
616
|
+
Please commit or stash your changes before bumping or use --no-clean flag.
|
|
580
617
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
return changelog;
|
|
586
|
-
} catch (error) {
|
|
587
|
-
throw new Error(`Error generating changelog for ${pkg.name} (${fromTag}...${toTag}): ${error}`);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
function writeChangelogToFile({
|
|
591
|
-
cwd,
|
|
592
|
-
pkg,
|
|
593
|
-
changelog,
|
|
594
|
-
dryRun = false
|
|
595
|
-
}) {
|
|
596
|
-
const changelogPath = join(pkg.path, "CHANGELOG.md");
|
|
597
|
-
let existingChangelog = "";
|
|
598
|
-
if (existsSync(changelogPath)) {
|
|
599
|
-
existingChangelog = readFileSync(changelogPath, "utf8");
|
|
600
|
-
}
|
|
601
|
-
const lines = existingChangelog.split("\n");
|
|
602
|
-
const titleIndex = lines.findIndex((line) => line.startsWith("# "));
|
|
603
|
-
let updatedChangelog;
|
|
604
|
-
if (titleIndex !== -1) {
|
|
605
|
-
const beforeTitle = lines.slice(0, titleIndex + 1);
|
|
606
|
-
const afterTitle = lines.slice(titleIndex + 1);
|
|
607
|
-
updatedChangelog = [...beforeTitle, "", changelog, "", ...afterTitle].join("\n");
|
|
608
|
-
} else {
|
|
609
|
-
const title = "# Changelog\n";
|
|
610
|
-
updatedChangelog = `${title}
|
|
611
|
-
${changelog}
|
|
612
|
-
${existingChangelog}`;
|
|
613
|
-
}
|
|
614
|
-
if (dryRun) {
|
|
615
|
-
const relativeChangelogPath = relative(cwd, changelogPath);
|
|
616
|
-
logger.info(`[dry-run] ${pkg.name} - Write changelog to ${relativeChangelogPath}`);
|
|
617
|
-
} else {
|
|
618
|
-
logger.debug(`Writing changelog to ${changelogPath}`);
|
|
619
|
-
writeFileSync(changelogPath, updatedChangelog, "utf8");
|
|
620
|
-
logger.info(`Changelog updated for ${pkg.name} (${"newVersion" in pkg && pkg.newVersion || pkg.version})`);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
function getDefaultConfig() {
|
|
625
|
-
return {
|
|
626
|
-
cwd: process$1.cwd(),
|
|
627
|
-
types: {
|
|
628
|
-
feat: { title: "\u{1F680} Enhancements", semver: "minor" },
|
|
629
|
-
perf: { title: "\u{1F525} Performance", semver: "patch" },
|
|
630
|
-
fix: { title: "\u{1FA79} Fixes", semver: "patch" },
|
|
631
|
-
refactor: { title: "\u{1F485} Refactors", semver: "patch" },
|
|
632
|
-
docs: { title: "\u{1F4D6} Documentation", semver: "patch" },
|
|
633
|
-
build: { title: "\u{1F4E6} Build", semver: "patch" },
|
|
634
|
-
types: { title: "\u{1F30A} Types", semver: "patch" },
|
|
635
|
-
chore: { title: "\u{1F3E1} Chore" },
|
|
636
|
-
examples: { title: "\u{1F3C0} Examples" },
|
|
637
|
-
test: { title: "\u2705 Tests" },
|
|
638
|
-
style: { title: "\u{1F3A8} Styles" },
|
|
639
|
-
ci: { title: "\u{1F916} CI" }
|
|
640
|
-
},
|
|
641
|
-
templates: {
|
|
642
|
-
commitMessage: "chore(release): bump version to {{newVersion}}",
|
|
643
|
-
tagMessage: "Bump version to {{newVersion}}",
|
|
644
|
-
tagBody: "v{{newVersion}}",
|
|
645
|
-
emptyChangelogContent: "No relevant changes for this release"
|
|
646
|
-
},
|
|
647
|
-
excludeAuthors: [],
|
|
648
|
-
noAuthors: false,
|
|
649
|
-
bump: {
|
|
650
|
-
type: "release",
|
|
651
|
-
clean: true,
|
|
652
|
-
dependencyTypes: ["dependencies"],
|
|
653
|
-
yes: false
|
|
654
|
-
},
|
|
655
|
-
changelog: {
|
|
656
|
-
rootChangelog: true,
|
|
657
|
-
includeCommitBody: true
|
|
658
|
-
},
|
|
659
|
-
publish: {
|
|
660
|
-
private: false,
|
|
661
|
-
args: []
|
|
662
|
-
},
|
|
663
|
-
tokens: {
|
|
664
|
-
gitlab: process$1.env.RELIZY_GITLAB_TOKEN || process$1.env.GITLAB_TOKEN || process$1.env.GITLAB_API_TOKEN || process$1.env.CI_JOB_TOKEN,
|
|
665
|
-
github: process$1.env.RELIZY_GITHUB_TOKEN || process$1.env.GITHUB_TOKEN || process$1.env.GH_TOKEN
|
|
666
|
-
},
|
|
667
|
-
scopeMap: {},
|
|
668
|
-
release: {
|
|
669
|
-
commit: true,
|
|
670
|
-
publish: true,
|
|
671
|
-
changelog: true,
|
|
672
|
-
push: true,
|
|
673
|
-
clean: true,
|
|
674
|
-
providerRelease: true,
|
|
675
|
-
noVerify: false
|
|
676
|
-
},
|
|
677
|
-
logLevel: "default",
|
|
678
|
-
safetyCheck: true
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
function setupLogger(logLevel) {
|
|
682
|
-
if (logLevel) {
|
|
683
|
-
logger.setLevel(logLevel);
|
|
684
|
-
logger.debug(`Log level set to: ${logLevel}`);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
async function resolveConfig(config, cwd) {
|
|
688
|
-
if (!config.repo) {
|
|
689
|
-
const resolvedRepoConfig = await resolveRepoConfig(cwd);
|
|
690
|
-
config.repo = {
|
|
691
|
-
...resolvedRepoConfig,
|
|
692
|
-
provider: resolvedRepoConfig.provider
|
|
693
|
-
};
|
|
694
|
-
}
|
|
695
|
-
if (typeof config.repo === "string") {
|
|
696
|
-
const resolvedRepoConfig = getRepoConfig(config.repo);
|
|
697
|
-
config.repo = {
|
|
698
|
-
...resolvedRepoConfig,
|
|
699
|
-
provider: resolvedRepoConfig.provider
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
return config;
|
|
703
|
-
}
|
|
704
|
-
async function loadRelizyConfig(options) {
|
|
705
|
-
const cwd = options?.overrides?.cwd ?? process$1.cwd();
|
|
706
|
-
const configName = options?.configName ?? "relizy";
|
|
707
|
-
await setupDotenv({ cwd });
|
|
708
|
-
const defaultConfig = getDefaultConfig();
|
|
709
|
-
const overridesConfig = defu(options?.overrides, options?.baseConfig);
|
|
710
|
-
const results = await loadConfig({
|
|
711
|
-
cwd,
|
|
712
|
-
name: configName,
|
|
713
|
-
packageJson: true,
|
|
714
|
-
defaults: defaultConfig,
|
|
715
|
-
overrides: overridesConfig
|
|
716
|
-
});
|
|
717
|
-
if (!results._configFile) {
|
|
718
|
-
logger.debug(`No config file found with name "${configName}" - using standalone mode`);
|
|
719
|
-
if (options?.configName) {
|
|
720
|
-
logger.error(`No config file found with name "${configName}"`);
|
|
721
|
-
process$1.exit(1);
|
|
722
|
-
}
|
|
723
|
-
}
|
|
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;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
async function githubIndependentMode({
|
|
853
|
-
config,
|
|
854
|
-
dryRun,
|
|
855
|
-
bumpResult,
|
|
856
|
-
force,
|
|
857
|
-
suffix
|
|
858
|
-
}) {
|
|
859
|
-
const repoConfig = config.repo;
|
|
860
|
-
if (!repoConfig) {
|
|
861
|
-
throw new Error("No repository configuration found. Please check your changelog config.");
|
|
862
|
-
}
|
|
863
|
-
logger.debug(`GitHub token: ${config.tokens.github || config.repo?.token ? "\u2713 provided" : "\u2717 missing"}`);
|
|
864
|
-
if (!config.tokens.github && !config.repo?.token) {
|
|
865
|
-
throw new Error("No GitHub token specified. Set GITHUB_TOKEN or GH_TOKEN environment variable.");
|
|
866
|
-
}
|
|
867
|
-
const packages = bumpResult?.bumped && bumpResult?.bumpedPackages || await getPackages({
|
|
868
|
-
suffix,
|
|
869
|
-
patterns: config.monorepo?.packages,
|
|
870
|
-
config,
|
|
871
|
-
force
|
|
872
|
-
});
|
|
873
|
-
logger.info(`Creating ${packages.length} GitHub release(s)`);
|
|
874
|
-
const postedReleases = [];
|
|
875
|
-
for (const pkg of packages) {
|
|
876
|
-
const newVersion = isBumpedPackage(pkg) && pkg.newVersion || pkg.version;
|
|
877
|
-
const from = config.from || pkg.fromTag;
|
|
878
|
-
const to = config.to || getIndependentTag({ version: newVersion, name: pkg.name });
|
|
879
|
-
if (!from) {
|
|
880
|
-
logger.warn(`No from tag found for ${pkg.name}, skipping release`);
|
|
881
|
-
continue;
|
|
882
|
-
}
|
|
883
|
-
const toTag = dryRun ? "HEAD" : to;
|
|
884
|
-
logger.debug(`Processing ${pkg.name}: ${from} \u2192 ${toTag}`);
|
|
885
|
-
const changelog = await generateChangelog({
|
|
886
|
-
pkg,
|
|
887
|
-
config,
|
|
888
|
-
dryRun,
|
|
889
|
-
newVersion
|
|
890
|
-
});
|
|
891
|
-
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
892
|
-
const release = {
|
|
893
|
-
tag_name: to,
|
|
894
|
-
name: to,
|
|
895
|
-
body: releaseBody,
|
|
896
|
-
prerelease: isPrerelease(newVersion)
|
|
897
|
-
};
|
|
898
|
-
logger.debug(`Creating release for ${to}${release.prerelease ? " (prerelease)" : ""}`);
|
|
899
|
-
if (dryRun) {
|
|
900
|
-
logger.info(`[dry-run] Publish GitHub release for ${to}`);
|
|
901
|
-
postedReleases.push({
|
|
902
|
-
name: pkg.name,
|
|
903
|
-
tag: release.tag_name,
|
|
904
|
-
version: newVersion,
|
|
905
|
-
prerelease: release.prerelease
|
|
906
|
-
});
|
|
907
|
-
} else {
|
|
908
|
-
logger.debug(`Publishing release ${to} to GitHub...`);
|
|
909
|
-
await createGithubRelease({
|
|
910
|
-
...config,
|
|
911
|
-
from,
|
|
912
|
-
to,
|
|
913
|
-
repo: repoConfig
|
|
914
|
-
}, release);
|
|
915
|
-
postedReleases.push({
|
|
916
|
-
name: pkg.name,
|
|
917
|
-
tag: release.tag_name,
|
|
918
|
-
version: newVersion,
|
|
919
|
-
prerelease: release.prerelease
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
if (postedReleases.length === 0) {
|
|
924
|
-
logger.warn("No releases created");
|
|
925
|
-
} else {
|
|
926
|
-
logger.success(`Releases ${postedReleases.map((r) => r.tag).join(", ")} published to GitHub!`);
|
|
927
|
-
}
|
|
928
|
-
return postedReleases;
|
|
929
|
-
}
|
|
930
|
-
async function githubUnified({
|
|
931
|
-
config,
|
|
932
|
-
dryRun,
|
|
933
|
-
rootPackage,
|
|
934
|
-
bumpResult
|
|
935
|
-
}) {
|
|
936
|
-
const repoConfig = config.repo;
|
|
937
|
-
if (!repoConfig) {
|
|
938
|
-
throw new Error("No repository configuration found. Please check your changelog config.");
|
|
939
|
-
}
|
|
940
|
-
logger.debug(`GitHub token: ${config.tokens.github || config.repo?.token ? "\u2713 provided" : "\u2717 missing"}`);
|
|
941
|
-
if (!config.tokens.github && !config.repo?.token) {
|
|
942
|
-
throw new Error("No GitHub token specified. Set GITHUB_TOKEN or GH_TOKEN environment variable.");
|
|
943
|
-
}
|
|
944
|
-
const to = config.to || config.templates.tagBody.replace("{{newVersion}}", bumpResult?.bumped && bumpResult.newVersion || rootPackage.version);
|
|
945
|
-
const changelog = await generateChangelog({
|
|
946
|
-
pkg: rootPackage,
|
|
947
|
-
config,
|
|
948
|
-
dryRun,
|
|
949
|
-
newVersion: bumpResult?.newVersion || rootPackage.version
|
|
950
|
-
});
|
|
951
|
-
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
952
|
-
const release = {
|
|
953
|
-
tag_name: to,
|
|
954
|
-
name: to,
|
|
955
|
-
body: releaseBody,
|
|
956
|
-
prerelease: isPrerelease(to)
|
|
957
|
-
};
|
|
958
|
-
logger.debug(`Creating release for ${to}${release.prerelease ? " (prerelease)" : ""}`);
|
|
959
|
-
logger.debug("Release details:", formatJson({
|
|
960
|
-
tag_name: release.tag_name,
|
|
961
|
-
name: release.name,
|
|
962
|
-
prerelease: release.prerelease
|
|
963
|
-
}));
|
|
964
|
-
if (dryRun) {
|
|
965
|
-
logger.info("[dry-run] Publish GitHub release for", release.tag_name);
|
|
966
|
-
} else {
|
|
967
|
-
logger.debug("Publishing release to GitHub...");
|
|
968
|
-
await createGithubRelease({
|
|
969
|
-
...config,
|
|
970
|
-
from: bumpResult?.bumped && bumpResult.fromTag || "v0.0.0",
|
|
971
|
-
to,
|
|
972
|
-
repo: repoConfig
|
|
973
|
-
}, release);
|
|
974
|
-
}
|
|
975
|
-
logger.success(`Release ${to} published to GitHub!`);
|
|
976
|
-
return [{
|
|
977
|
-
name: to,
|
|
978
|
-
tag: to,
|
|
979
|
-
version: to,
|
|
980
|
-
prerelease: release.prerelease
|
|
981
|
-
}];
|
|
982
|
-
}
|
|
983
|
-
async function github(options) {
|
|
984
|
-
try {
|
|
985
|
-
const dryRun = options.dryRun ?? false;
|
|
986
|
-
logger.debug(`Dry run: ${dryRun}`);
|
|
987
|
-
const config = await loadRelizyConfig({
|
|
988
|
-
configName: options.configName,
|
|
989
|
-
baseConfig: options.config,
|
|
990
|
-
overrides: {
|
|
991
|
-
from: options.from,
|
|
992
|
-
to: options.to,
|
|
993
|
-
logLevel: options.logLevel,
|
|
994
|
-
tokens: {
|
|
995
|
-
github: options.token
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
});
|
|
999
|
-
if (config.monorepo?.versionMode === "independent") {
|
|
1000
|
-
return await githubIndependentMode({
|
|
1001
|
-
config,
|
|
1002
|
-
dryRun,
|
|
1003
|
-
bumpResult: options.bumpResult,
|
|
1004
|
-
force: options.force ?? false,
|
|
1005
|
-
suffix: options.suffix
|
|
1006
|
-
});
|
|
1007
|
-
}
|
|
1008
|
-
const rootPackageBase = readPackageJson(config.cwd);
|
|
1009
|
-
const { from, to } = await resolveTags({
|
|
1010
|
-
config,
|
|
1011
|
-
step: "provider-release",
|
|
1012
|
-
newVersion: options.bumpResult?.newVersion || rootPackageBase.version,
|
|
1013
|
-
pkg: rootPackageBase
|
|
1014
|
-
});
|
|
1015
|
-
const rootPackage = options.bumpResult?.rootPackage || await getRootPackage({
|
|
1016
|
-
config,
|
|
1017
|
-
force: options.force ?? false,
|
|
1018
|
-
suffix: options.suffix,
|
|
1019
|
-
changelog: true,
|
|
1020
|
-
from,
|
|
1021
|
-
to
|
|
1022
|
-
});
|
|
1023
|
-
return await githubUnified({
|
|
1024
|
-
config,
|
|
1025
|
-
dryRun,
|
|
1026
|
-
rootPackage,
|
|
1027
|
-
bumpResult: options.bumpResult
|
|
1028
|
-
});
|
|
1029
|
-
} catch (error) {
|
|
1030
|
-
logger.error("Error publishing GitHub release:", error);
|
|
1031
|
-
throw error;
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
async function createGitlabRelease({
|
|
1036
|
-
config,
|
|
1037
|
-
release,
|
|
1038
|
-
dryRun
|
|
1039
|
-
}) {
|
|
1040
|
-
const token = config.tokens.gitlab || config.repo?.token;
|
|
1041
|
-
if (!token && !dryRun) {
|
|
1042
|
-
throw new Error(
|
|
1043
|
-
"No GitLab token found. Set GITLAB_TOKEN or CI_JOB_TOKEN environment variable or configure tokens.gitlab"
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
const repoConfig = config.repo?.repo;
|
|
1047
|
-
if (!repoConfig) {
|
|
1048
|
-
throw new Error("No repository URL found in config");
|
|
618
|
+
Unstaged files:
|
|
619
|
+
|
|
620
|
+
${dirty.trim()}`;
|
|
621
|
+
throw new Error(error);
|
|
1049
622
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
const apiUrl = `https://${gitlabDomain}/api/v4/projects/${projectPath}/releases`;
|
|
1054
|
-
logger.info(`Creating GitLab release at: ${apiUrl}`);
|
|
1055
|
-
const payload = {
|
|
1056
|
-
tag_name: release.tag_name,
|
|
1057
|
-
name: release.name || release.tag_name,
|
|
1058
|
-
description: release.description || "",
|
|
1059
|
-
ref: release.ref || "main"
|
|
1060
|
-
};
|
|
623
|
+
}
|
|
624
|
+
async function fetchGitTags(cwd) {
|
|
625
|
+
logger.debug("Fetching git tags from remote");
|
|
1061
626
|
try {
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
return {
|
|
1065
|
-
tag_name: release.tag_name,
|
|
1066
|
-
name: release.name || release.tag_name,
|
|
1067
|
-
description: release.description || "",
|
|
1068
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1069
|
-
released_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1070
|
-
_links: {
|
|
1071
|
-
self: `${apiUrl}/${encodeURIComponent(release.tag_name)}`
|
|
1072
|
-
}
|
|
1073
|
-
};
|
|
1074
|
-
}
|
|
1075
|
-
logger.debug(`POST GitLab release to ${apiUrl} with payload: ${formatJson(payload)}`);
|
|
1076
|
-
const response = await fetch(apiUrl, {
|
|
1077
|
-
method: "POST",
|
|
1078
|
-
headers: {
|
|
1079
|
-
"Content-Type": "application/json",
|
|
1080
|
-
"PRIVATE-TOKEN": token || ""
|
|
1081
|
-
},
|
|
1082
|
-
body: JSON.stringify(payload)
|
|
1083
|
-
});
|
|
1084
|
-
if (!response.ok) {
|
|
1085
|
-
const errorText = await response.text();
|
|
1086
|
-
throw new Error(`GitLab API error (${response.status}): ${errorText}`);
|
|
1087
|
-
}
|
|
1088
|
-
const result = await response.json();
|
|
1089
|
-
logger.debug(`Created GitLab release: ${result._links.self}`);
|
|
1090
|
-
return result;
|
|
627
|
+
await execPromise("git fetch --tags", { cwd, noStderr: true, noStdout: true, noSuccess: true });
|
|
628
|
+
logger.debug("Git tags fetched successfully");
|
|
1091
629
|
} catch (error) {
|
|
1092
|
-
logger.
|
|
1093
|
-
|
|
630
|
+
logger.fail("Failed to fetch some git tags from remote (tags might already exist locally)", error);
|
|
631
|
+
logger.info("Continuing with local tags");
|
|
1094
632
|
}
|
|
1095
633
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
const packages = bumpResult?.bumped && bumpResult?.bumpedPackages || await getPackages({
|
|
1105
|
-
patterns: config.monorepo?.packages,
|
|
1106
|
-
config,
|
|
1107
|
-
suffix,
|
|
1108
|
-
force
|
|
1109
|
-
});
|
|
1110
|
-
logger.info(`Creating ${packages.length} GitLab release(s) for independent packages`);
|
|
1111
|
-
logger.debug("Getting current branch...");
|
|
1112
|
-
const { stdout: currentBranch } = await execPromise("git rev-parse --abbrev-ref HEAD", {
|
|
1113
|
-
noSuccess: true,
|
|
1114
|
-
noStdout: true,
|
|
1115
|
-
logLevel: config.logLevel,
|
|
1116
|
-
cwd: config.cwd
|
|
1117
|
-
});
|
|
1118
|
-
const postedReleases = [];
|
|
1119
|
-
for (const pkg of packages) {
|
|
1120
|
-
const newVersion = isBumpedPackage(pkg) && pkg.newVersion || pkg.version;
|
|
1121
|
-
const from = config.from || pkg.fromTag;
|
|
1122
|
-
const to = getIndependentTag({ version: newVersion, name: pkg.name });
|
|
1123
|
-
if (!from) {
|
|
1124
|
-
logger.warn(`No from tag found for ${pkg.name}, skipping release`);
|
|
1125
|
-
continue;
|
|
634
|
+
function detectGitProvider(cwd = process.cwd()) {
|
|
635
|
+
try {
|
|
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";
|
|
1126
642
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
pkg,
|
|
1130
|
-
config,
|
|
1131
|
-
dryRun,
|
|
1132
|
-
newVersion
|
|
1133
|
-
});
|
|
1134
|
-
if (!changelog) {
|
|
1135
|
-
logger.warn(`No changelog found for ${pkg.name}`);
|
|
1136
|
-
continue;
|
|
643
|
+
if (remoteUrl.includes("gitlab.com") || remoteUrl.includes("gitlab")) {
|
|
644
|
+
return "gitlab";
|
|
1137
645
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
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]
|
|
1144
659
|
};
|
|
1145
|
-
logger.debug(`Creating release for ${to} (ref: ${release.ref})`);
|
|
1146
|
-
if (dryRun) {
|
|
1147
|
-
logger.info(`[dry-run] Publish GitLab release for ${to}`);
|
|
1148
|
-
} else {
|
|
1149
|
-
logger.debug(`Publishing release ${to} to GitLab...`);
|
|
1150
|
-
await createGitlabRelease({
|
|
1151
|
-
config,
|
|
1152
|
-
release,
|
|
1153
|
-
dryRun
|
|
1154
|
-
});
|
|
1155
|
-
postedReleases.push({
|
|
1156
|
-
name: pkg.name,
|
|
1157
|
-
tag: release.tag_name,
|
|
1158
|
-
version: newVersion,
|
|
1159
|
-
prerelease: isPrerelease(newVersion)
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
660
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
661
|
+
const httpsMatch = remoteUrl.match(httpsRegex);
|
|
662
|
+
if (httpsMatch) {
|
|
663
|
+
return {
|
|
664
|
+
owner: httpsMatch[1],
|
|
665
|
+
repo: httpsMatch[2]
|
|
666
|
+
};
|
|
1167
667
|
}
|
|
1168
|
-
return
|
|
668
|
+
return null;
|
|
1169
669
|
}
|
|
1170
|
-
async function
|
|
670
|
+
async function createCommitAndTags({
|
|
1171
671
|
config,
|
|
672
|
+
noVerify,
|
|
673
|
+
bumpedPackages,
|
|
674
|
+
newVersion,
|
|
1172
675
|
dryRun,
|
|
1173
|
-
|
|
1174
|
-
bumpResult
|
|
676
|
+
logLevel
|
|
1175
677
|
}) {
|
|
1176
|
-
|
|
1177
|
-
const to = config.templates.tagBody.replace("{{newVersion}}", rootPackage.newVersion || rootPackage.version);
|
|
1178
|
-
const changelog = await generateChangelog({
|
|
1179
|
-
pkg: rootPackage,
|
|
1180
|
-
config,
|
|
1181
|
-
dryRun,
|
|
1182
|
-
newVersion: bumpResult?.newVersion || rootPackage.version
|
|
1183
|
-
});
|
|
1184
|
-
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
1185
|
-
logger.debug("Getting current branch...");
|
|
1186
|
-
const { stdout: currentBranch } = await execPromise("git rev-parse --abbrev-ref HEAD", {
|
|
1187
|
-
noSuccess: true,
|
|
1188
|
-
noStdout: true,
|
|
1189
|
-
logLevel: config.logLevel,
|
|
1190
|
-
cwd: config.cwd
|
|
1191
|
-
});
|
|
1192
|
-
const release = {
|
|
1193
|
-
tag_name: to,
|
|
1194
|
-
name: to,
|
|
1195
|
-
description: releaseBody,
|
|
1196
|
-
ref: currentBranch.trim()
|
|
1197
|
-
};
|
|
1198
|
-
logger.info(`Creating release for ${to} (ref: ${release.ref})`);
|
|
1199
|
-
logger.debug("Release details:", formatJson({
|
|
1200
|
-
tag_name: release.tag_name,
|
|
1201
|
-
name: release.name,
|
|
1202
|
-
ref: release.ref
|
|
1203
|
-
}));
|
|
1204
|
-
if (dryRun) {
|
|
1205
|
-
logger.info("[dry-run] Publish GitLab release for", release.tag_name);
|
|
1206
|
-
} else {
|
|
1207
|
-
logger.debug("Publishing release to GitLab...");
|
|
1208
|
-
await createGitlabRelease({
|
|
1209
|
-
config,
|
|
1210
|
-
release,
|
|
1211
|
-
dryRun
|
|
1212
|
-
});
|
|
1213
|
-
}
|
|
1214
|
-
logger.success(`Release ${to} published to GitLab!`);
|
|
1215
|
-
return [{
|
|
1216
|
-
name: to,
|
|
1217
|
-
tag: to,
|
|
1218
|
-
version: to,
|
|
1219
|
-
prerelease: isPrerelease(rootPackage.version)
|
|
1220
|
-
}];
|
|
1221
|
-
}
|
|
1222
|
-
async function gitlab(options = {}) {
|
|
678
|
+
const internalConfig = config || await loadRelizyConfig();
|
|
1223
679
|
try {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
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
|
+
}
|
|
1235
758
|
}
|
|
759
|
+
createdTags.push(tagName);
|
|
1236
760
|
}
|
|
1237
|
-
|
|
1238
|
-
if (
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
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);
|
|
1246
784
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
newVersion: options.bumpResult?.newVersion || rootPackageBase.version,
|
|
1252
|
-
pkg: rootPackageBase
|
|
1253
|
-
});
|
|
1254
|
-
const rootPackage = options.bumpResult?.rootPackage || await getRootPackage({
|
|
1255
|
-
config,
|
|
1256
|
-
force: options.force ?? false,
|
|
1257
|
-
suffix: options.suffix,
|
|
1258
|
-
changelog: true,
|
|
1259
|
-
from,
|
|
1260
|
-
to
|
|
1261
|
-
});
|
|
1262
|
-
logger.debug(`Root package: ${getIndependentTag({ name: rootPackage.name, version: rootPackage.newVersion || rootPackage.version })}`);
|
|
1263
|
-
return await gitlabUnified({
|
|
1264
|
-
config,
|
|
1265
|
-
dryRun,
|
|
1266
|
-
rootPackage,
|
|
1267
|
-
bumpResult: options.bumpResult
|
|
1268
|
-
});
|
|
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;
|
|
1269
789
|
} catch (error) {
|
|
1270
|
-
logger.error("Error
|
|
790
|
+
logger.error("Error committing and tagging:", error);
|
|
791
|
+
await executeHook("error:commit-and-tag", internalConfig, dryRun ?? false);
|
|
1271
792
|
throw error;
|
|
1272
793
|
}
|
|
1273
794
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
}
|
|
1282
|
-
const semverType = commitType.semver;
|
|
1283
|
-
if (semverType === "major" || commit.isBreaking) {
|
|
1284
|
-
hasMajor = true;
|
|
1285
|
-
} else if (semverType === "minor") {
|
|
1286
|
-
hasMinor = true;
|
|
1287
|
-
} else if (semverType === "patch") {
|
|
1288
|
-
hasPatch = true;
|
|
1289
|
-
}
|
|
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 });
|
|
1290
803
|
}
|
|
1291
|
-
|
|
804
|
+
logger.success("Pushing changes and tags completed!");
|
|
1292
805
|
}
|
|
1293
|
-
function
|
|
1294
|
-
|
|
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();
|
|
1295
815
|
}
|
|
1296
|
-
function
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
if (isNotUpgrade) {
|
|
1303
|
-
throw new Error(`Unable to graduate from ${currentVersion} to ${testVersion}, it's not a valid prerelease`);
|
|
1304
|
-
}
|
|
816
|
+
function getCurrentGitBranch(cwd) {
|
|
817
|
+
const result = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
818
|
+
cwd,
|
|
819
|
+
encoding: "utf8"
|
|
820
|
+
});
|
|
821
|
+
return result.trim();
|
|
1305
822
|
}
|
|
1306
|
-
function
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
return void 0;
|
|
1310
|
-
}
|
|
1311
|
-
const detectedType = commits?.length ? detectReleaseTypeFromCommits(commits, types) : void 0;
|
|
1312
|
-
if (!detectedType && !force) {
|
|
1313
|
-
logger.debug("No significant commits found, skipping bump");
|
|
1314
|
-
return void 0;
|
|
1315
|
-
}
|
|
1316
|
-
logger.debug(`Auto-detected release type from commits: ${detectedType}`);
|
|
1317
|
-
return detectedType;
|
|
823
|
+
function getCurrentGitRef(cwd) {
|
|
824
|
+
const branch = getCurrentGitBranch(cwd);
|
|
825
|
+
return branch || "HEAD";
|
|
1318
826
|
}
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
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);
|
|
1328
852
|
}
|
|
1329
|
-
const
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
function handlePrereleaseVersionToStable(currentVersion) {
|
|
1334
|
-
logger.debug(`Graduating from prerelease ${currentVersion} to stable release`);
|
|
1335
|
-
return "release";
|
|
1336
|
-
}
|
|
1337
|
-
function handlePrereleaseVersionWithPrereleaseType({ currentVersion, preid, commits, force }) {
|
|
1338
|
-
const currentPreid = getPreid(currentVersion);
|
|
1339
|
-
const hasChangedPreid = preid && currentPreid && currentPreid !== preid;
|
|
1340
|
-
if (hasChangedPreid) {
|
|
1341
|
-
const testVersion = semver.inc(currentVersion, "prerelease", preid);
|
|
1342
|
-
if (!testVersion) {
|
|
1343
|
-
throw new Error(`Unable to change preid from ${currentPreid} to ${preid} for version ${currentVersion}`);
|
|
853
|
+
for (const type in updatedConfig.types) {
|
|
854
|
+
const group = typeGroups[type];
|
|
855
|
+
if (!group || group.length === 0) {
|
|
856
|
+
continue;
|
|
1344
857
|
}
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
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
|
+
}
|
|
1348
868
|
}
|
|
1349
|
-
return "prerelease";
|
|
1350
|
-
}
|
|
1351
|
-
if (!commits?.length && !force) {
|
|
1352
|
-
logger.debug("No commits found for prerelease version, skipping bump");
|
|
1353
|
-
return void 0;
|
|
1354
|
-
}
|
|
1355
|
-
logger.debug(`Incrementing prerelease version: ${currentVersion}`);
|
|
1356
|
-
return "prerelease";
|
|
1357
|
-
}
|
|
1358
|
-
function handleExplicitReleaseType({
|
|
1359
|
-
releaseType,
|
|
1360
|
-
currentVersion
|
|
1361
|
-
}) {
|
|
1362
|
-
const isCurrentPrerelease = isPrerelease(currentVersion);
|
|
1363
|
-
const isGraduatingToStable = isCurrentPrerelease && isStableReleaseType(releaseType);
|
|
1364
|
-
if (isGraduatingToStable) {
|
|
1365
|
-
logger.debug(`Graduating from prerelease ${currentVersion} to stable with type: ${releaseType}`);
|
|
1366
|
-
} else {
|
|
1367
|
-
logger.debug(`Using explicit release type: ${releaseType}`);
|
|
1368
|
-
}
|
|
1369
|
-
return releaseType;
|
|
1370
|
-
}
|
|
1371
|
-
function determineReleaseType({
|
|
1372
|
-
currentVersion,
|
|
1373
|
-
commits,
|
|
1374
|
-
releaseType,
|
|
1375
|
-
preid,
|
|
1376
|
-
types,
|
|
1377
|
-
force
|
|
1378
|
-
}) {
|
|
1379
|
-
if (releaseType === "release" && preid) {
|
|
1380
|
-
throw new Error('You cannot use a "release" type with a "preid", to use a preid you must use a "prerelease" type');
|
|
1381
869
|
}
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
logger.debug(`Force flag enabled, using configured type: ${releaseType}`);
|
|
1385
|
-
return releaseType;
|
|
870
|
+
if (breakingChanges.length > 0) {
|
|
871
|
+
markdown.push("", "#### \u26A0\uFE0F Breaking Changes", "", ...breakingChanges);
|
|
1386
872
|
}
|
|
1387
|
-
const
|
|
1388
|
-
|
|
1389
|
-
if (
|
|
1390
|
-
|
|
873
|
+
const _authors = /* @__PURE__ */ new Map();
|
|
874
|
+
for (const commit of commits) {
|
|
875
|
+
if (!commit.author) {
|
|
876
|
+
continue;
|
|
1391
877
|
}
|
|
1392
|
-
|
|
1393
|
-
|
|
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 });
|
|
1394
892
|
}
|
|
1395
|
-
return handleExplicitReleaseType({ releaseType, currentVersion });
|
|
1396
893
|
}
|
|
1397
|
-
if (
|
|
1398
|
-
|
|
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
|
+
);
|
|
1399
910
|
}
|
|
1400
|
-
|
|
1401
|
-
|
|
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
|
+
);
|
|
1402
929
|
}
|
|
1403
|
-
|
|
930
|
+
const result = convert(markdown.join("\n").trim(), true);
|
|
931
|
+
return result;
|
|
1404
932
|
}
|
|
1405
|
-
function
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
const
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
logger.info(`[dry-run] Updated ${packageJson.name}: ${oldVersion} \u2192 ${version}`);
|
|
1415
|
-
return;
|
|
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;
|
|
1416
942
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
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 "";
|
|
1422
948
|
}
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
currentVersion,
|
|
1426
|
-
releaseType,
|
|
1427
|
-
preid,
|
|
1428
|
-
suffix
|
|
1429
|
-
}) {
|
|
1430
|
-
let newVersion = semver.inc(currentVersion, releaseType, preid);
|
|
1431
|
-
if (!newVersion) {
|
|
1432
|
-
throw new Error(`Unable to bump version "${currentVersion}" with release type "${releaseType}"
|
|
949
|
+
const indentedBody = contentLines.map((line) => ` ${line}`).join("\n");
|
|
950
|
+
return `
|
|
1433
951
|
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
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(", ")})`;
|
|
1442
964
|
}
|
|
1443
|
-
if (
|
|
1444
|
-
|
|
965
|
+
if (references.length > 0) {
|
|
966
|
+
return ` (${formatReference(references[0], config.repo)})`;
|
|
1445
967
|
}
|
|
1446
|
-
|
|
1447
|
-
|
|
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);
|
|
1448
978
|
}
|
|
1449
|
-
return
|
|
979
|
+
return groups;
|
|
1450
980
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
981
|
+
|
|
982
|
+
function fromTagIsFirstCommit(fromTag, cwd) {
|
|
983
|
+
return fromTag === getFirstCommit(cwd);
|
|
984
|
+
}
|
|
985
|
+
async function generateChangelog({
|
|
986
|
+
pkg,
|
|
987
|
+
config,
|
|
988
|
+
dryRun,
|
|
989
|
+
newVersion
|
|
1456
990
|
}) {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
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");
|
|
1460
995
|
}
|
|
1461
|
-
|
|
1462
|
-
if (!
|
|
1463
|
-
|
|
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}`);
|
|
1464
1002
|
}
|
|
1003
|
+
logger.debug(`Generating changelog for ${pkg.name} - from ${fromTag} to ${toTag}`);
|
|
1465
1004
|
try {
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
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
|
|
1016
|
+
});
|
|
1017
|
+
let changelog = generatedChangelog;
|
|
1018
|
+
if (pkg.commits.length === 0) {
|
|
1019
|
+
changelog = `${changelog}
|
|
1020
|
+
|
|
1021
|
+
${config.templates.emptyChangelogContent}`;
|
|
1473
1022
|
}
|
|
1474
|
-
|
|
1023
|
+
const changelogResult = await executeHook("generate:changelog", config, dryRun, {
|
|
1024
|
+
commits: pkg.commits,
|
|
1025
|
+
changelog
|
|
1026
|
+
});
|
|
1027
|
+
changelog = changelogResult || changelog;
|
|
1028
|
+
logger.verbose(`Output changelog for ${pkg.name}:
|
|
1029
|
+
${changelog}`);
|
|
1030
|
+
logger.debug(`Changelog generated for ${pkg.name} (${pkg.commits.length} commits)`);
|
|
1031
|
+
logger.verbose(`Final changelog for ${pkg.name}:
|
|
1032
|
+
|
|
1033
|
+
${changelog}
|
|
1034
|
+
|
|
1035
|
+
`);
|
|
1475
1036
|
if (dryRun) {
|
|
1476
|
-
logger.info(`[dry-run]
|
|
1477
|
-
return;
|
|
1037
|
+
logger.info(`[dry-run] ${pkg.name} - Generate changelog ${fromTag}...${toTag}`);
|
|
1478
1038
|
}
|
|
1479
|
-
|
|
1480
|
-
`, "utf8");
|
|
1481
|
-
logger.success(`Updated lerna.json: ${oldVersion} \u2192 ${version}`);
|
|
1039
|
+
return changelog;
|
|
1482
1040
|
} catch (error) {
|
|
1483
|
-
|
|
1041
|
+
throw new Error(`Error generating changelog for ${pkg.name} (${fromTag}...${toTag}): ${error}`);
|
|
1484
1042
|
}
|
|
1485
1043
|
}
|
|
1486
|
-
function
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1044
|
+
function writeChangelogToFile({
|
|
1045
|
+
cwd,
|
|
1046
|
+
pkg,
|
|
1047
|
+
changelog,
|
|
1048
|
+
dryRun = false
|
|
1049
|
+
}) {
|
|
1050
|
+
const changelogPath = join(pkg.path, "CHANGELOG.md");
|
|
1051
|
+
let existingChangelog = "";
|
|
1052
|
+
if (existsSync(changelogPath)) {
|
|
1053
|
+
existingChangelog = readFileSync(changelogPath, "utf8");
|
|
1054
|
+
}
|
|
1055
|
+
const lines = existingChangelog.split("\n");
|
|
1056
|
+
const titleIndex = lines.findIndex((line) => line.startsWith("# "));
|
|
1057
|
+
let updatedChangelog;
|
|
1058
|
+
if (titleIndex !== -1) {
|
|
1059
|
+
const beforeTitle = lines.slice(0, titleIndex + 1);
|
|
1060
|
+
const afterTitle = lines.slice(titleIndex + 1);
|
|
1061
|
+
updatedChangelog = [...beforeTitle, "", changelog, "", ...afterTitle].join("\n");
|
|
1062
|
+
} else {
|
|
1063
|
+
const title = "# Changelog\n";
|
|
1064
|
+
updatedChangelog = `${title}
|
|
1065
|
+
${changelog}
|
|
1066
|
+
${existingChangelog}`;
|
|
1067
|
+
}
|
|
1068
|
+
if (dryRun) {
|
|
1069
|
+
const relativeChangelogPath = relative(cwd, changelogPath);
|
|
1070
|
+
logger.info(`[dry-run] ${pkg.name} - Write changelog to ${relativeChangelogPath}`);
|
|
1071
|
+
} else {
|
|
1072
|
+
logger.debug(`Writing changelog to ${changelogPath}`);
|
|
1073
|
+
writeFileSync(changelogPath, updatedChangelog, "utf8");
|
|
1074
|
+
logger.info(`Changelog updated for ${pkg.name} (${"newVersion" in pkg && pkg.newVersion || pkg.version})`);
|
|
1490
1075
|
}
|
|
1491
|
-
return tag.slice(atIndex + 1);
|
|
1492
|
-
}
|
|
1493
|
-
function isPrerelease(version) {
|
|
1494
|
-
if (!version)
|
|
1495
|
-
return false;
|
|
1496
|
-
const prerelease = semver.prerelease(version);
|
|
1497
|
-
return prerelease ? prerelease.length > 0 : false;
|
|
1498
|
-
}
|
|
1499
|
-
function isStableReleaseType(releaseType) {
|
|
1500
|
-
const stableTypes = ["release", "major", "minor", "patch"];
|
|
1501
|
-
return stableTypes.includes(releaseType);
|
|
1502
|
-
}
|
|
1503
|
-
function isPrereleaseReleaseType(releaseType) {
|
|
1504
|
-
const prereleaseTypes = ["prerelease", "premajor", "preminor", "prepatch"];
|
|
1505
|
-
return prereleaseTypes.includes(releaseType);
|
|
1506
1076
|
}
|
|
1507
|
-
|
|
1508
|
-
|
|
1077
|
+
|
|
1078
|
+
function getDefaultConfig() {
|
|
1079
|
+
return {
|
|
1080
|
+
cwd: process$1.cwd(),
|
|
1081
|
+
types: {
|
|
1082
|
+
feat: { title: "\u{1F680} Enhancements", semver: "minor" },
|
|
1083
|
+
perf: { title: "\u{1F525} Performance", semver: "patch" },
|
|
1084
|
+
fix: { title: "\u{1FA79} Fixes", semver: "patch" },
|
|
1085
|
+
refactor: { title: "\u{1F485} Refactors", semver: "patch" },
|
|
1086
|
+
docs: { title: "\u{1F4D6} Documentation", semver: "patch" },
|
|
1087
|
+
build: { title: "\u{1F4E6} Build", semver: "patch" },
|
|
1088
|
+
types: { title: "\u{1F30A} Types", semver: "patch" },
|
|
1089
|
+
chore: { title: "\u{1F3E1} Chore" },
|
|
1090
|
+
examples: { title: "\u{1F3C0} Examples" },
|
|
1091
|
+
test: { title: "\u2705 Tests" },
|
|
1092
|
+
style: { title: "\u{1F3A8} Styles" },
|
|
1093
|
+
ci: { title: "\u{1F916} CI" }
|
|
1094
|
+
},
|
|
1095
|
+
templates: {
|
|
1096
|
+
commitMessage: "chore(release): bump version to {{newVersion}}",
|
|
1097
|
+
tagMessage: "Bump version to {{newVersion}}",
|
|
1098
|
+
tagBody: "v{{newVersion}}",
|
|
1099
|
+
emptyChangelogContent: "No relevant changes for this release"
|
|
1100
|
+
},
|
|
1101
|
+
excludeAuthors: [],
|
|
1102
|
+
noAuthors: false,
|
|
1103
|
+
bump: {
|
|
1104
|
+
type: "release",
|
|
1105
|
+
clean: true,
|
|
1106
|
+
dependencyTypes: ["dependencies"],
|
|
1107
|
+
yes: false
|
|
1108
|
+
},
|
|
1109
|
+
changelog: {
|
|
1110
|
+
rootChangelog: true,
|
|
1111
|
+
includeCommitBody: true
|
|
1112
|
+
},
|
|
1113
|
+
publish: {
|
|
1114
|
+
private: false,
|
|
1115
|
+
args: [],
|
|
1116
|
+
safetyCheck: false
|
|
1117
|
+
},
|
|
1118
|
+
tokens: {
|
|
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,
|
|
1120
|
+
github: process$1.env.RELIZY_GITHUB_TOKEN || process$1.env.GITHUB_TOKEN || process$1.env.GH_TOKEN
|
|
1121
|
+
},
|
|
1122
|
+
scopeMap: {},
|
|
1123
|
+
release: {
|
|
1124
|
+
commit: true,
|
|
1125
|
+
publish: true,
|
|
1126
|
+
changelog: true,
|
|
1127
|
+
push: true,
|
|
1128
|
+
clean: true,
|
|
1129
|
+
providerRelease: true,
|
|
1130
|
+
noVerify: false,
|
|
1131
|
+
gitTag: true
|
|
1132
|
+
},
|
|
1133
|
+
logLevel: "default",
|
|
1134
|
+
safetyCheck: true
|
|
1135
|
+
};
|
|
1509
1136
|
}
|
|
1510
|
-
function
|
|
1511
|
-
if (
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
if (!prerelease || prerelease.length === 0) {
|
|
1515
|
-
return null;
|
|
1137
|
+
function setupLogger(logLevel) {
|
|
1138
|
+
if (logLevel) {
|
|
1139
|
+
logger.setLevel(logLevel);
|
|
1140
|
+
logger.debug(`Log level set to: ${logLevel}`);
|
|
1516
1141
|
}
|
|
1517
|
-
return prerelease[0];
|
|
1518
1142
|
}
|
|
1519
|
-
function
|
|
1520
|
-
if (!
|
|
1521
|
-
|
|
1143
|
+
async function resolveConfig(config, cwd) {
|
|
1144
|
+
if (!config.repo) {
|
|
1145
|
+
const resolvedRepoConfig = await resolveRepoConfig(cwd);
|
|
1146
|
+
config.repo = {
|
|
1147
|
+
...resolvedRepoConfig,
|
|
1148
|
+
provider: resolvedRepoConfig.provider
|
|
1149
|
+
};
|
|
1522
1150
|
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1151
|
+
if (typeof config.repo === "string") {
|
|
1152
|
+
const resolvedRepoConfig = getRepoConfig(config.repo);
|
|
1153
|
+
config.repo = {
|
|
1154
|
+
...resolvedRepoConfig,
|
|
1155
|
+
provider: resolvedRepoConfig.provider
|
|
1156
|
+
};
|
|
1526
1157
|
}
|
|
1527
|
-
return
|
|
1158
|
+
return config;
|
|
1528
1159
|
}
|
|
1529
|
-
function
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
})
|
|
1533
|
-
|
|
1534
|
-
const
|
|
1535
|
-
const
|
|
1536
|
-
|
|
1537
|
-
|
|
1160
|
+
async function loadRelizyConfig(options) {
|
|
1161
|
+
const cwd = options?.overrides?.cwd ?? process$1.cwd();
|
|
1162
|
+
const configName = options?.configName ?? "relizy";
|
|
1163
|
+
await setupDotenv({ cwd });
|
|
1164
|
+
const defaultConfig = getDefaultConfig();
|
|
1165
|
+
const overridesConfig = defu(options?.overrides, options?.baseConfig);
|
|
1166
|
+
const results = await loadConfig({
|
|
1167
|
+
cwd,
|
|
1168
|
+
name: configName,
|
|
1169
|
+
packageJson: true,
|
|
1170
|
+
defaults: defaultConfig,
|
|
1171
|
+
overrides: overridesConfig
|
|
1172
|
+
});
|
|
1173
|
+
if (!results._configFile) {
|
|
1174
|
+
logger.debug(`No config file found with name "${configName}" - using standalone mode`);
|
|
1175
|
+
if (options?.configName) {
|
|
1176
|
+
logger.error(`No config file found with name "${configName}"`);
|
|
1177
|
+
process$1.exit(1);
|
|
1178
|
+
}
|
|
1538
1179
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
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;
|
|
1542
1185
|
}
|
|
1543
|
-
function
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1186
|
+
function defineConfig(config) {
|
|
1187
|
+
return config;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
async function githubIndependentMode({
|
|
1191
|
+
config,
|
|
1547
1192
|
dryRun,
|
|
1548
|
-
|
|
1193
|
+
bumpResult,
|
|
1194
|
+
force,
|
|
1195
|
+
suffix
|
|
1549
1196
|
}) {
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
if (lernaJsonExists) {
|
|
1554
|
-
logger.log(`${dryRun ? "[dry-run] " : ""}lerna.json: ${currentVersion} \u2192 ${newVersion}`);
|
|
1555
|
-
logger.log("");
|
|
1556
|
-
}
|
|
1197
|
+
const repoConfig = config.repo;
|
|
1198
|
+
if (!repoConfig) {
|
|
1199
|
+
throw new Error("No repository configuration found. Please check your changelog config.");
|
|
1557
1200
|
}
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1201
|
+
logger.debug(`GitHub token: ${config.tokens.github || config.repo?.token ? "\u2713 provided" : "\u2717 missing"}`);
|
|
1202
|
+
if (!config.tokens.github && !config.repo?.token) {
|
|
1203
|
+
throw new Error("No GitHub token specified. Set GITHUB_TOKEN or GH_TOKEN environment variable.");
|
|
1204
|
+
}
|
|
1205
|
+
const packages = await getPackagesOrBumpedPackages({
|
|
1206
|
+
config,
|
|
1207
|
+
bumpResult,
|
|
1208
|
+
suffix,
|
|
1209
|
+
force
|
|
1567
1210
|
});
|
|
1568
|
-
logger.
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
packages.forEach((pkg) => {
|
|
1578
|
-
logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${newVersion} (force)`);
|
|
1579
|
-
});
|
|
1580
|
-
logger.log("");
|
|
1581
|
-
} else {
|
|
1582
|
-
const packagesWithCommits = packages.filter((p) => "reason" in p && p.reason === "commits");
|
|
1583
|
-
const packagesAsDependents = packages.filter((p) => "reason" in p && p.reason === "dependency");
|
|
1584
|
-
const packagesAsGraduation = packages.filter((p) => "reason" in p && p.reason === "graduation");
|
|
1585
|
-
if (packagesWithCommits.length > 0) {
|
|
1586
|
-
logger.log(`${packagesWithCommits.length} package(s) with commits:`);
|
|
1587
|
-
packagesWithCommits.forEach((pkg) => {
|
|
1588
|
-
logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${newVersion}`);
|
|
1589
|
-
});
|
|
1590
|
-
logger.log("");
|
|
1211
|
+
logger.info(`Creating ${packages.length} GitHub release(s)`);
|
|
1212
|
+
const postedReleases = [];
|
|
1213
|
+
for (const pkg of packages) {
|
|
1214
|
+
const newVersion = isBumpedPackage(pkg) && pkg.newVersion || pkg.version;
|
|
1215
|
+
const from = config.from || pkg.fromTag;
|
|
1216
|
+
const to = config.to || getIndependentTag({ version: newVersion, name: pkg.name });
|
|
1217
|
+
if (!from) {
|
|
1218
|
+
logger.warn(`No from tag found for ${pkg.name}, skipping release`);
|
|
1219
|
+
continue;
|
|
1591
1220
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1221
|
+
const toTag = dryRun ? "HEAD" : to;
|
|
1222
|
+
logger.debug(`Processing ${pkg.name}: ${from} \u2192 ${toTag}`);
|
|
1223
|
+
const changelog = await generateChangelog({
|
|
1224
|
+
pkg,
|
|
1225
|
+
config,
|
|
1226
|
+
dryRun,
|
|
1227
|
+
newVersion
|
|
1228
|
+
});
|
|
1229
|
+
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
1230
|
+
const release = {
|
|
1231
|
+
tag_name: to,
|
|
1232
|
+
name: to,
|
|
1233
|
+
body: releaseBody,
|
|
1234
|
+
prerelease: isPrerelease(newVersion)
|
|
1235
|
+
};
|
|
1236
|
+
logger.debug(`Creating release for ${to}${release.prerelease ? " (prerelease)" : ""}`);
|
|
1237
|
+
if (dryRun) {
|
|
1238
|
+
logger.info(`[dry-run] Publish GitHub release for ${to}`);
|
|
1239
|
+
postedReleases.push({
|
|
1240
|
+
name: pkg.name,
|
|
1241
|
+
tag: release.tag_name,
|
|
1242
|
+
version: newVersion,
|
|
1243
|
+
prerelease: release.prerelease
|
|
1596
1244
|
});
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1245
|
+
} else {
|
|
1246
|
+
logger.debug(`Publishing release ${to} to GitHub...`);
|
|
1247
|
+
await createGithubRelease({
|
|
1248
|
+
...config,
|
|
1249
|
+
from,
|
|
1250
|
+
to,
|
|
1251
|
+
repo: repoConfig
|
|
1252
|
+
}, release);
|
|
1253
|
+
postedReleases.push({
|
|
1254
|
+
name: pkg.name,
|
|
1255
|
+
tag: release.tag_name,
|
|
1256
|
+
version: newVersion,
|
|
1257
|
+
prerelease: release.prerelease
|
|
1603
1258
|
});
|
|
1604
|
-
logger.log("");
|
|
1605
1259
|
}
|
|
1606
1260
|
}
|
|
1261
|
+
if (postedReleases.length === 0) {
|
|
1262
|
+
logger.warn("No releases created");
|
|
1263
|
+
} else {
|
|
1264
|
+
logger.success(`Releases ${postedReleases.map((r) => r.tag).join(", ")} published to GitHub!`);
|
|
1265
|
+
}
|
|
1266
|
+
return postedReleases;
|
|
1607
1267
|
}
|
|
1608
|
-
function
|
|
1609
|
-
|
|
1610
|
-
|
|
1268
|
+
async function githubUnified({
|
|
1269
|
+
config,
|
|
1270
|
+
dryRun,
|
|
1271
|
+
rootPackage,
|
|
1272
|
+
bumpResult
|
|
1611
1273
|
}) {
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1274
|
+
const repoConfig = config.repo;
|
|
1275
|
+
if (!repoConfig) {
|
|
1276
|
+
throw new Error("No repository configuration found. Please check your changelog config.");
|
|
1277
|
+
}
|
|
1278
|
+
logger.debug(`GitHub token: ${config.tokens.github || config.repo?.token ? "\u2713 provided" : "\u2717 missing"}`);
|
|
1279
|
+
if (!config.tokens.github && !config.repo?.token) {
|
|
1280
|
+
throw new Error("No GitHub token specified. Set GITHUB_TOKEN or GH_TOKEN environment variable.");
|
|
1281
|
+
}
|
|
1282
|
+
const newVersion = bumpResult?.newVersion || rootPackage.version;
|
|
1283
|
+
const to = config.to || config.templates.tagBody.replace("{{newVersion}}", newVersion);
|
|
1284
|
+
const changelog = await generateChangelog({
|
|
1285
|
+
pkg: rootPackage,
|
|
1286
|
+
config,
|
|
1287
|
+
dryRun,
|
|
1288
|
+
newVersion
|
|
1289
|
+
});
|
|
1290
|
+
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
1291
|
+
const release = {
|
|
1292
|
+
tag_name: to,
|
|
1293
|
+
name: to,
|
|
1294
|
+
body: releaseBody,
|
|
1295
|
+
prerelease: isPrerelease(to)
|
|
1296
|
+
};
|
|
1297
|
+
logger.debug(`Creating release for ${to}${release.prerelease ? " (prerelease)" : ""}`);
|
|
1298
|
+
logger.debug("Release details:", formatJson({
|
|
1299
|
+
tag_name: release.tag_name,
|
|
1300
|
+
name: release.name,
|
|
1301
|
+
prerelease: release.prerelease
|
|
1302
|
+
}));
|
|
1303
|
+
if (dryRun) {
|
|
1304
|
+
logger.info("[dry-run] Publish GitHub release for", release.tag_name);
|
|
1618
1305
|
} else {
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1306
|
+
logger.debug("Publishing release to GitHub...");
|
|
1307
|
+
await createGithubRelease({
|
|
1308
|
+
...config,
|
|
1309
|
+
from: bumpResult?.bumped && bumpResult.fromTag || "v0.0.0",
|
|
1310
|
+
to,
|
|
1311
|
+
repo: repoConfig
|
|
1312
|
+
}, release);
|
|
1313
|
+
}
|
|
1314
|
+
logger.success(`Release ${to} published to GitHub!`);
|
|
1315
|
+
return [{
|
|
1316
|
+
name: to,
|
|
1317
|
+
tag: to,
|
|
1318
|
+
version: to,
|
|
1319
|
+
prerelease: release.prerelease
|
|
1320
|
+
}];
|
|
1321
|
+
}
|
|
1322
|
+
async function github(options) {
|
|
1323
|
+
try {
|
|
1324
|
+
const dryRun = options.dryRun ?? false;
|
|
1325
|
+
logger.debug(`Dry run: ${dryRun}`);
|
|
1326
|
+
const config = await loadRelizyConfig({
|
|
1327
|
+
configName: options.configName,
|
|
1328
|
+
baseConfig: options.config,
|
|
1329
|
+
overrides: {
|
|
1330
|
+
from: options.from,
|
|
1331
|
+
to: options.to,
|
|
1332
|
+
logLevel: options.logLevel,
|
|
1333
|
+
tokens: {
|
|
1334
|
+
github: options.token
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
if (config.monorepo?.versionMode === "independent") {
|
|
1339
|
+
return await githubIndependentMode({
|
|
1340
|
+
config,
|
|
1341
|
+
dryRun,
|
|
1342
|
+
bumpResult: options.bumpResult,
|
|
1343
|
+
force: options.force ?? false,
|
|
1344
|
+
suffix: options.suffix
|
|
1633
1345
|
});
|
|
1634
|
-
logger.log("");
|
|
1635
1346
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
pkg.newVersion && logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${pkg.newVersion}`);
|
|
1640
|
-
});
|
|
1641
|
-
logger.log("");
|
|
1347
|
+
const rootPackageBase = readPackageJson(config.cwd);
|
|
1348
|
+
if (!rootPackageBase) {
|
|
1349
|
+
throw new Error("Failed to read root package.json");
|
|
1642
1350
|
}
|
|
1351
|
+
const newVersion = options.bumpResult?.newVersion || rootPackageBase.version;
|
|
1352
|
+
const { from, to } = await resolveTags({
|
|
1353
|
+
config,
|
|
1354
|
+
step: "provider-release",
|
|
1355
|
+
newVersion,
|
|
1356
|
+
pkg: rootPackageBase
|
|
1357
|
+
});
|
|
1358
|
+
const rootPackage = options.bumpResult?.rootPackage || await getRootPackage({
|
|
1359
|
+
config,
|
|
1360
|
+
force: options.force ?? false,
|
|
1361
|
+
suffix: options.suffix,
|
|
1362
|
+
changelog: true,
|
|
1363
|
+
from,
|
|
1364
|
+
to
|
|
1365
|
+
});
|
|
1366
|
+
return await githubUnified({
|
|
1367
|
+
config,
|
|
1368
|
+
dryRun,
|
|
1369
|
+
rootPackage,
|
|
1370
|
+
bumpResult: options.bumpResult
|
|
1371
|
+
});
|
|
1372
|
+
} catch (error) {
|
|
1373
|
+
logger.error("Error publishing GitHub release:", error);
|
|
1374
|
+
throw error;
|
|
1643
1375
|
}
|
|
1644
1376
|
}
|
|
1645
|
-
|
|
1646
|
-
|
|
1377
|
+
|
|
1378
|
+
async function createGitlabRelease({
|
|
1647
1379
|
config,
|
|
1648
|
-
|
|
1649
|
-
force,
|
|
1650
|
-
currentVersion,
|
|
1651
|
-
newVersion,
|
|
1380
|
+
release,
|
|
1652
1381
|
dryRun
|
|
1653
1382
|
}) {
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1383
|
+
const token = config.tokens.gitlab || config.repo?.token;
|
|
1384
|
+
if (!token && !dryRun) {
|
|
1385
|
+
throw new Error(
|
|
1386
|
+
"No GitLab token found. Set GITLAB_TOKEN or CI_JOB_TOKEN environment variable or configure tokens.gitlab"
|
|
1387
|
+
);
|
|
1657
1388
|
}
|
|
1658
|
-
const
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1389
|
+
const repoConfig = config.repo?.repo;
|
|
1390
|
+
if (!repoConfig) {
|
|
1391
|
+
throw new Error("No repository URL found in config");
|
|
1392
|
+
}
|
|
1393
|
+
logger.debug(`Parsed repository URL: ${repoConfig}`);
|
|
1394
|
+
const projectPath = encodeURIComponent(repoConfig);
|
|
1395
|
+
const gitlabDomain = config.repo?.domain || "gitlab.com";
|
|
1396
|
+
const apiUrl = `https://${gitlabDomain}/api/v4/projects/${projectPath}/releases`;
|
|
1397
|
+
logger.info(`Creating GitLab release at: ${apiUrl}`);
|
|
1398
|
+
const payload = {
|
|
1399
|
+
tag_name: release.tag_name,
|
|
1400
|
+
name: release.name || release.tag_name,
|
|
1401
|
+
description: release.description || "",
|
|
1402
|
+
ref: release.ref || "main"
|
|
1403
|
+
};
|
|
1404
|
+
try {
|
|
1405
|
+
if (dryRun) {
|
|
1406
|
+
logger.info("[dry-run] GitLab release:", formatJson(payload));
|
|
1407
|
+
return {
|
|
1408
|
+
tag_name: release.tag_name,
|
|
1409
|
+
name: release.name || release.tag_name,
|
|
1410
|
+
description: release.description || "",
|
|
1411
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1412
|
+
released_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1413
|
+
_links: {
|
|
1414
|
+
self: `${apiUrl}/${encodeURIComponent(release.tag_name)}`
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1673
1417
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1418
|
+
logger.debug(`POST GitLab release to ${apiUrl} with payload: ${formatJson(payload)}`);
|
|
1419
|
+
const response = await fetch(apiUrl, {
|
|
1420
|
+
method: "POST",
|
|
1421
|
+
headers: {
|
|
1422
|
+
"Content-Type": "application/json",
|
|
1423
|
+
"PRIVATE-TOKEN": token || ""
|
|
1424
|
+
},
|
|
1425
|
+
body: JSON.stringify(payload)
|
|
1426
|
+
});
|
|
1427
|
+
if (!response.ok) {
|
|
1428
|
+
const errorText = await response.text();
|
|
1429
|
+
throw new Error(`GitLab API error (${response.status}): ${errorText}`);
|
|
1679
1430
|
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1431
|
+
const result = await response.json();
|
|
1432
|
+
logger.debug(`Created GitLab release: ${result._links.self}`);
|
|
1433
|
+
return result;
|
|
1434
|
+
} catch (error) {
|
|
1435
|
+
logger.error("Failed to create GitLab release:", error);
|
|
1436
|
+
throw error;
|
|
1683
1437
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1438
|
+
}
|
|
1439
|
+
async function gitlabIndependentMode({
|
|
1440
|
+
config,
|
|
1441
|
+
dryRun,
|
|
1442
|
+
bumpResult,
|
|
1443
|
+
suffix,
|
|
1444
|
+
force
|
|
1445
|
+
}) {
|
|
1446
|
+
logger.debug(`GitLab token: ${config.tokens.gitlab || config.repo?.token ? "\u2713 provided" : "\u2717 missing"}`);
|
|
1447
|
+
const packages = await getPackagesOrBumpedPackages({
|
|
1448
|
+
config,
|
|
1449
|
+
bumpResult,
|
|
1450
|
+
suffix,
|
|
1451
|
+
force
|
|
1452
|
+
});
|
|
1453
|
+
logger.info(`Creating ${packages.length} GitLab release(s) for independent packages`);
|
|
1454
|
+
logger.debug("Getting current branch...");
|
|
1455
|
+
const { stdout: currentBranch } = await execPromise("git rev-parse --abbrev-ref HEAD", {
|
|
1456
|
+
noSuccess: true,
|
|
1457
|
+
noStdout: true,
|
|
1458
|
+
logLevel: config.logLevel,
|
|
1459
|
+
cwd: config.cwd
|
|
1460
|
+
});
|
|
1461
|
+
const postedReleases = [];
|
|
1462
|
+
for (const pkg of packages) {
|
|
1463
|
+
const newVersion = isBumpedPackage(pkg) && pkg.newVersion || pkg.version;
|
|
1464
|
+
const from = config.from || pkg.fromTag;
|
|
1465
|
+
const to = getIndependentTag({ version: newVersion, name: pkg.name });
|
|
1466
|
+
if (!from) {
|
|
1467
|
+
logger.warn(`No from tag found for ${pkg.name}, skipping release`);
|
|
1468
|
+
continue;
|
|
1469
|
+
}
|
|
1470
|
+
logger.debug(`Processing ${pkg.name}: ${from} \u2192 ${to}`);
|
|
1471
|
+
const changelog = await generateChangelog({
|
|
1472
|
+
pkg,
|
|
1473
|
+
config,
|
|
1474
|
+
dryRun,
|
|
1475
|
+
newVersion
|
|
1688
1476
|
});
|
|
1689
|
-
if (!
|
|
1690
|
-
logger.
|
|
1691
|
-
|
|
1692
|
-
process.exit(0);
|
|
1477
|
+
if (!changelog) {
|
|
1478
|
+
logger.warn(`No changelog found for ${pkg.name}`);
|
|
1479
|
+
continue;
|
|
1693
1480
|
}
|
|
1694
|
-
|
|
1695
|
-
const
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1481
|
+
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
1482
|
+
const release = {
|
|
1483
|
+
tag_name: to,
|
|
1484
|
+
name: to,
|
|
1485
|
+
description: releaseBody,
|
|
1486
|
+
ref: currentBranch.trim()
|
|
1487
|
+
};
|
|
1488
|
+
logger.debug(`Creating release for ${to} (ref: ${release.ref})`);
|
|
1489
|
+
if (dryRun) {
|
|
1490
|
+
logger.info(`[dry-run] Publish GitLab release for ${to}`);
|
|
1491
|
+
} else {
|
|
1492
|
+
logger.debug(`Publishing release ${to} to GitLab...`);
|
|
1493
|
+
await createGitlabRelease({
|
|
1494
|
+
config,
|
|
1495
|
+
release,
|
|
1496
|
+
dryRun
|
|
1497
|
+
});
|
|
1498
|
+
postedReleases.push({
|
|
1499
|
+
name: pkg.name,
|
|
1500
|
+
tag: release.tag_name,
|
|
1501
|
+
version: newVersion,
|
|
1502
|
+
prerelease: isPrerelease(newVersion)
|
|
1503
|
+
});
|
|
1700
1504
|
}
|
|
1701
|
-
logger.fail("Error while confirming bump");
|
|
1702
|
-
process.exit(1);
|
|
1703
1505
|
}
|
|
1704
|
-
|
|
1506
|
+
if (postedReleases.length === 0) {
|
|
1507
|
+
logger.warn("No releases created");
|
|
1508
|
+
} else {
|
|
1509
|
+
logger.success(`Releases ${postedReleases.map((r) => r.tag).join(", ")} published to GitLab!`);
|
|
1510
|
+
}
|
|
1511
|
+
return postedReleases;
|
|
1705
1512
|
}
|
|
1706
|
-
function
|
|
1707
|
-
|
|
1708
|
-
dryRun
|
|
1513
|
+
async function gitlabUnified({
|
|
1514
|
+
config,
|
|
1515
|
+
dryRun,
|
|
1516
|
+
rootPackage,
|
|
1517
|
+
bumpResult
|
|
1709
1518
|
}) {
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1519
|
+
logger.debug(`GitLab token: ${config.tokens.gitlab || config.repo?.token ? "\u2713 provided" : "\u2717 missing"}`);
|
|
1520
|
+
const newVersion = bumpResult?.newVersion || rootPackage.newVersion || rootPackage.version;
|
|
1521
|
+
const to = config.templates.tagBody.replace("{{newVersion}}", newVersion);
|
|
1522
|
+
const changelog = await generateChangelog({
|
|
1523
|
+
pkg: rootPackage,
|
|
1524
|
+
config,
|
|
1525
|
+
dryRun,
|
|
1526
|
+
newVersion
|
|
1527
|
+
});
|
|
1528
|
+
const releaseBody = changelog.split("\n").slice(2).join("\n");
|
|
1529
|
+
logger.debug("Getting current branch...");
|
|
1530
|
+
const { stdout: currentBranch } = await execPromise("git rev-parse --abbrev-ref HEAD", {
|
|
1531
|
+
noSuccess: true,
|
|
1532
|
+
noStdout: true,
|
|
1533
|
+
logLevel: config.logLevel,
|
|
1534
|
+
cwd: config.cwd
|
|
1535
|
+
});
|
|
1536
|
+
const release = {
|
|
1537
|
+
tag_name: to,
|
|
1538
|
+
name: to,
|
|
1539
|
+
description: releaseBody,
|
|
1540
|
+
ref: currentBranch.trim()
|
|
1541
|
+
};
|
|
1542
|
+
logger.info(`Creating release for ${to} (ref: ${release.ref})`);
|
|
1543
|
+
logger.debug("Release details:", formatJson({
|
|
1544
|
+
tag_name: release.tag_name,
|
|
1545
|
+
name: release.name,
|
|
1546
|
+
ref: release.ref
|
|
1547
|
+
}));
|
|
1548
|
+
if (dryRun) {
|
|
1549
|
+
logger.info("[dry-run] Publish GitLab release for", release.tag_name);
|
|
1550
|
+
} else {
|
|
1551
|
+
logger.debug("Publishing release to GitLab...");
|
|
1552
|
+
await createGitlabRelease({
|
|
1553
|
+
config,
|
|
1554
|
+
release,
|
|
1715
1555
|
dryRun
|
|
1716
1556
|
});
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1557
|
+
}
|
|
1558
|
+
logger.success(`Release ${to} published to GitLab!`);
|
|
1559
|
+
return [{
|
|
1560
|
+
name: to,
|
|
1561
|
+
tag: to,
|
|
1562
|
+
version: to,
|
|
1563
|
+
prerelease: isPrerelease(newVersion)
|
|
1564
|
+
}];
|
|
1565
|
+
}
|
|
1566
|
+
async function gitlab(options = {}) {
|
|
1567
|
+
try {
|
|
1568
|
+
const dryRun = options.dryRun ?? false;
|
|
1569
|
+
logger.debug(`Dry run: ${dryRun}`);
|
|
1570
|
+
const config = await loadRelizyConfig({
|
|
1571
|
+
configName: options.configName,
|
|
1572
|
+
baseConfig: options.config,
|
|
1573
|
+
overrides: {
|
|
1574
|
+
from: options.from,
|
|
1575
|
+
to: options.to,
|
|
1576
|
+
logLevel: options.logLevel,
|
|
1577
|
+
tokens: {
|
|
1578
|
+
gitlab: options.token
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
});
|
|
1582
|
+
if (config.monorepo?.versionMode === "independent") {
|
|
1583
|
+
return await gitlabIndependentMode({
|
|
1584
|
+
config,
|
|
1585
|
+
dryRun,
|
|
1586
|
+
bumpResult: options.bumpResult,
|
|
1587
|
+
suffix: options.suffix,
|
|
1588
|
+
force: options.force ?? false
|
|
1721
1589
|
});
|
|
1722
1590
|
}
|
|
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;
|
|
1596
|
+
const { from, to } = await resolveTags({
|
|
1597
|
+
config,
|
|
1598
|
+
step: "provider-release",
|
|
1599
|
+
newVersion,
|
|
1600
|
+
pkg: rootPackageBase
|
|
1601
|
+
});
|
|
1602
|
+
const rootPackage = options.bumpResult?.rootPackage || await getRootPackage({
|
|
1603
|
+
config,
|
|
1604
|
+
force: options.force ?? false,
|
|
1605
|
+
suffix: options.suffix,
|
|
1606
|
+
changelog: true,
|
|
1607
|
+
from,
|
|
1608
|
+
to
|
|
1609
|
+
});
|
|
1610
|
+
logger.debug(`Root package: ${getIndependentTag({ name: rootPackage.name, version: newVersion })}`);
|
|
1611
|
+
return await gitlabUnified({
|
|
1612
|
+
config,
|
|
1613
|
+
dryRun,
|
|
1614
|
+
rootPackage,
|
|
1615
|
+
bumpResult: options.bumpResult
|
|
1616
|
+
});
|
|
1617
|
+
} catch (error) {
|
|
1618
|
+
logger.error("Error publishing GitLab release:", error);
|
|
1619
|
+
throw error;
|
|
1723
1620
|
}
|
|
1724
|
-
return bumpedPackages;
|
|
1725
1621
|
}
|
|
1726
1622
|
|
|
1727
|
-
function
|
|
1728
|
-
|
|
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;
|
|
1729
1628
|
}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
noStdout: true,
|
|
1737
|
-
noSuccess: true,
|
|
1738
|
-
cwd
|
|
1629
|
+
function determineSemverChange(commits, types) {
|
|
1630
|
+
let [hasMajor, hasMinor, hasPatch] = [false, false, false];
|
|
1631
|
+
for (const commit of commits) {
|
|
1632
|
+
const commitType = types[commit.type];
|
|
1633
|
+
if (!commitType) {
|
|
1634
|
+
continue;
|
|
1739
1635
|
}
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1636
|
+
const semverType = commitType.semver;
|
|
1637
|
+
if (semverType === "major" || commit.isBreaking) {
|
|
1638
|
+
hasMajor = true;
|
|
1639
|
+
} else if (semverType === "minor") {
|
|
1640
|
+
hasMinor = true;
|
|
1641
|
+
} else if (semverType === "patch") {
|
|
1642
|
+
hasPatch = true;
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
return hasMajor ? "major" : hasMinor ? "minor" : hasPatch ? "patch" : void 0;
|
|
1744
1646
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
logLevel,
|
|
1748
|
-
noStderr: true,
|
|
1749
|
-
noStdout: true,
|
|
1750
|
-
noSuccess: true,
|
|
1751
|
-
cwd
|
|
1752
|
-
});
|
|
1753
|
-
const lastTag = stdout.trim();
|
|
1754
|
-
logger.debug("Last tag:", lastTag || "No tags found");
|
|
1755
|
-
return lastTag;
|
|
1647
|
+
function detectReleaseTypeFromCommits(commits, types) {
|
|
1648
|
+
return determineSemverChange(commits, types);
|
|
1756
1649
|
}
|
|
1757
|
-
function
|
|
1758
|
-
if (
|
|
1759
|
-
return
|
|
1650
|
+
function validatePrereleaseDowngrade(currentVersion, targetPreid, configuredType) {
|
|
1651
|
+
if (configuredType !== "prerelease" || !targetPreid || !isPrerelease(currentVersion)) {
|
|
1652
|
+
return;
|
|
1653
|
+
}
|
|
1654
|
+
const testVersion = semver.inc(currentVersion, "prerelease", targetPreid);
|
|
1655
|
+
const isNotUpgrade = testVersion && !semver.gt(testVersion, currentVersion);
|
|
1656
|
+
if (isNotUpgrade) {
|
|
1657
|
+
throw new Error(`Unable to graduate from ${currentVersion} to ${testVersion}, it's not a valid prerelease`);
|
|
1760
1658
|
}
|
|
1761
|
-
return getLastTag({ logLevel: options?.logLevel, cwd: options?.cwd });
|
|
1762
1659
|
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
logLevel,
|
|
1781
|
-
noStderr: true,
|
|
1782
|
-
noStdout: true,
|
|
1783
|
-
noSuccess: true,
|
|
1784
|
-
cwd
|
|
1785
|
-
}
|
|
1786
|
-
);
|
|
1787
|
-
const tag = stdout.trim();
|
|
1788
|
-
return tag || null;
|
|
1789
|
-
} catch {
|
|
1790
|
-
return null;
|
|
1660
|
+
function handleStableVersionWithReleaseType(commits, types, force) {
|
|
1661
|
+
if (!commits?.length && !force) {
|
|
1662
|
+
logger.debug('No commits found for stable version with "release" type, skipping bump');
|
|
1663
|
+
return void 0;
|
|
1664
|
+
}
|
|
1665
|
+
const detectedType = commits?.length ? detectReleaseTypeFromCommits(commits, types) : void 0;
|
|
1666
|
+
if (!detectedType && !force) {
|
|
1667
|
+
logger.debug("No significant commits found, skipping bump");
|
|
1668
|
+
return void 0;
|
|
1669
|
+
}
|
|
1670
|
+
logger.debug(`Auto-detected release type from commits: ${detectedType}`);
|
|
1671
|
+
return detectedType;
|
|
1672
|
+
}
|
|
1673
|
+
function handleStableVersionWithPrereleaseType(commits, types, force) {
|
|
1674
|
+
if (!commits?.length && !force) {
|
|
1675
|
+
logger.debug('No commits found for stable version with "prerelease" type, skipping bump');
|
|
1676
|
+
return void 0;
|
|
1791
1677
|
}
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
graduating,
|
|
1797
|
-
logLevel
|
|
1798
|
-
}) {
|
|
1799
|
-
const lastPackageTag = await getLastPackageTag({
|
|
1800
|
-
packageName,
|
|
1801
|
-
onlyStable: graduating,
|
|
1802
|
-
logLevel
|
|
1803
|
-
});
|
|
1804
|
-
if (!lastPackageTag) {
|
|
1805
|
-
return getFirstCommit(cwd);
|
|
1678
|
+
const detectedType = commits?.length ? detectReleaseTypeFromCommits(commits, types) : void 0;
|
|
1679
|
+
if (!detectedType) {
|
|
1680
|
+
logger.debug("No significant commits found, using prepatch as default");
|
|
1681
|
+
return "prepatch";
|
|
1806
1682
|
}
|
|
1807
|
-
|
|
1683
|
+
const prereleaseType = `pre${detectedType}`;
|
|
1684
|
+
logger.debug(`Auto-detected prerelease type from commits: ${prereleaseType}`);
|
|
1685
|
+
return prereleaseType;
|
|
1808
1686
|
}
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
logLevel
|
|
1813
|
-
}) {
|
|
1814
|
-
const from = await getLastRepoTag({ onlyStable: graduating, logLevel }) || getFirstCommit(config.cwd);
|
|
1815
|
-
return from;
|
|
1687
|
+
function handlePrereleaseVersionToStable(currentVersion) {
|
|
1688
|
+
logger.debug(`Graduating from prerelease ${currentVersion} to stable release`);
|
|
1689
|
+
return "release";
|
|
1816
1690
|
}
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
}) {
|
|
1825
|
-
let from;
|
|
1826
|
-
if (versionMode === "independent") {
|
|
1827
|
-
if (!packageName) {
|
|
1828
|
-
throw new Error("Package name is required for independent version mode");
|
|
1691
|
+
function handlePrereleaseVersionWithPrereleaseType({ currentVersion, preid, commits, force }) {
|
|
1692
|
+
const currentPreid = getPreid(currentVersion);
|
|
1693
|
+
const hasChangedPreid = preid && currentPreid && currentPreid !== preid;
|
|
1694
|
+
if (hasChangedPreid) {
|
|
1695
|
+
const testVersion = semver.inc(currentVersion, "prerelease", preid);
|
|
1696
|
+
if (!testVersion) {
|
|
1697
|
+
throw new Error(`Unable to change preid from ${currentPreid} to ${preid} for version ${currentVersion}`);
|
|
1829
1698
|
}
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1699
|
+
const isUpgrade = semver.gt(testVersion, currentVersion);
|
|
1700
|
+
if (!isUpgrade) {
|
|
1701
|
+
throw new Error(`Unable to change preid from ${currentVersion} to ${testVersion}, it's not a valid upgrade (cannot downgrade from ${currentPreid} to ${preid})`);
|
|
1702
|
+
}
|
|
1703
|
+
return "prerelease";
|
|
1704
|
+
}
|
|
1705
|
+
if (!commits?.length && !force) {
|
|
1706
|
+
logger.debug("No commits found for prerelease version, skipping bump");
|
|
1707
|
+
return void 0;
|
|
1708
|
+
}
|
|
1709
|
+
logger.debug(`Incrementing prerelease version: ${currentVersion}`);
|
|
1710
|
+
return "prerelease";
|
|
1711
|
+
}
|
|
1712
|
+
function handleExplicitReleaseType({
|
|
1713
|
+
releaseType,
|
|
1714
|
+
currentVersion
|
|
1715
|
+
}) {
|
|
1716
|
+
const isCurrentPrerelease = isPrerelease(currentVersion);
|
|
1717
|
+
const isGraduatingToStable = isCurrentPrerelease && isStableReleaseType(releaseType);
|
|
1718
|
+
if (isGraduatingToStable) {
|
|
1719
|
+
logger.debug(`Graduating from prerelease ${currentVersion} to stable with type: ${releaseType}`);
|
|
1836
1720
|
} else {
|
|
1837
|
-
|
|
1838
|
-
config,
|
|
1839
|
-
graduating,
|
|
1840
|
-
logLevel
|
|
1841
|
-
});
|
|
1721
|
+
logger.debug(`Using explicit release type: ${releaseType}`);
|
|
1842
1722
|
}
|
|
1843
|
-
|
|
1844
|
-
return config.from || from;
|
|
1723
|
+
return releaseType;
|
|
1845
1724
|
}
|
|
1846
|
-
function
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1725
|
+
function determineReleaseType({
|
|
1726
|
+
currentVersion,
|
|
1727
|
+
commits,
|
|
1728
|
+
releaseType,
|
|
1729
|
+
preid,
|
|
1730
|
+
types,
|
|
1731
|
+
force
|
|
1852
1732
|
}) {
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1733
|
+
if (releaseType === "release" && preid) {
|
|
1734
|
+
throw new Error('You cannot use a "release" type with a "preid", to use a preid you must use a "prerelease" type');
|
|
1735
|
+
}
|
|
1736
|
+
validatePrereleaseDowngrade(currentVersion, preid, releaseType);
|
|
1737
|
+
if (force) {
|
|
1738
|
+
logger.debug(`Force flag enabled, using configured type: ${releaseType}`);
|
|
1739
|
+
return releaseType;
|
|
1740
|
+
}
|
|
1741
|
+
const isCurrentPrerelease = isPrerelease(currentVersion);
|
|
1742
|
+
if (!isCurrentPrerelease) {
|
|
1743
|
+
if (releaseType === "release") {
|
|
1744
|
+
return handleStableVersionWithReleaseType(commits, types, force);
|
|
1860
1745
|
}
|
|
1861
|
-
if (
|
|
1862
|
-
|
|
1746
|
+
if (releaseType === "prerelease") {
|
|
1747
|
+
return handleStableVersionWithPrereleaseType(commits, types, force);
|
|
1863
1748
|
}
|
|
1864
|
-
|
|
1865
|
-
} else {
|
|
1866
|
-
to = newVersion ? config.templates.tagBody.replace("{{newVersion}}", newVersion) : getCurrentGitRef(config.cwd);
|
|
1749
|
+
return handleExplicitReleaseType({ releaseType, currentVersion });
|
|
1867
1750
|
}
|
|
1868
|
-
|
|
1869
|
-
|
|
1751
|
+
if (releaseType === "release") {
|
|
1752
|
+
return handlePrereleaseVersionToStable(currentVersion);
|
|
1753
|
+
}
|
|
1754
|
+
if (releaseType === "prerelease") {
|
|
1755
|
+
return handlePrereleaseVersionWithPrereleaseType({ currentVersion, preid, commits, force });
|
|
1756
|
+
}
|
|
1757
|
+
return handleExplicitReleaseType({ releaseType, currentVersion });
|
|
1870
1758
|
}
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
}
|
|
1889
|
-
const to = resolveToTag({
|
|
1890
|
-
config,
|
|
1891
|
-
versionMode,
|
|
1892
|
-
newVersion,
|
|
1893
|
-
step,
|
|
1894
|
-
packageName: pkg.name
|
|
1895
|
-
});
|
|
1896
|
-
logger.debug(`[${versionMode}](${step}) Using tags: ${from} \u2192 ${to}`);
|
|
1897
|
-
return { from, to };
|
|
1759
|
+
function writeVersion(pkgPath, newVersion, dryRun = false) {
|
|
1760
|
+
const packageJsonPath = join(pkgPath, "package.json");
|
|
1761
|
+
try {
|
|
1762
|
+
logger.debug(`Writing ${newVersion} to ${pkgPath}`);
|
|
1763
|
+
const content = readFileSync(packageJsonPath, "utf8");
|
|
1764
|
+
const packageJson = JSON.parse(content);
|
|
1765
|
+
const oldVersion = packageJson.version;
|
|
1766
|
+
packageJson.version = newVersion;
|
|
1767
|
+
if (dryRun) {
|
|
1768
|
+
logger.info(`[dry-run] Updated ${packageJson.name}: ${oldVersion} \u2192 ${newVersion}`);
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
writeFileSync(packageJsonPath, `${formatJson(packageJson)}
|
|
1772
|
+
`, "utf8");
|
|
1773
|
+
logger.info(`Updated ${packageJson.name}: ${oldVersion} \u2192 ${newVersion}`);
|
|
1774
|
+
} catch (error) {
|
|
1775
|
+
throw new Error(`Unable to write version to ${packageJsonPath}: ${error}`);
|
|
1776
|
+
}
|
|
1898
1777
|
}
|
|
1778
|
+
function getPackageNewVersion({
|
|
1779
|
+
name,
|
|
1780
|
+
currentVersion,
|
|
1781
|
+
releaseType,
|
|
1782
|
+
preid,
|
|
1783
|
+
suffix
|
|
1784
|
+
}) {
|
|
1785
|
+
let newVersion = semver.inc(currentVersion, releaseType, preid);
|
|
1786
|
+
if (!newVersion) {
|
|
1787
|
+
throw new Error(`Unable to bump "${name}" version "${currentVersion}" with release type "${releaseType}"
|
|
1899
1788
|
|
|
1900
|
-
|
|
1901
|
-
|
|
1789
|
+
You should use an explicit release type (use flag: --major, --minor, --patch, --premajor, --preminor, --prepatch, --prerelease)`);
|
|
1790
|
+
}
|
|
1791
|
+
if (isPrereleaseReleaseType(releaseType) && suffix) {
|
|
1792
|
+
newVersion = newVersion.replace(/\.(\d+)$/, `.${suffix}`);
|
|
1793
|
+
}
|
|
1794
|
+
const isValidVersion = semver.gt(newVersion, currentVersion);
|
|
1795
|
+
if (!isValidVersion) {
|
|
1796
|
+
throw new Error(`Unable to bump "${name}" version "${currentVersion}" to "${newVersion}", new version is not greater than current version`);
|
|
1797
|
+
}
|
|
1798
|
+
if (isGraduating(currentVersion, releaseType)) {
|
|
1799
|
+
logger.info(`Graduating "${name}" from prerelease ${currentVersion} to stable ${newVersion}`);
|
|
1800
|
+
}
|
|
1801
|
+
if (isChangedPreid(currentVersion, preid)) {
|
|
1802
|
+
logger.debug(`Graduating "${name}" from ${getPreid(currentVersion)} to ${preid}`);
|
|
1803
|
+
}
|
|
1804
|
+
return newVersion;
|
|
1805
|
+
}
|
|
1806
|
+
function updateLernaVersion({
|
|
1807
|
+
rootDir,
|
|
1808
|
+
versionMode,
|
|
1809
|
+
version,
|
|
1810
|
+
dryRun = false
|
|
1811
|
+
}) {
|
|
1812
|
+
const lernaJsonExists = hasLernaJson(rootDir);
|
|
1813
|
+
if (!lernaJsonExists) {
|
|
1814
|
+
return;
|
|
1815
|
+
}
|
|
1816
|
+
const lernaJsonPath = join(rootDir, "lerna.json");
|
|
1817
|
+
if (!existsSync(lernaJsonPath)) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1902
1820
|
try {
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
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
|
-
}
|
|
1821
|
+
logger.debug("Updating lerna.json version");
|
|
1822
|
+
const content = readFileSync(lernaJsonPath, "utf8");
|
|
1823
|
+
const lernaJson = JSON.parse(content);
|
|
1824
|
+
const oldVersion = lernaJson.version;
|
|
1825
|
+
if (lernaJson.version === "independent" || versionMode === "independent") {
|
|
1826
|
+
logger.debug("Lerna version is independent or version mode is independent, skipping update");
|
|
1827
|
+
return;
|
|
1939
1828
|
}
|
|
1940
|
-
|
|
1941
|
-
|
|
1829
|
+
lernaJson.version = version;
|
|
1830
|
+
if (dryRun) {
|
|
1831
|
+
logger.info(`[dry-run] update lerna.json: ${oldVersion} \u2192 ${version}`);
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
writeFileSync(lernaJsonPath, `${formatJson(lernaJson)}
|
|
1835
|
+
`, "utf8");
|
|
1836
|
+
logger.success(`Updated lerna.json: ${oldVersion} \u2192 ${version}`);
|
|
1942
1837
|
} catch (error) {
|
|
1943
|
-
logger.fail(`
|
|
1944
|
-
return "npm";
|
|
1838
|
+
logger.fail(`Unable to update lerna.json: ${error}`);
|
|
1945
1839
|
}
|
|
1946
1840
|
}
|
|
1947
|
-
function
|
|
1948
|
-
|
|
1949
|
-
if (
|
|
1950
|
-
|
|
1841
|
+
function extractVersionFromPackageTag(tag) {
|
|
1842
|
+
const atIndex = tag.lastIndexOf("@");
|
|
1843
|
+
if (atIndex === -1) {
|
|
1844
|
+
return null;
|
|
1951
1845
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1846
|
+
return tag.slice(atIndex + 1);
|
|
1847
|
+
}
|
|
1848
|
+
function isPrerelease(version) {
|
|
1849
|
+
if (!version)
|
|
1850
|
+
return false;
|
|
1851
|
+
const prerelease = semver.prerelease(version);
|
|
1852
|
+
return prerelease ? prerelease.length > 0 : false;
|
|
1853
|
+
}
|
|
1854
|
+
function isStableReleaseType(releaseType) {
|
|
1855
|
+
const stableTypes = ["release", "major", "minor", "patch"];
|
|
1856
|
+
return stableTypes.includes(releaseType);
|
|
1857
|
+
}
|
|
1858
|
+
function isPrereleaseReleaseType(releaseType) {
|
|
1859
|
+
const prereleaseTypes = ["prerelease", "premajor", "preminor", "prepatch"];
|
|
1860
|
+
return prereleaseTypes.includes(releaseType);
|
|
1861
|
+
}
|
|
1862
|
+
function isGraduating(currentVersion, releaseType) {
|
|
1863
|
+
return isPrerelease(currentVersion) && isStableReleaseType(releaseType);
|
|
1864
|
+
}
|
|
1865
|
+
function getPreid(version) {
|
|
1866
|
+
if (!version)
|
|
1867
|
+
return null;
|
|
1868
|
+
const prerelease = semver.prerelease(version);
|
|
1869
|
+
if (!prerelease || prerelease.length === 0) {
|
|
1870
|
+
return null;
|
|
1955
1871
|
}
|
|
1956
|
-
|
|
1957
|
-
|
|
1872
|
+
return prerelease[0];
|
|
1873
|
+
}
|
|
1874
|
+
function isChangedPreid(currentVersion, targetPreid) {
|
|
1875
|
+
if (!targetPreid || !isPrerelease(currentVersion)) {
|
|
1876
|
+
return false;
|
|
1958
1877
|
}
|
|
1959
|
-
|
|
1878
|
+
const currentPreid = getPreid(currentVersion);
|
|
1879
|
+
if (!currentPreid) {
|
|
1880
|
+
return false;
|
|
1881
|
+
}
|
|
1882
|
+
return currentPreid !== targetPreid;
|
|
1960
1883
|
}
|
|
1961
|
-
function
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1884
|
+
function getBumpedPackageIndependently({
|
|
1885
|
+
pkg,
|
|
1886
|
+
dryRun
|
|
1887
|
+
}) {
|
|
1888
|
+
logger.debug(`Analyzing ${pkg.name}`);
|
|
1889
|
+
const currentVersion = pkg.version || "0.0.0";
|
|
1890
|
+
const newVersion = pkg.newVersion;
|
|
1891
|
+
if (!newVersion) {
|
|
1892
|
+
return { bumped: false };
|
|
1969
1893
|
}
|
|
1970
|
-
|
|
1894
|
+
logger.debug(`Bumping ${pkg.name} from ${currentVersion} to ${newVersion}`);
|
|
1895
|
+
writeVersion(pkg.path, newVersion, dryRun);
|
|
1896
|
+
return { bumped: true, newVersion, oldVersion: currentVersion };
|
|
1971
1897
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
});
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
logger.
|
|
1898
|
+
function displayRootAndLernaUpdates({
|
|
1899
|
+
versionMode,
|
|
1900
|
+
currentVersion,
|
|
1901
|
+
newVersion,
|
|
1902
|
+
dryRun,
|
|
1903
|
+
lernaJsonExists
|
|
1904
|
+
}) {
|
|
1905
|
+
if (versionMode !== "independent" && currentVersion && newVersion) {
|
|
1906
|
+
logger.log(`${dryRun ? "[dry-run] " : ""}Root package.json: ${currentVersion} \u2192 ${newVersion}`);
|
|
1907
|
+
logger.log("");
|
|
1908
|
+
if (lernaJsonExists) {
|
|
1909
|
+
logger.log(`${dryRun ? "[dry-run] " : ""}lerna.json: ${currentVersion} \u2192 ${newVersion}`);
|
|
1910
|
+
logger.log("");
|
|
1984
1911
|
}
|
|
1985
1912
|
}
|
|
1986
|
-
return packagesToPublish;
|
|
1987
1913
|
}
|
|
1988
|
-
function
|
|
1989
|
-
|
|
1914
|
+
function displayUnifiedModePackages({
|
|
1915
|
+
packages,
|
|
1916
|
+
newVersion,
|
|
1917
|
+
force
|
|
1918
|
+
}) {
|
|
1919
|
+
logger.log(`${packages.length} package(s):`);
|
|
1920
|
+
packages.forEach((pkg) => {
|
|
1921
|
+
logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${newVersion} ${force ? "(force)" : ""}`);
|
|
1922
|
+
});
|
|
1923
|
+
logger.log("");
|
|
1990
1924
|
}
|
|
1991
|
-
function
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
otp
|
|
1925
|
+
function displaySelectiveModePackages({
|
|
1926
|
+
packages,
|
|
1927
|
+
newVersion,
|
|
1928
|
+
force
|
|
1996
1929
|
}) {
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
}
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
1930
|
+
if (force) {
|
|
1931
|
+
logger.log(`${packages.length} package(s):`);
|
|
1932
|
+
packages.forEach((pkg) => {
|
|
1933
|
+
logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${newVersion} (force)`);
|
|
1934
|
+
});
|
|
1935
|
+
logger.log("");
|
|
1936
|
+
} else {
|
|
1937
|
+
const packagesWithCommits = packages.filter((p) => "reason" in p && p.reason === "commits");
|
|
1938
|
+
const packagesAsDependents = packages.filter((p) => "reason" in p && p.reason === "dependency");
|
|
1939
|
+
const packagesAsGraduation = packages.filter((p) => "reason" in p && p.reason === "graduation");
|
|
1940
|
+
if (packagesWithCommits.length > 0) {
|
|
1941
|
+
logger.log(`${packagesWithCommits.length} package(s) with commits:`);
|
|
1942
|
+
packagesWithCommits.forEach((pkg) => {
|
|
1943
|
+
logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${newVersion} (${pkg.commits.length} commits) ${force ? "(force)" : ""}`);
|
|
1944
|
+
});
|
|
1945
|
+
logger.log("");
|
|
1946
|
+
}
|
|
1947
|
+
if (packagesAsDependents.length > 0) {
|
|
1948
|
+
logger.log(`${packagesAsDependents.length} dependent package(s):`);
|
|
1949
|
+
packagesAsDependents.forEach((pkg) => {
|
|
1950
|
+
logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${newVersion} ${force ? "(force)" : ""}`);
|
|
1951
|
+
});
|
|
1952
|
+
logger.log("");
|
|
1953
|
+
}
|
|
1954
|
+
if (packagesAsGraduation.length > 0) {
|
|
1955
|
+
logger.log(`${packagesAsGraduation.length} graduation package(s):`);
|
|
1956
|
+
packagesAsGraduation.forEach((pkg) => {
|
|
1957
|
+
logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${newVersion} ${force ? "(force)" : ""}`);
|
|
1958
|
+
});
|
|
1959
|
+
logger.log("");
|
|
1960
|
+
}
|
|
2018
1961
|
}
|
|
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
1962
|
}
|
|
2027
|
-
function
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
clearTimeout(timer);
|
|
2036
|
-
resolve(otp);
|
|
2037
|
-
}).catch((error) => {
|
|
2038
|
-
clearTimeout(timer);
|
|
2039
|
-
reject(error);
|
|
1963
|
+
function displayIndependentModePackages({
|
|
1964
|
+
packages,
|
|
1965
|
+
force
|
|
1966
|
+
}) {
|
|
1967
|
+
if (force) {
|
|
1968
|
+
logger.log(`${packages.length} package(s):`);
|
|
1969
|
+
packages.forEach((pkg) => {
|
|
1970
|
+
logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${pkg.newVersion} (force)`);
|
|
2040
1971
|
});
|
|
2041
|
-
|
|
1972
|
+
logger.log("");
|
|
1973
|
+
} else {
|
|
1974
|
+
const packagesWithCommits = packages.filter((p) => "reason" in p && p.reason === "commits");
|
|
1975
|
+
const packagesAsDependents = packages.filter((p) => "reason" in p && p.reason === "dependency");
|
|
1976
|
+
const packagesAsGraduation = packages.filter((p) => "reason" in p && p.reason === "graduation");
|
|
1977
|
+
if (packagesWithCommits.length > 0) {
|
|
1978
|
+
logger.log(`${packagesWithCommits.length} package(s) with commits:`);
|
|
1979
|
+
packagesWithCommits.forEach((pkg) => {
|
|
1980
|
+
pkg.newVersion && logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${pkg.newVersion} (${pkg.commits.length} commits) ${force ? "(force)" : ""}`);
|
|
1981
|
+
});
|
|
1982
|
+
logger.log("");
|
|
1983
|
+
}
|
|
1984
|
+
if (packagesAsDependents.length > 0) {
|
|
1985
|
+
logger.log(`${packagesAsDependents.length} dependent package(s):`);
|
|
1986
|
+
packagesAsDependents.forEach((pkg) => {
|
|
1987
|
+
pkg.newVersion && logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${pkg.newVersion} ${force ? "(force)" : ""}`);
|
|
1988
|
+
});
|
|
1989
|
+
logger.log("");
|
|
1990
|
+
}
|
|
1991
|
+
if (packagesAsGraduation.length > 0) {
|
|
1992
|
+
logger.log(`${packagesAsGraduation.length} graduation package(s):`);
|
|
1993
|
+
packagesAsGraduation.forEach((pkg) => {
|
|
1994
|
+
pkg.newVersion && logger.log(` \u2022 ${pkg.name}: ${pkg.version} \u2192 ${pkg.newVersion} ${force ? "(force)" : ""}`);
|
|
1995
|
+
});
|
|
1996
|
+
logger.log("");
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
2042
1999
|
}
|
|
2043
|
-
async function
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2000
|
+
async function confirmBump({
|
|
2001
|
+
versionMode,
|
|
2002
|
+
config,
|
|
2003
|
+
packages,
|
|
2004
|
+
force,
|
|
2005
|
+
currentVersion,
|
|
2006
|
+
newVersion,
|
|
2007
|
+
dryRun
|
|
2008
|
+
}) {
|
|
2009
|
+
if (packages.length === 0) {
|
|
2010
|
+
logger.debug("No packages to bump");
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
const lernaJsonExists = hasLernaJson(config.cwd);
|
|
2014
|
+
logger.log("");
|
|
2015
|
+
logger.info(`${dryRun ? "[dry-run] " : ""}The following packages will be updated:
|
|
2016
|
+
`);
|
|
2017
|
+
displayRootAndLernaUpdates({
|
|
2018
|
+
versionMode,
|
|
2019
|
+
currentVersion,
|
|
2020
|
+
newVersion,
|
|
2021
|
+
lernaJsonExists,
|
|
2022
|
+
dryRun
|
|
2023
|
+
});
|
|
2024
|
+
if (versionMode === "unified") {
|
|
2025
|
+
if (!newVersion) {
|
|
2026
|
+
throw new Error("Cannot confirm bump in unified mode without a new version");
|
|
2027
|
+
}
|
|
2028
|
+
displayUnifiedModePackages({ packages, newVersion, force });
|
|
2029
|
+
} else if (versionMode === "selective") {
|
|
2030
|
+
if (!newVersion) {
|
|
2031
|
+
throw new Error("Cannot confirm bump in selective mode without a new version");
|
|
2032
|
+
}
|
|
2033
|
+
displaySelectiveModePackages({ packages, newVersion, force });
|
|
2034
|
+
} else if (versionMode === "independent") {
|
|
2035
|
+
displayIndependentModePackages({ packages, force });
|
|
2047
2036
|
}
|
|
2048
|
-
logger.warn("Publish failed: OTP required");
|
|
2049
2037
|
try {
|
|
2050
|
-
const
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2038
|
+
const confirmed = await confirm({
|
|
2039
|
+
message: `${dryRun ? "[dry-run] " : ""}Do you want to proceed with these version updates?`,
|
|
2040
|
+
default: true
|
|
2041
|
+
});
|
|
2042
|
+
if (!confirmed) {
|
|
2043
|
+
logger.log("");
|
|
2044
|
+
logger.fail("Bump refused");
|
|
2045
|
+
process.exit(0);
|
|
2046
|
+
}
|
|
2047
|
+
} catch (error) {
|
|
2048
|
+
const userHasExited = error instanceof Error && error.name === "ExitPromptError";
|
|
2049
|
+
if (userHasExited) {
|
|
2050
|
+
logger.log("");
|
|
2051
|
+
logger.fail("Bump cancelled");
|
|
2052
|
+
process.exit(0);
|
|
2053
|
+
}
|
|
2054
|
+
logger.fail("Error while confirming bump");
|
|
2055
|
+
process.exit(1);
|
|
2056
2056
|
}
|
|
2057
|
+
logger.log("");
|
|
2057
2058
|
}
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
packageNameAndVersion,
|
|
2061
|
-
pkg,
|
|
2062
|
-
config,
|
|
2059
|
+
function getBumpedIndependentPackages({
|
|
2060
|
+
packages,
|
|
2063
2061
|
dryRun
|
|
2064
2062
|
}) {
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
logger.
|
|
2068
|
-
|
|
2063
|
+
const bumpedPackages = [];
|
|
2064
|
+
for (const pkgToBump of packages) {
|
|
2065
|
+
logger.debug(`Bumping ${pkgToBump.name} from ${pkgToBump.version} to ${pkgToBump.newVersion} (reason: ${pkgToBump.reason})`);
|
|
2066
|
+
const result = getBumpedPackageIndependently({
|
|
2067
|
+
pkg: pkgToBump,
|
|
2068
|
+
dryRun
|
|
2069
|
+
});
|
|
2070
|
+
if (result.bumped) {
|
|
2071
|
+
bumpedPackages.push({
|
|
2072
|
+
...pkgToBump,
|
|
2073
|
+
version: result.oldVersion
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2069
2076
|
}
|
|
2070
|
-
|
|
2077
|
+
return bumpedPackages;
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
function getIndependentTag({ version, name }) {
|
|
2081
|
+
return `${name}@${version}`;
|
|
2082
|
+
}
|
|
2083
|
+
async function getLastStableTag({ logLevel, cwd }) {
|
|
2084
|
+
const { stdout } = await execPromise(
|
|
2085
|
+
`git tag --sort=-creatordate | grep -E '^[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+$' | head -n 1`,
|
|
2086
|
+
{
|
|
2087
|
+
logLevel,
|
|
2088
|
+
noStderr: true,
|
|
2089
|
+
noStdout: true,
|
|
2090
|
+
noSuccess: true,
|
|
2091
|
+
cwd
|
|
2092
|
+
}
|
|
2093
|
+
);
|
|
2094
|
+
const lastTag = stdout.trim();
|
|
2095
|
+
logger.debug("Last stable tag:", lastTag || "No stable tags found");
|
|
2096
|
+
return lastTag;
|
|
2097
|
+
}
|
|
2098
|
+
async function getLastTag({ logLevel, cwd }) {
|
|
2099
|
+
const { stdout } = await execPromise(`git tag --sort=-creatordate | head -n 1`, {
|
|
2100
|
+
logLevel,
|
|
2071
2101
|
noStderr: true,
|
|
2072
2102
|
noStdout: true,
|
|
2073
|
-
|
|
2074
|
-
cwd
|
|
2103
|
+
noSuccess: true,
|
|
2104
|
+
cwd
|
|
2075
2105
|
});
|
|
2076
|
-
|
|
2077
|
-
|
|
2106
|
+
const lastTag = stdout.trim();
|
|
2107
|
+
logger.debug("Last tag:", lastTag || "No tags found");
|
|
2108
|
+
return lastTag;
|
|
2109
|
+
}
|
|
2110
|
+
function getLastRepoTag(options) {
|
|
2111
|
+
if (options?.onlyStable) {
|
|
2112
|
+
return getLastStableTag({ logLevel: options?.logLevel, cwd: options?.cwd });
|
|
2078
2113
|
}
|
|
2079
|
-
|
|
2114
|
+
return getLastTag({ logLevel: options?.logLevel, cwd: options?.cwd });
|
|
2080
2115
|
}
|
|
2081
|
-
async function
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2116
|
+
async function getLastPackageTag({
|
|
2117
|
+
packageName,
|
|
2118
|
+
onlyStable,
|
|
2119
|
+
logLevel,
|
|
2120
|
+
cwd
|
|
2086
2121
|
}) {
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
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);
|
|
2122
|
+
try {
|
|
2123
|
+
const escapedPackageName = packageName.replace(/[@/]/g, "\\$&");
|
|
2124
|
+
let grepPattern;
|
|
2125
|
+
if (onlyStable) {
|
|
2126
|
+
grepPattern = `^${escapedPackageName}@[0-9]+\\.[0-9]+\\.[0-9]+$`;
|
|
2127
|
+
} else {
|
|
2128
|
+
grepPattern = `^${escapedPackageName}@`;
|
|
2125
2129
|
}
|
|
2130
|
+
const { stdout } = await execPromise(
|
|
2131
|
+
`git tag --sort=-creatordate | grep -E '${grepPattern}' | sed -n '1p'`,
|
|
2132
|
+
{
|
|
2133
|
+
logLevel,
|
|
2134
|
+
noStderr: true,
|
|
2135
|
+
noStdout: true,
|
|
2136
|
+
noSuccess: true,
|
|
2137
|
+
cwd
|
|
2138
|
+
}
|
|
2139
|
+
);
|
|
2140
|
+
const tag = stdout.trim();
|
|
2141
|
+
return tag || null;
|
|
2142
|
+
} catch {
|
|
2143
|
+
return null;
|
|
2126
2144
|
}
|
|
2127
2145
|
}
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2146
|
+
async function resolveFromTagIndependent({
|
|
2147
|
+
cwd,
|
|
2148
|
+
packageName,
|
|
2149
|
+
graduating,
|
|
2150
|
+
logLevel
|
|
2151
|
+
}) {
|
|
2152
|
+
const lastPackageTag = await getLastPackageTag({
|
|
2153
|
+
packageName,
|
|
2154
|
+
onlyStable: graduating,
|
|
2155
|
+
logLevel
|
|
2156
|
+
});
|
|
2157
|
+
if (!lastPackageTag) {
|
|
2158
|
+
return getFirstCommit(cwd);
|
|
2138
2159
|
}
|
|
2139
|
-
return
|
|
2140
|
-
name: packageJson.name,
|
|
2141
|
-
version: packageJson.version,
|
|
2142
|
-
private: packageJson.private || false,
|
|
2143
|
-
path: packagePath
|
|
2144
|
-
};
|
|
2160
|
+
return lastPackageTag;
|
|
2145
2161
|
}
|
|
2146
|
-
async function
|
|
2162
|
+
async function resolveFromTagUnified({
|
|
2147
2163
|
config,
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
to,
|
|
2151
|
-
suffix,
|
|
2152
|
-
changelog
|
|
2164
|
+
graduating,
|
|
2165
|
+
logLevel
|
|
2153
2166
|
}) {
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
preid: config.bump.preid,
|
|
2170
|
-
types: config.types,
|
|
2171
|
-
force
|
|
2172
|
-
});
|
|
2173
|
-
if (!releaseType) {
|
|
2174
|
-
logger.fail("No commits require a version bump");
|
|
2175
|
-
process.exit(1);
|
|
2176
|
-
}
|
|
2177
|
-
newVersion = getPackageNewVersion({
|
|
2178
|
-
currentVersion: packageJson.version,
|
|
2179
|
-
releaseType,
|
|
2180
|
-
preid: config.bump.preid,
|
|
2181
|
-
suffix
|
|
2182
|
-
});
|
|
2167
|
+
const from = await getLastRepoTag({ onlyStable: graduating, logLevel }) || getFirstCommit(config.cwd);
|
|
2168
|
+
return from;
|
|
2169
|
+
}
|
|
2170
|
+
async function resolveFromTag({
|
|
2171
|
+
config,
|
|
2172
|
+
versionMode,
|
|
2173
|
+
step,
|
|
2174
|
+
packageName,
|
|
2175
|
+
graduating,
|
|
2176
|
+
logLevel
|
|
2177
|
+
}) {
|
|
2178
|
+
let from;
|
|
2179
|
+
if (versionMode === "independent") {
|
|
2180
|
+
if (!packageName) {
|
|
2181
|
+
throw new Error("Package name is required for independent version mode");
|
|
2183
2182
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2183
|
+
from = await resolveFromTagIndependent({
|
|
2184
|
+
cwd: config.cwd,
|
|
2185
|
+
packageName,
|
|
2186
|
+
graduating,
|
|
2187
|
+
logLevel
|
|
2188
|
+
});
|
|
2189
|
+
} else {
|
|
2190
|
+
from = await resolveFromTagUnified({
|
|
2191
|
+
config,
|
|
2192
|
+
graduating,
|
|
2193
|
+
logLevel
|
|
2194
|
+
});
|
|
2194
2195
|
}
|
|
2196
|
+
logger.debug(`[${versionMode}](${step}) Using from tag: ${from}`);
|
|
2197
|
+
return config.from || from;
|
|
2195
2198
|
}
|
|
2196
|
-
function
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2199
|
+
function resolveToTag({
|
|
2200
|
+
config,
|
|
2201
|
+
versionMode,
|
|
2202
|
+
newVersion,
|
|
2203
|
+
step,
|
|
2204
|
+
packageName
|
|
2200
2205
|
}) {
|
|
2201
|
-
const
|
|
2202
|
-
|
|
2203
|
-
if (
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
absolute: true,
|
|
2212
|
-
ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"]
|
|
2213
|
-
});
|
|
2214
|
-
for (const matchPath of matches) {
|
|
2215
|
-
if (foundPaths.has(matchPath))
|
|
2216
|
-
continue;
|
|
2217
|
-
const packageBase = readPackageJson(matchPath);
|
|
2218
|
-
if (!packageBase || packageBase.private || ignorePackageNames?.includes(packageBase.name))
|
|
2219
|
-
continue;
|
|
2220
|
-
foundPaths.add(matchPath);
|
|
2221
|
-
packages.push({
|
|
2222
|
-
...packageBase,
|
|
2223
|
-
path: matchPath
|
|
2224
|
-
});
|
|
2225
|
-
}
|
|
2226
|
-
} catch (error) {
|
|
2227
|
-
logger.error(error);
|
|
2206
|
+
const isUntaggedStep = step === "bump" || step === "changelog";
|
|
2207
|
+
let to;
|
|
2208
|
+
if (isUntaggedStep) {
|
|
2209
|
+
to = getCurrentGitRef(config.cwd);
|
|
2210
|
+
} else if (versionMode === "independent") {
|
|
2211
|
+
if (!packageName) {
|
|
2212
|
+
throw new Error("Package name is required for independent version mode");
|
|
2213
|
+
}
|
|
2214
|
+
if (!newVersion) {
|
|
2215
|
+
throw new Error("New version is required for independent version mode");
|
|
2228
2216
|
}
|
|
2217
|
+
to = getIndependentTag({ version: newVersion, name: packageName });
|
|
2218
|
+
} else {
|
|
2219
|
+
to = newVersion ? config.templates.tagBody.replace("{{newVersion}}", newVersion) : getCurrentGitRef(config.cwd);
|
|
2229
2220
|
}
|
|
2230
|
-
|
|
2221
|
+
logger.debug(`[${versionMode}](${step}) Using to tag: ${to}`);
|
|
2222
|
+
return config.to || to;
|
|
2231
2223
|
}
|
|
2232
|
-
function
|
|
2233
|
-
pkg,
|
|
2224
|
+
async function resolveTags({
|
|
2234
2225
|
config,
|
|
2235
|
-
|
|
2226
|
+
step,
|
|
2227
|
+
pkg,
|
|
2228
|
+
newVersion
|
|
2236
2229
|
}) {
|
|
2230
|
+
const versionMode = config.monorepo?.versionMode || "standalone";
|
|
2231
|
+
const logLevel = config.logLevel;
|
|
2232
|
+
logger.debug(`[${versionMode}](${step}) Resolving tags`);
|
|
2237
2233
|
const releaseType = config.bump.type;
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
});
|
|
2247
|
-
}
|
|
2248
|
-
if (pkg.reason === "dependency") {
|
|
2249
|
-
if (isStableReleaseType(releaseType))
|
|
2250
|
-
return "patch";
|
|
2251
|
-
if (isPrerelease(pkg.version))
|
|
2252
|
-
return "prerelease";
|
|
2253
|
-
return "prepatch";
|
|
2254
|
-
}
|
|
2255
|
-
return determineReleaseType({
|
|
2256
|
-
currentVersion: pkg.version,
|
|
2257
|
-
commits: pkg.commits,
|
|
2258
|
-
releaseType,
|
|
2259
|
-
preid: config.bump.preid,
|
|
2260
|
-
types: config.types,
|
|
2261
|
-
force
|
|
2234
|
+
const graduating = typeof newVersion === "string" ? isGraduatingToStableBetweenVersion(pkg.version, newVersion) : isGraduating(pkg.version, releaseType);
|
|
2235
|
+
const from = await resolveFromTag({
|
|
2236
|
+
config,
|
|
2237
|
+
versionMode,
|
|
2238
|
+
step,
|
|
2239
|
+
packageName: pkg.name,
|
|
2240
|
+
graduating,
|
|
2241
|
+
logLevel
|
|
2262
2242
|
});
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
}) {
|
|
2270
|
-
const readedPackages = readPackages({
|
|
2271
|
-
cwd: config.cwd,
|
|
2272
|
-
patterns,
|
|
2273
|
-
ignorePackageNames: config.monorepo?.ignorePackageNames
|
|
2243
|
+
const to = resolveToTag({
|
|
2244
|
+
config,
|
|
2245
|
+
versionMode,
|
|
2246
|
+
newVersion,
|
|
2247
|
+
step,
|
|
2248
|
+
packageName: pkg.name
|
|
2274
2249
|
});
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
const
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2250
|
+
logger.debug(`[${versionMode}](${step}) Using tags: ${from} \u2192 ${to}`);
|
|
2251
|
+
return { from, to };
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
let sessionOtp;
|
|
2255
|
+
function detectPackageManager(cwd = process.cwd()) {
|
|
2256
|
+
try {
|
|
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}`);
|
|
2295
2272
|
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2273
|
+
}
|
|
2274
|
+
const lockFiles = {
|
|
2275
|
+
pnpm: "pnpm-lock.yaml",
|
|
2276
|
+
yarn: "yarn.lock",
|
|
2277
|
+
npm: "package-lock.json",
|
|
2278
|
+
bun: "bun.lockb"
|
|
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;
|
|
2299
2284
|
}
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
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];
|
|
2303
2292
|
}
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2293
|
+
}
|
|
2294
|
+
logger.debug("No package manager detected, defaulting to npm");
|
|
2295
|
+
return "npm";
|
|
2296
|
+
} catch (error) {
|
|
2297
|
+
logger.fail(`Error detecting package manager: ${error}, defaulting to npm`);
|
|
2298
|
+
return "npm";
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
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);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
return packagesToPublish;
|
|
2325
|
+
}
|
|
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
|
|
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
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
return packagesToPublish;
|
|
2341
|
+
}
|
|
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);
|
|
2333
2368
|
}
|
|
2334
2369
|
}
|
|
2335
|
-
const
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
allPackages: packagesArray,
|
|
2339
|
-
packagesWithCommits
|
|
2340
|
-
});
|
|
2341
|
-
for (const pkg of expandedPackages) {
|
|
2342
|
-
packages.set(pkg.name, pkg);
|
|
2370
|
+
const finalOtp = otp ?? sessionOtp ?? config.publish.otp;
|
|
2371
|
+
if (finalOtp) {
|
|
2372
|
+
args.push("--otp", finalOtp);
|
|
2343
2373
|
}
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
pkg,
|
|
2347
|
-
config,
|
|
2348
|
-
force
|
|
2349
|
-
});
|
|
2350
|
-
const newVersion = releaseType ? getPackageNewVersion({
|
|
2351
|
-
currentVersion: pkg.version,
|
|
2352
|
-
releaseType,
|
|
2353
|
-
preid: config.bump.preid,
|
|
2354
|
-
suffix
|
|
2355
|
-
}) : void 0;
|
|
2356
|
-
const graduating = releaseType && isGraduating(pkg.version, releaseType) || isChangedPreid(pkg.version, config.bump.preid);
|
|
2357
|
-
packages.set(pkg.name, {
|
|
2358
|
-
...pkg,
|
|
2359
|
-
newVersion,
|
|
2360
|
-
reason: pkg.reason || releaseType && graduating && "graduation" || void 0
|
|
2361
|
-
});
|
|
2374
|
+
if (type === "auth") {
|
|
2375
|
+
return args;
|
|
2362
2376
|
}
|
|
2363
|
-
const
|
|
2364
|
-
if (
|
|
2365
|
-
|
|
2366
|
-
return [];
|
|
2377
|
+
const access = config.publish.access;
|
|
2378
|
+
if (access) {
|
|
2379
|
+
args.push("--access", access);
|
|
2367
2380
|
}
|
|
2368
|
-
|
|
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;
|
|
2369
2391
|
}
|
|
2370
|
-
function
|
|
2371
|
-
|
|
2372
|
-
type,
|
|
2373
|
-
changelog
|
|
2374
|
-
}) {
|
|
2375
|
-
if (commit.type === "chore" && ["deps", "release"].includes(commit.scope) && !commit.isBreaking) {
|
|
2392
|
+
function isOtpError(error) {
|
|
2393
|
+
if (typeof error !== "object" || error === null)
|
|
2376
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");
|
|
2377
2418
|
}
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
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;
|
|
2383
2427
|
}
|
|
2384
|
-
return false;
|
|
2385
2428
|
}
|
|
2386
|
-
async function
|
|
2429
|
+
async function executePublishCommand({
|
|
2430
|
+
command,
|
|
2431
|
+
packageNameAndVersion,
|
|
2387
2432
|
pkg,
|
|
2388
|
-
from,
|
|
2389
|
-
to,
|
|
2390
2433
|
config,
|
|
2391
|
-
|
|
2434
|
+
tag,
|
|
2435
|
+
dryRun
|
|
2392
2436
|
}) {
|
|
2393
|
-
logger.
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
const commits = allCommits.filter((commit) => {
|
|
2405
|
-
const type = changelogConfig?.types[commit.type];
|
|
2406
|
-
if (!isAllowedCommit({ commit, type, changelog })) {
|
|
2407
|
-
return false;
|
|
2408
|
-
}
|
|
2409
|
-
if (pkg.path === changelogConfig.cwd || pkg.name === rootPackage.name) {
|
|
2410
|
-
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);
|
|
2411
2448
|
}
|
|
2412
|
-
const packageRelativePath = relative(changelogConfig.cwd, pkg.path);
|
|
2413
|
-
const scopeMatches = commit.scope === pkg.name;
|
|
2414
|
-
const bodyContainsPath = commit.body.includes(packageRelativePath);
|
|
2415
|
-
return scopeMatches || bodyContainsPath;
|
|
2416
|
-
});
|
|
2417
|
-
logger.debug(`Found ${commits.length} commit(s) for ${pkg.name} from ${from} to ${to}`);
|
|
2418
|
-
if (commits.length > 0) {
|
|
2419
|
-
logger.debug(`${pkg.name}: ${commits.length} commit(s) found`);
|
|
2420
|
-
} else {
|
|
2421
|
-
logger.debug(`${pkg.name}: No commits found`);
|
|
2422
2449
|
}
|
|
2423
|
-
|
|
2450
|
+
logger.info(`${dryRun ? "[dry-run] " : ""}Published ${packageNameAndVersion}`);
|
|
2424
2451
|
}
|
|
2425
|
-
function
|
|
2426
|
-
|
|
2427
|
-
|
|
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
|
+
}
|
|
2428
2526
|
}
|
|
2429
2527
|
|
|
2430
2528
|
async function bumpUnifiedMode({
|
|
@@ -2435,6 +2533,9 @@ async function bumpUnifiedMode({
|
|
|
2435
2533
|
}) {
|
|
2436
2534
|
logger.debug("Starting bump in unified mode");
|
|
2437
2535
|
const rootPackageBase = readPackageJson(config.cwd);
|
|
2536
|
+
if (!rootPackageBase) {
|
|
2537
|
+
throw new Error("Failed to read root package.json");
|
|
2538
|
+
}
|
|
2438
2539
|
const { from, to } = await resolveTags({
|
|
2439
2540
|
config,
|
|
2440
2541
|
step: "bump",
|
|
@@ -2514,6 +2615,9 @@ async function bumpSelectiveMode({
|
|
|
2514
2615
|
}) {
|
|
2515
2616
|
logger.debug("Starting bump in selective mode");
|
|
2516
2617
|
const rootPackageBase = readPackageJson(config.cwd);
|
|
2618
|
+
if (!rootPackageBase) {
|
|
2619
|
+
throw new Error("Failed to read root package.json");
|
|
2620
|
+
}
|
|
2517
2621
|
const { from, to } = await resolveTags({
|
|
2518
2622
|
config,
|
|
2519
2623
|
step: "bump",
|
|
@@ -2716,22 +2820,6 @@ async function bump(options = {}) {
|
|
|
2716
2820
|
}
|
|
2717
2821
|
}
|
|
2718
2822
|
|
|
2719
|
-
async function getPackagesToGenerateChangelogFor({
|
|
2720
|
-
config,
|
|
2721
|
-
bumpResult,
|
|
2722
|
-
suffix,
|
|
2723
|
-
force
|
|
2724
|
-
}) {
|
|
2725
|
-
if (bumpResult?.bumpedPackages && bumpResult.bumpedPackages.length > 0) {
|
|
2726
|
-
return bumpResult.bumpedPackages;
|
|
2727
|
-
}
|
|
2728
|
-
return await getPackages({
|
|
2729
|
-
config,
|
|
2730
|
-
patterns: config.monorepo?.packages,
|
|
2731
|
-
suffix,
|
|
2732
|
-
force
|
|
2733
|
-
});
|
|
2734
|
-
}
|
|
2735
2823
|
async function generateIndependentRootChangelog({
|
|
2736
2824
|
packages,
|
|
2737
2825
|
config,
|
|
@@ -2763,10 +2851,13 @@ async function generateIndependentRootChangelog({
|
|
|
2763
2851
|
|
|
2764
2852
|
${packageChangelogs.join("\n\n")}`;
|
|
2765
2853
|
logger.verbose(`Aggregated root changelog: ${aggregatedChangelog}`);
|
|
2766
|
-
const
|
|
2854
|
+
const rootPackageRead = readPackageJson(config.cwd);
|
|
2855
|
+
if (!rootPackageRead) {
|
|
2856
|
+
throw new Error("Failed to read root package.json");
|
|
2857
|
+
}
|
|
2767
2858
|
writeChangelogToFile({
|
|
2768
2859
|
cwd: config.cwd,
|
|
2769
|
-
pkg:
|
|
2860
|
+
pkg: rootPackageRead,
|
|
2770
2861
|
changelog: aggregatedChangelog,
|
|
2771
2862
|
dryRun
|
|
2772
2863
|
});
|
|
@@ -2785,10 +2876,14 @@ async function generateSimpleRootChangelog({
|
|
|
2785
2876
|
}
|
|
2786
2877
|
logger.debug("Generating simple root changelog");
|
|
2787
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;
|
|
2788
2883
|
const { from, to } = await resolveTags({
|
|
2789
2884
|
config,
|
|
2790
2885
|
step: "changelog",
|
|
2791
|
-
newVersion
|
|
2886
|
+
newVersion,
|
|
2792
2887
|
pkg: rootPackageRead
|
|
2793
2888
|
});
|
|
2794
2889
|
const fromTag = bumpResult?.fromTag || from;
|
|
@@ -2801,7 +2896,6 @@ async function generateSimpleRootChangelog({
|
|
|
2801
2896
|
to
|
|
2802
2897
|
});
|
|
2803
2898
|
logger.debug(`Generating ${rootPackage.name} changelog (${fromTag}...${to})`);
|
|
2804
|
-
const newVersion = bumpResult?.newVersion || rootPackage.version;
|
|
2805
2899
|
const rootChangelog = await generateChangelog({
|
|
2806
2900
|
pkg: rootPackage,
|
|
2807
2901
|
config,
|
|
@@ -2842,7 +2936,7 @@ async function changelog(options = {}) {
|
|
|
2842
2936
|
logger.start("Start generating changelogs");
|
|
2843
2937
|
if (config.changelog?.rootChangelog && config.monorepo) {
|
|
2844
2938
|
if (config.monorepo.versionMode === "independent") {
|
|
2845
|
-
const packages2 = await
|
|
2939
|
+
const packages2 = await getPackagesOrBumpedPackages({
|
|
2846
2940
|
config,
|
|
2847
2941
|
bumpResult: options.bumpResult,
|
|
2848
2942
|
suffix: options.suffix,
|
|
@@ -2866,27 +2960,28 @@ async function changelog(options = {}) {
|
|
|
2866
2960
|
logger.debug("Skipping root changelog generation");
|
|
2867
2961
|
}
|
|
2868
2962
|
logger.debug("Generating package changelogs...");
|
|
2869
|
-
const packages =
|
|
2963
|
+
const packages = await getPackagesOrBumpedPackages({
|
|
2870
2964
|
config,
|
|
2871
|
-
|
|
2965
|
+
bumpResult: options.bumpResult,
|
|
2872
2966
|
suffix: options.suffix,
|
|
2873
2967
|
force: options.force ?? false
|
|
2874
2968
|
});
|
|
2875
2969
|
logger.debug(`Processing ${packages.length} package(s)`);
|
|
2876
2970
|
let generatedCount = 0;
|
|
2877
2971
|
for await (const pkg of packages) {
|
|
2972
|
+
const newVersion = options.bumpResult?.bumpedPackages?.find((p) => p.name === pkg.name)?.newVersion || pkg.newVersion || pkg.version;
|
|
2878
2973
|
const { from, to } = await resolveTags({
|
|
2879
2974
|
config,
|
|
2880
2975
|
step: "changelog",
|
|
2881
2976
|
pkg,
|
|
2882
|
-
newVersion
|
|
2977
|
+
newVersion
|
|
2883
2978
|
});
|
|
2884
2979
|
logger.debug(`Processing ${pkg.name} (${from}...${to})`);
|
|
2885
2980
|
const changelog2 = await generateChangelog({
|
|
2886
2981
|
pkg,
|
|
2887
2982
|
config,
|
|
2888
2983
|
dryRun,
|
|
2889
|
-
newVersion
|
|
2984
|
+
newVersion
|
|
2890
2985
|
});
|
|
2891
2986
|
if (changelog2) {
|
|
2892
2987
|
writeChangelogToFile({
|
|
@@ -2926,11 +3021,11 @@ function providerReleaseSafetyCheck({ config, provider }) {
|
|
|
2926
3021
|
} else if (internalProvider === "gitlab") {
|
|
2927
3022
|
token = config.tokens?.gitlab || config.repo?.token;
|
|
2928
3023
|
} else {
|
|
2929
|
-
logger.error(`Unsupported Git provider: ${internalProvider || "unknown"}`);
|
|
3024
|
+
logger.error(`[provider-release-safety-check] Unsupported Git provider: ${internalProvider || "unknown"}`);
|
|
2930
3025
|
process.exit(1);
|
|
2931
3026
|
}
|
|
2932
3027
|
if (!token) {
|
|
2933
|
-
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`);
|
|
2934
3029
|
process.exit(1);
|
|
2935
3030
|
}
|
|
2936
3031
|
}
|
|
@@ -2997,6 +3092,40 @@ async function providerRelease(options = {}) {
|
|
|
2997
3092
|
}
|
|
2998
3093
|
}
|
|
2999
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
|
+
}
|
|
3000
3129
|
async function publish(options = {}) {
|
|
3001
3130
|
const config = await loadRelizyConfig({
|
|
3002
3131
|
configName: options.configName,
|
|
@@ -3007,14 +3136,16 @@ async function publish(options = {}) {
|
|
|
3007
3136
|
otp: options.otp,
|
|
3008
3137
|
registry: options.registry,
|
|
3009
3138
|
tag: options.tag,
|
|
3010
|
-
buildCmd: options.buildCmd
|
|
3139
|
+
buildCmd: options.buildCmd,
|
|
3140
|
+
token: options.token
|
|
3011
3141
|
},
|
|
3012
|
-
logLevel: options.logLevel
|
|
3142
|
+
logLevel: options.logLevel,
|
|
3143
|
+
safetyCheck: options.safetyCheck
|
|
3013
3144
|
}
|
|
3014
3145
|
});
|
|
3015
3146
|
const dryRun = options.dryRun ?? false;
|
|
3016
3147
|
logger.debug(`Dry run: ${dryRun}`);
|
|
3017
|
-
const packageManager = detectPackageManager(
|
|
3148
|
+
const packageManager = config.publish.packageManager || detectPackageManager(config.cwd);
|
|
3018
3149
|
logger.debug(`Package manager: ${packageManager}`);
|
|
3019
3150
|
logger.info(`Version mode: ${config.monorepo?.versionMode || "standalone"}`);
|
|
3020
3151
|
if (config.publish.registry) {
|
|
@@ -3025,11 +3156,15 @@ async function publish(options = {}) {
|
|
|
3025
3156
|
}
|
|
3026
3157
|
try {
|
|
3027
3158
|
await executeHook("before:publish", config, dryRun);
|
|
3159
|
+
await publishSafetyCheck({ config });
|
|
3028
3160
|
const rootPackage = readPackageJson(config.cwd);
|
|
3161
|
+
if (!rootPackage) {
|
|
3162
|
+
throw new Error("Failed to read root package.json");
|
|
3163
|
+
}
|
|
3029
3164
|
logger.start("Start publishing packages");
|
|
3030
|
-
const packages =
|
|
3165
|
+
const packages = await getPackagesOrBumpedPackages({
|
|
3031
3166
|
config,
|
|
3032
|
-
|
|
3167
|
+
bumpResult: options.bumpResult,
|
|
3033
3168
|
suffix: options.suffix,
|
|
3034
3169
|
force: options.force ?? false
|
|
3035
3170
|
});
|
|
@@ -3113,7 +3248,8 @@ function getReleaseConfig(options = {}) {
|
|
|
3113
3248
|
otp: options.otp,
|
|
3114
3249
|
registry: options.registry,
|
|
3115
3250
|
tag: options.tag,
|
|
3116
|
-
buildCmd: options.buildCmd
|
|
3251
|
+
buildCmd: options.buildCmd,
|
|
3252
|
+
token: options.publishToken
|
|
3117
3253
|
},
|
|
3118
3254
|
release: {
|
|
3119
3255
|
commit: options.commit,
|
|
@@ -3129,7 +3265,7 @@ function getReleaseConfig(options = {}) {
|
|
|
3129
3265
|
}
|
|
3130
3266
|
});
|
|
3131
3267
|
}
|
|
3132
|
-
function releaseSafetyCheck({
|
|
3268
|
+
async function releaseSafetyCheck({
|
|
3133
3269
|
config,
|
|
3134
3270
|
provider
|
|
3135
3271
|
}) {
|
|
@@ -3137,6 +3273,7 @@ function releaseSafetyCheck({
|
|
|
3137
3273
|
return;
|
|
3138
3274
|
}
|
|
3139
3275
|
providerReleaseSafetyCheck({ config, provider });
|
|
3276
|
+
await publishSafetyCheck({ config });
|
|
3140
3277
|
}
|
|
3141
3278
|
async function release(options = {}) {
|
|
3142
3279
|
const dryRun = options.dryRun ?? false;
|
|
@@ -3146,7 +3283,7 @@ async function release(options = {}) {
|
|
|
3146
3283
|
const config = await getReleaseConfig(options);
|
|
3147
3284
|
logger.debug(`Version mode: ${config.monorepo?.versionMode || "standalone"}`);
|
|
3148
3285
|
logger.debug(`Push: ${config.release.push}, Publish: ${config.release.publish}, Provider Release: ${config.release.providerRelease}`);
|
|
3149
|
-
releaseSafetyCheck({ config, provider: options.provider });
|
|
3286
|
+
await releaseSafetyCheck({ config, provider: options.provider });
|
|
3150
3287
|
try {
|
|
3151
3288
|
await executeHook("before:release", config, dryRun);
|
|
3152
3289
|
logger.box("Step 1/6: Bump versions");
|
|
@@ -3222,7 +3359,7 @@ async function release(options = {}) {
|
|
|
3222
3359
|
tag: config.publish.tag,
|
|
3223
3360
|
access: config.publish.access,
|
|
3224
3361
|
otp: config.publish.otp,
|
|
3225
|
-
|
|
3362
|
+
bumpResult,
|
|
3226
3363
|
dryRun,
|
|
3227
3364
|
config,
|
|
3228
3365
|
configName: options.configName,
|
|
@@ -3260,10 +3397,10 @@ async function release(options = {}) {
|
|
|
3260
3397
|
logger.info("Skipping release (--no-provider-release)");
|
|
3261
3398
|
}
|
|
3262
3399
|
const publishedPackageCount = publishResponse?.publishedPackages.length ?? 0;
|
|
3263
|
-
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;
|
|
3264
3401
|
logger.box(`Release workflow completed!
|
|
3265
3402
|
|
|
3266
|
-
Version: ${versionDisplay}
|
|
3403
|
+
Version: ${versionDisplay ?? "Unknown"}
|
|
3267
3404
|
Tag(s): ${createdTags.length ? createdTags.join(", ") : "No"}
|
|
3268
3405
|
Pushed: ${config.release.push ? "Yes" : "Disabled"}
|
|
3269
3406
|
Published packages: ${config.release.publish ? publishedPackageCount : "Disabled"}
|
|
@@ -3277,4 +3414,4 @@ Git provider: ${provider}`);
|
|
|
3277
3414
|
}
|
|
3278
3415
|
}
|
|
3279
3416
|
|
|
3280
|
-
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 };
|