1 | 'use strict';
|
2 |
|
3 | var fs = require('fs-extra');
|
4 | var chalk = require('chalk');
|
5 | var ora = require('ora');
|
6 | var semver = require('semver');
|
7 | var minimatch = require('minimatch');
|
8 | var errors = require('@backstage/errors');
|
9 | var path = require('path');
|
10 | var run = require('./run-a95417b1.cjs.js');
|
11 | var index = require('./index-09611511.cjs.js');
|
12 | var Lockfile = require('./Lockfile-48dc675e.cjs.js');
|
13 | var packages = require('./packages-f8fc8f67.cjs.js');
|
14 | var lint = require('./lint-08d4074b.cjs.js');
|
15 | var cliCommon = require('@backstage/cli-common');
|
16 | var parallel = require('./parallel-8286d3fa.cjs.js');
|
17 | var releaseManifests = require('@backstage/release-manifests');
|
18 | require('global-agent/bootstrap');
|
19 | require('child_process');
|
20 | require('util');
|
21 | require('commander');
|
22 | require('@yarnpkg/parsers');
|
23 | require('@yarnpkg/lockfile');
|
24 | require('@manypkg/get-packages');
|
25 | require('lodash/partition');
|
26 | require('os');
|
27 | require('worker_threads');
|
28 |
|
29 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
30 |
|
31 | var fs__default = _interopDefaultLegacy(fs);
|
32 | var chalk__default = _interopDefaultLegacy(chalk);
|
33 | var ora__default = _interopDefaultLegacy(ora);
|
34 | var semver__default = _interopDefaultLegacy(semver);
|
35 | var minimatch__default = _interopDefaultLegacy(minimatch);
|
36 |
|
37 | const DEP_TYPES = [
|
38 | "dependencies",
|
39 | "devDependencies",
|
40 | "peerDependencies",
|
41 | "optionalDependencies"
|
42 | ];
|
43 | const DEFAULT_PATTERN_GLOB = "@backstage/*";
|
44 | var bump = async (opts) => {
|
45 | var _a;
|
46 | const lockfilePath = index.paths.resolveTargetRoot("yarn.lock");
|
47 | const lockfile = await Lockfile.Lockfile.load(lockfilePath);
|
48 | let pattern = opts.pattern;
|
49 | if (!pattern) {
|
50 | console.log(`Using default pattern glob ${DEFAULT_PATTERN_GLOB}`);
|
51 | pattern = DEFAULT_PATTERN_GLOB;
|
52 | } else {
|
53 | console.log(`Using custom pattern glob ${pattern}`);
|
54 | }
|
55 | let findTargetVersion;
|
56 | let releaseManifest;
|
57 | if (semver__default["default"].valid(opts.release)) {
|
58 | releaseManifest = await releaseManifests.getManifestByVersion({ version: opts.release });
|
59 | findTargetVersion = createStrictVersionFinder({
|
60 | releaseManifest
|
61 | });
|
62 | } else {
|
63 | if (opts.release === "next") {
|
64 | const next = await releaseManifests.getManifestByReleaseLine({
|
65 | releaseLine: "next"
|
66 | });
|
67 | const main = await releaseManifests.getManifestByReleaseLine({
|
68 | releaseLine: "main"
|
69 | });
|
70 | releaseManifest = semver__default["default"].gt(next.releaseVersion, main.releaseVersion) ? next : main;
|
71 | } else {
|
72 | releaseManifest = await releaseManifests.getManifestByReleaseLine({
|
73 | releaseLine: opts.release
|
74 | });
|
75 | }
|
76 | findTargetVersion = createVersionFinder({
|
77 | releaseLine: opts.releaseLine,
|
78 | releaseManifest
|
79 | });
|
80 | }
|
81 | const dependencyMap = await packages.mapDependencies(index.paths.targetDir, pattern);
|
82 | const versionBumps = new Map();
|
83 | const unlocked = Array();
|
84 | await parallel.runParallelWorkers({
|
85 | parallelismFactor: 4,
|
86 | items: dependencyMap.entries(),
|
87 | async worker([name, pkgs]) {
|
88 | var _a2, _b;
|
89 | let target;
|
90 | try {
|
91 | target = await findTargetVersion(name);
|
92 | } catch (error) {
|
93 | if (errors.isError(error) && error.name === "NotFoundError") {
|
94 | console.log(`Package info not found, ignoring package ${name}`);
|
95 | return;
|
96 | }
|
97 | throw error;
|
98 | }
|
99 | for (const pkg of pkgs) {
|
100 | if (semver__default["default"].satisfies(target, pkg.range)) {
|
101 | if (((_a2 = semver__default["default"].minVersion(pkg.range)) == null ? void 0 : _a2.version) !== target) {
|
102 | unlocked.push({ name, range: pkg.range, target });
|
103 | }
|
104 | continue;
|
105 | }
|
106 | versionBumps.set(pkg.name, ((_b = versionBumps.get(pkg.name)) != null ? _b : []).concat({
|
107 | name,
|
108 | location: pkg.location,
|
109 | range: `^${target}`,
|
110 | target
|
111 | }));
|
112 | }
|
113 | }
|
114 | });
|
115 | const filter = (name) => minimatch__default["default"](name, pattern);
|
116 | await parallel.runParallelWorkers({
|
117 | parallelismFactor: 4,
|
118 | items: lockfile.keys(),
|
119 | async worker(name) {
|
120 | var _a2;
|
121 | if (!filter(name)) {
|
122 | return;
|
123 | }
|
124 | let target;
|
125 | try {
|
126 | target = await findTargetVersion(name);
|
127 | } catch (error) {
|
128 | if (errors.isError(error) && error.name === "NotFoundError") {
|
129 | console.log(`Package info not found, ignoring package ${name}`);
|
130 | return;
|
131 | }
|
132 | throw error;
|
133 | }
|
134 | for (const entry of (_a2 = lockfile.get(name)) != null ? _a2 : []) {
|
135 | if (!semver__default["default"].satisfies(target, entry.range)) {
|
136 | continue;
|
137 | }
|
138 | unlocked.push({ name, range: entry.range, target });
|
139 | }
|
140 | }
|
141 | });
|
142 | console.log();
|
143 | if (versionBumps.size === 0 && unlocked.length === 0) {
|
144 | console.log(chalk__default["default"].green("All Backstage packages are up to date!"));
|
145 | } else {
|
146 | console.log(chalk__default["default"].yellow("Some packages are outdated, updating"));
|
147 | console.log();
|
148 | if (unlocked.length > 0) {
|
149 | const removed = new Set();
|
150 | for (const { name, range, target } of unlocked) {
|
151 | const existingEntry = (_a = lockfile.get(name)) == null ? void 0 : _a.find((e) => e.range === range);
|
152 | if ((existingEntry == null ? void 0 : existingEntry.version) === target) {
|
153 | continue;
|
154 | }
|
155 | const key = JSON.stringify({ name, range });
|
156 | if (!removed.has(key)) {
|
157 | removed.add(key);
|
158 | console.log(`${chalk__default["default"].magenta("unlocking")} ${name}@${chalk__default["default"].yellow(range)} ~> ${chalk__default["default"].yellow(target)}`);
|
159 | lockfile.remove(name, range);
|
160 | }
|
161 | }
|
162 | await lockfile.save();
|
163 | }
|
164 | const breakingUpdates = new Map();
|
165 | await parallel.runParallelWorkers({
|
166 | parallelismFactor: 4,
|
167 | items: versionBumps.entries(),
|
168 | async worker([name, deps]) {
|
169 | var _a2;
|
170 | const pkgPath = path.resolve(deps[0].location, "package.json");
|
171 | const pkgJson = await fs__default["default"].readJson(pkgPath);
|
172 | for (const dep of deps) {
|
173 | console.log(`${chalk__default["default"].cyan("bumping")} ${dep.name} in ${chalk__default["default"].cyan(name)} to ${chalk__default["default"].yellow(dep.range)}`);
|
174 | for (const depType of DEP_TYPES) {
|
175 | if (depType in pkgJson && dep.name in pkgJson[depType]) {
|
176 | const oldRange = pkgJson[depType][dep.name];
|
177 | pkgJson[depType][dep.name] = dep.range;
|
178 | const lockfileEntry = (_a2 = lockfile.get(dep.name)) == null ? void 0 : _a2.find((entry) => entry.range === oldRange);
|
179 | if (lockfileEntry) {
|
180 | const from = lockfileEntry.version;
|
181 | const to = dep.target;
|
182 | if (!semver__default["default"].satisfies(to, `^${from}`)) {
|
183 | breakingUpdates.set(dep.name, { from, to });
|
184 | }
|
185 | }
|
186 | }
|
187 | }
|
188 | }
|
189 | await fs__default["default"].writeJson(pkgPath, pkgJson, { spaces: 2 });
|
190 | }
|
191 | });
|
192 | console.log();
|
193 | if (pattern === DEFAULT_PATTERN_GLOB) {
|
194 | await bumpBackstageJsonVersion(releaseManifest.releaseVersion);
|
195 | } else {
|
196 | console.log(chalk__default["default"].yellow(`Skipping backstage.json update as custom pattern is used`));
|
197 | }
|
198 | await runYarnInstall();
|
199 | if (breakingUpdates.size > 0) {
|
200 | console.log();
|
201 | console.log(chalk__default["default"].yellow("\u26A0\uFE0F The following packages may have breaking changes:"));
|
202 | console.log();
|
203 | for (const [name, { from, to }] of Array.from(breakingUpdates.entries()).sort()) {
|
204 | console.log(` ${chalk__default["default"].yellow(name)} : ${chalk__default["default"].yellow(from)} ~> ${chalk__default["default"].yellow(to)}`);
|
205 | let path;
|
206 | if (name.startsWith("@backstage/plugin-")) {
|
207 | path = `plugins/${name.replace("@backstage/plugin-", "")}`;
|
208 | } else if (name.startsWith("@backstage/")) {
|
209 | path = `packages/${name.replace("@backstage/", "")}`;
|
210 | }
|
211 | if (path) {
|
212 | console.log(` https://github.com/backstage/backstage/blob/master/${path}/CHANGELOG.md`);
|
213 | }
|
214 | console.log();
|
215 | }
|
216 | } else {
|
217 | console.log();
|
218 | }
|
219 | console.log(chalk__default["default"].green("Version bump complete!"));
|
220 | }
|
221 | console.log();
|
222 | const dedupLockfile = await Lockfile.Lockfile.load(lockfilePath);
|
223 | const result = dedupLockfile.analyze({
|
224 | filter
|
225 | });
|
226 | if (result.newVersions.length > 0) {
|
227 | throw new Error("Duplicate versions present after package bump");
|
228 | }
|
229 | const forbiddenNewRanges = result.newRanges.filter(({ name }) => lint.forbiddenDuplicatesFilter(name));
|
230 | if (forbiddenNewRanges.length > 0) {
|
231 | throw new Error(`Version bump failed for ${forbiddenNewRanges.map((i) => i.name).join(", ")}`);
|
232 | }
|
233 | };
|
234 | function createStrictVersionFinder(options) {
|
235 | const releasePackages = new Map(options.releaseManifest.packages.map((p) => [p.name, p.version]));
|
236 | return async function findTargetVersion(name) {
|
237 | console.log(`Checking for updates of ${name}`);
|
238 | const manifestVersion = releasePackages.get(name);
|
239 | if (manifestVersion) {
|
240 | return manifestVersion;
|
241 | }
|
242 | throw new errors.NotFoundError(`Package ${name} not found in release manifest`);
|
243 | };
|
244 | }
|
245 | function createVersionFinder(options) {
|
246 | const {
|
247 | releaseLine = "latest",
|
248 | packageInfoFetcher = packages.fetchPackageInfo,
|
249 | releaseManifest
|
250 | } = options;
|
251 | const distTag = releaseLine === "main" ? "latest" : releaseLine;
|
252 | const found = new Map();
|
253 | const releasePackages = new Map(releaseManifest == null ? void 0 : releaseManifest.packages.map((p) => [p.name, p.version]));
|
254 | return async function findTargetVersion(name) {
|
255 | const existing = found.get(name);
|
256 | if (existing) {
|
257 | return existing;
|
258 | }
|
259 | console.log(`Checking for updates of ${name}`);
|
260 | const manifestVersion = releasePackages.get(name);
|
261 | if (manifestVersion) {
|
262 | return manifestVersion;
|
263 | }
|
264 | const info = await packageInfoFetcher(name);
|
265 | const latestVersion = info["dist-tags"].latest;
|
266 | if (!latestVersion) {
|
267 | throw new Error(`No target 'latest' version found for ${name}`);
|
268 | }
|
269 | const taggedVersion = info["dist-tags"][distTag];
|
270 | if (distTag === "latest" || !taggedVersion) {
|
271 | found.set(name, latestVersion);
|
272 | return latestVersion;
|
273 | }
|
274 | const latestVersionDateStr = info.time[latestVersion];
|
275 | const taggedVersionDateStr = info.time[taggedVersion];
|
276 | if (!latestVersionDateStr) {
|
277 | throw new Error(`No time available for version '${latestVersion}' of ${name}`);
|
278 | }
|
279 | if (!taggedVersionDateStr) {
|
280 | throw new Error(`No time available for version '${taggedVersion}' of ${name}`);
|
281 | }
|
282 | const latestVersionRelease = new Date(latestVersionDateStr).getTime();
|
283 | const taggedVersionRelease = new Date(taggedVersionDateStr).getTime();
|
284 | if (latestVersionRelease > taggedVersionRelease) {
|
285 | found.set(name, latestVersion);
|
286 | return latestVersion;
|
287 | }
|
288 | found.set(name, taggedVersion);
|
289 | return taggedVersion;
|
290 | };
|
291 | }
|
292 | async function bumpBackstageJsonVersion(version) {
|
293 | const backstageJsonPath = index.paths.resolveTargetRoot(cliCommon.BACKSTAGE_JSON);
|
294 | const backstageJson = await fs__default["default"].readJSON(backstageJsonPath).catch((e) => {
|
295 | if (e.code === "ENOENT") {
|
296 | return;
|
297 | }
|
298 | throw e;
|
299 | });
|
300 | const prevVersion = backstageJson == null ? void 0 : backstageJson.version;
|
301 | if (prevVersion === version) {
|
302 | return;
|
303 | }
|
304 | const { yellow, cyan, green } = chalk__default["default"];
|
305 | if (prevVersion) {
|
306 | const from = encodeURIComponent(prevVersion);
|
307 | const to = encodeURIComponent(version);
|
308 | const link = `https://backstage.github.io/upgrade-helper/?from=${from}&to=${to}`;
|
309 | console.log(yellow(`Upgraded from release ${green(prevVersion)} to ${green(version)}, please review these template changes:`));
|
310 | console.log();
|
311 | console.log(` ${cyan(link)}`);
|
312 | console.log();
|
313 | } else {
|
314 | console.log(yellow(`Your project is now at version ${version}, which has been written to ${cliCommon.BACKSTAGE_JSON}`));
|
315 | }
|
316 | await fs__default["default"].writeJson(backstageJsonPath, { ...backstageJson, version }, {
|
317 | spaces: 2,
|
318 | encoding: "utf8"
|
319 | });
|
320 | }
|
321 | async function runYarnInstall() {
|
322 | const spinner = ora__default["default"]({
|
323 | prefixText: `Running ${chalk__default["default"].blue("yarn install")} to install new versions`,
|
324 | spinner: "arc",
|
325 | color: "green"
|
326 | }).start();
|
327 | const installOutput = new Array();
|
328 | try {
|
329 | await run.run("yarn", ["install"], {
|
330 | env: {
|
331 | FORCE_COLOR: "true",
|
332 | ...Object.fromEntries(Object.entries(process.env).map(([name, value]) => name.startsWith("npm_") ? [name, void 0] : [name, value]))
|
333 | },
|
334 | stdoutLogFunc: (data) => installOutput.push(data),
|
335 | stderrLogFunc: (data) => installOutput.push(data)
|
336 | });
|
337 | spinner.succeed();
|
338 | } catch (error) {
|
339 | spinner.fail();
|
340 | process.stdout.write(Buffer.concat(installOutput));
|
341 | throw error;
|
342 | }
|
343 | }
|
344 |
|
345 | exports.bumpBackstageJsonVersion = bumpBackstageJsonVersion;
|
346 | exports.createStrictVersionFinder = createStrictVersionFinder;
|
347 | exports.createVersionFinder = createVersionFinder;
|
348 | exports["default"] = bump;
|
349 |
|