'use strict'; var fs = require('fs-extra'); var chalk = require('chalk'); var ora = require('ora'); var semver = require('semver'); var minimatch = require('minimatch'); var errors = require('@backstage/errors'); var path = require('path'); var run = require('./run-BcxUFacd.cjs.js'); var index = require('./index-CCLafGQH.cjs.js'); var Lockfile = require('./Lockfile-C7rtIlD6.cjs.js'); var packages = require('./packages-O225IQzG.cjs.js'); var lint = require('./lint-BHw1vR1K.cjs.js'); var cliCommon = require('@backstage/cli-common'); var parallel = require('./parallel-BszNaKyc.cjs.js'); var releaseManifests = require('@backstage/release-manifests'); require('global-agent/bootstrap'); var cliNode = require('@backstage/cli-node'); var replace = require('replace-in-file'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } var fs__default = /*#__PURE__*/_interopDefaultCompat(fs); var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk); var ora__default = /*#__PURE__*/_interopDefaultCompat(ora); var semver__default = /*#__PURE__*/_interopDefaultCompat(semver); var replace__default = /*#__PURE__*/_interopDefaultCompat(replace); var migrate = async (options) => { const changed = await migrateMovedPackages({ pattern: options.pattern, skipCodeChanges: options.skipCodeChanges }); if (changed) { await runYarnInstall(); } }; async function migrateMovedPackages(options) { var _a; console.log( "Checking for moved packages to the @backstage-community namespace..." ); const packages = await cliNode.PackageGraph.listTargetPackages(); let didAnythingChange = false; for (const pkg of packages) { const pkgName = pkg.packageJson.name; let didPackageChange = false; const movedPackages = /* @__PURE__ */ new Map(); for (const depType of [ "dependencies", "devDependencies", "peerDependencies" ]) { const depsObj = pkg.packageJson[depType]; if (!depsObj) { continue; } for (const [depName, depVersion] of Object.entries(depsObj)) { if ((options == null ? void 0 : options.pattern) && !minimatch.minimatch(depName, options.pattern)) { continue; } let packageInfo; try { packageInfo = await fs.readJson( require.resolve(`${depName}/package.json`, { paths: [pkg.dir] }) ); } catch (ex) { console.warn( chalk__default.default.yellow( `Could not find package.json for ${depName}@${depVersion} in ${pkgName} (${depType})` ) ); continue; } const movedPackageName = (_a = packageInfo.backstage) == null ? void 0 : _a.moved; if (movedPackageName) { movedPackages.set(depName, movedPackageName); console.log( chalk__default.default.yellow( `Found a moved package ${depName}@${depVersion} -> ${movedPackageName} in ${pkgName} (${depType})` ) ); didPackageChange = true; didAnythingChange = true; depsObj[movedPackageName] = depsObj[depName]; delete depsObj[depName]; } } } if (didPackageChange) { await fs.writeJson(path.resolve(pkg.dir, "package.json"), pkg.packageJson, { spaces: 2 }); if (!(options == null ? void 0 : options.skipCodeChanges)) { const files = await replace__default.default({ files: path.join(pkg.dir, "src", "**"), allowEmptyPaths: true, processor: (content) => { return Array.from(movedPackages.entries()).reduce( (newContent, [oldName, newName]) => { return newContent.replace(new RegExp(`"${oldName}"`, "g"), `"${newName}"`).replace(new RegExp(`'${oldName}'`, "g"), `'${newName}'`).replace(new RegExp(`${oldName}/`, "g"), `${newName}/`); }, content ); } }); if (files.length > 0) { console.log( chalk__default.default.green( `Updated ${files.length} files in ${pkgName} to use the new package names` ) ); } } } } return didAnythingChange; } var migrate$1 = /*#__PURE__*/Object.freeze({ __proto__: null, default: migrate, migrateMovedPackages: migrateMovedPackages }); const DEP_TYPES = [ "dependencies", "devDependencies", "peerDependencies", "optionalDependencies" ]; const DEFAULT_PATTERN_GLOB = "@backstage/*"; var bump = async (opts) => { var _a; const lockfilePath = index.paths.resolveTargetRoot("yarn.lock"); const lockfile = await Lockfile.Lockfile.load(lockfilePath); let pattern = opts.pattern; if (!pattern) { console.log(`Using default pattern glob ${DEFAULT_PATTERN_GLOB}`); pattern = DEFAULT_PATTERN_GLOB; } else { console.log(`Using custom pattern glob ${pattern}`); } let findTargetVersion; let releaseManifest; if (semver__default.default.valid(opts.release)) { releaseManifest = await releaseManifests.getManifestByVersion({ version: opts.release }); findTargetVersion = createStrictVersionFinder({ releaseManifest }); } else { if (opts.release === "next") { const next = await releaseManifests.getManifestByReleaseLine({ releaseLine: "next" }); const main = await releaseManifests.getManifestByReleaseLine({ releaseLine: "main" }); releaseManifest = semver__default.default.gt(next.releaseVersion, main.releaseVersion) ? next : main; } else { releaseManifest = await releaseManifests.getManifestByReleaseLine({ releaseLine: opts.release }); } findTargetVersion = createVersionFinder({ releaseLine: opts.releaseLine, releaseManifest }); } const dependencyMap = await packages.mapDependencies(index.paths.targetDir, pattern); const versionBumps = /* @__PURE__ */ new Map(); const unlocked = Array(); await parallel.runParallelWorkers({ parallelismFactor: 4, items: dependencyMap.entries(), async worker([name, pkgs]) { var _a2; let target; try { target = await findTargetVersion(name); } catch (error) { if (errors.isError(error) && error.name === "NotFoundError") { console.log(`Package info not found, ignoring package ${name}`); return; } throw error; } for (const pkg of pkgs) { versionBumps.set( pkg.name, ((_a2 = versionBumps.get(pkg.name)) != null ? _a2 : []).concat({ name, location: pkg.location, range: `^${target}`, // TODO(Rugvip): Option to use something else than ^? target }) ); } } }); const filter = (name) => minimatch.minimatch(name, pattern); await parallel.runParallelWorkers({ parallelismFactor: 4, items: lockfile.keys(), async worker(name) { var _a2; if (!filter(name)) { return; } let target; try { target = await findTargetVersion(name); } catch (error) { if (errors.isError(error) && error.name === "NotFoundError") { console.log(`Package info not found, ignoring package ${name}`); return; } throw error; } for (const entry of (_a2 = lockfile.get(name)) != null ? _a2 : []) { if (!semver__default.default.satisfies(target, entry.range)) { continue; } unlocked.push({ name, range: entry.range, target }); } } }); console.log(); if (versionBumps.size === 0 && unlocked.length === 0) { console.log(chalk__default.default.green("All Backstage packages are up to date!")); } else { console.log(chalk__default.default.yellow("Some packages are outdated, updating")); console.log(); if (unlocked.length > 0) { const removed = /* @__PURE__ */ new Set(); for (const { name, range, target } of unlocked) { const existingEntry = (_a = lockfile.get(name)) == null ? void 0 : _a.find((e) => e.range === range); if ((existingEntry == null ? void 0 : existingEntry.version) === target) { continue; } const key = JSON.stringify({ name, range }); if (!removed.has(key)) { removed.add(key); console.log( `${chalk__default.default.magenta("unlocking")} ${name}@${chalk__default.default.yellow( range )} ~> ${chalk__default.default.yellow(target)}` ); lockfile.remove(name, range); } } await lockfile.save(lockfilePath); } const breakingUpdates = /* @__PURE__ */ new Map(); await parallel.runParallelWorkers({ parallelismFactor: 4, items: versionBumps.entries(), async worker([name, deps]) { var _a2; const pkgPath = path.resolve(deps[0].location, "package.json"); const pkgJson = await fs__default.default.readJson(pkgPath); for (const dep of deps) { console.log( `${chalk__default.default.cyan("bumping")} ${dep.name} in ${chalk__default.default.cyan( name )} to ${chalk__default.default.yellow(dep.range)}` ); for (const depType of DEP_TYPES) { if (depType in pkgJson && dep.name in pkgJson[depType]) { const oldRange = pkgJson[depType][dep.name]; pkgJson[depType][dep.name] = dep.range; const lockfileEntry = (_a2 = lockfile.get(dep.name)) == null ? void 0 : _a2.find((entry) => entry.range === oldRange); if (lockfileEntry) { const from = lockfileEntry.version; const to = dep.target; if (!semver__default.default.satisfies(to, `^${from}`)) { breakingUpdates.set(dep.name, { from, to }); } } } } } await fs__default.default.writeJson(pkgPath, pkgJson, { spaces: 2 }); } }); console.log(); if (pattern === DEFAULT_PATTERN_GLOB) { await bumpBackstageJsonVersion(releaseManifest.releaseVersion); } else { console.log( chalk__default.default.yellow( `Skipping backstage.json update as custom pattern is used` ) ); } if (!opts.skipInstall) { await runYarnInstall(); } else { console.log(); console.log(chalk__default.default.yellow(`Skipping yarn install`)); } if (!opts.skipMigrate) { console.log(); const changed = await migrateMovedPackages({ pattern: opts.pattern }); if (changed && !opts.skipInstall) { await runYarnInstall(); } } if (breakingUpdates.size > 0) { console.log(); console.log( chalk__default.default.yellow("\u26A0\uFE0F The following packages may have breaking changes:") ); console.log(); for (const [name, { from, to }] of Array.from( breakingUpdates.entries() ).sort()) { console.log( ` ${chalk__default.default.yellow(name)} : ${chalk__default.default.yellow(from)} ~> ${chalk__default.default.yellow( to )}` ); let path; if (name.startsWith("@backstage/plugin-")) { path = `plugins/${name.replace("@backstage/plugin-", "")}`; } else if (name.startsWith("@backstage/")) { path = `packages/${name.replace("@backstage/", "")}`; } if (path) { console.log( ` https://github.com/backstage/backstage/blob/master/${path}/CHANGELOG.md` ); } console.log(); } } else { console.log(); } console.log(chalk__default.default.green("Version bump complete!")); } console.log(); const dedupLockfile = await Lockfile.Lockfile.load(lockfilePath); const result = dedupLockfile.analyze({ filter, localPackages: cliNode.PackageGraph.fromPackages( await cliNode.PackageGraph.listTargetPackages() ) }); const forbiddenNewRanges = result.newRanges.filter( ({ name }) => lint.forbiddenDuplicatesFilter(name) ); if (forbiddenNewRanges.length > 0) { throw new Error( `Version bump failed for ${forbiddenNewRanges.map((i) => i.name).join(", ")}` ); } const allowedDuplicates = result.newRanges.filter( ({ name }) => !lint.forbiddenDuplicatesFilter(name) ); if (allowedDuplicates.length > 0) { console.log( chalk__default.default.yellow( "The following packages have duplicates but have been allowed:" ) ); console.log(chalk__default.default.yellow(allowedDuplicates.map((i) => i.name).join(", "))); } }; function createStrictVersionFinder(options) { const releasePackages = new Map( options.releaseManifest.packages.map((p) => [p.name, p.version]) ); return async function findTargetVersion(name) { console.log(`Checking for updates of ${name}`); const manifestVersion = releasePackages.get(name); if (manifestVersion) { return manifestVersion; } throw new errors.NotFoundError(`Package ${name} not found in release manifest`); }; } function createVersionFinder(options) { const { releaseLine = "latest", packageInfoFetcher = packages.fetchPackageInfo, releaseManifest } = options; const distTag = releaseLine === "main" ? "latest" : releaseLine; const found = /* @__PURE__ */ new Map(); const releasePackages = new Map( releaseManifest == null ? void 0 : releaseManifest.packages.map((p) => [p.name, p.version]) ); return async function findTargetVersion(name) { const existing = found.get(name); if (existing) { return existing; } console.log(`Checking for updates of ${name}`); const manifestVersion = releasePackages.get(name); if (manifestVersion) { return manifestVersion; } const info = await packageInfoFetcher(name); const latestVersion = info["dist-tags"].latest; if (!latestVersion) { throw new Error(`No target 'latest' version found for ${name}`); } const taggedVersion = info["dist-tags"][distTag]; if (distTag === "latest" || !taggedVersion) { found.set(name, latestVersion); return latestVersion; } const latestVersionDateStr = info.time[latestVersion]; const taggedVersionDateStr = info.time[taggedVersion]; if (!latestVersionDateStr) { throw new Error( `No time available for version '${latestVersion}' of ${name}` ); } if (!taggedVersionDateStr) { throw new Error( `No time available for version '${taggedVersion}' of ${name}` ); } const latestVersionRelease = new Date(latestVersionDateStr).getTime(); const taggedVersionRelease = new Date(taggedVersionDateStr).getTime(); if (latestVersionRelease > taggedVersionRelease) { found.set(name, latestVersion); return latestVersion; } found.set(name, taggedVersion); return taggedVersion; }; } async function bumpBackstageJsonVersion(version) { const backstageJsonPath = index.paths.resolveTargetRoot(cliCommon.BACKSTAGE_JSON); const backstageJson = await fs__default.default.readJSON(backstageJsonPath).catch((e) => { if (e.code === "ENOENT") { return; } throw e; }); const prevVersion = backstageJson == null ? void 0 : backstageJson.version; if (prevVersion === version) { return; } const { yellow, cyan, green } = chalk__default.default; if (prevVersion) { const from = encodeURIComponent(prevVersion); const to = encodeURIComponent(version); const link = `https://backstage.github.io/upgrade-helper/?from=${from}&to=${to}`; console.log( yellow( `Upgraded from release ${green(prevVersion)} to ${green( version )}, please review these template changes:` ) ); console.log(); console.log(` ${cyan(link)}`); console.log(); } else { console.log( yellow( `Your project is now at version ${version}, which has been written to ${cliCommon.BACKSTAGE_JSON}` ) ); } await fs__default.default.writeJson( backstageJsonPath, { ...backstageJson, version }, { spaces: 2, encoding: "utf8" } ); } async function runYarnInstall() { const spinner = ora__default.default({ prefixText: `Running ${chalk__default.default.blue("yarn install")} to install new versions`, spinner: "arc", color: "green" }).start(); const installOutput = new Array(); try { await run.run("yarn", ["install"], { env: { FORCE_COLOR: "true", // We filter out all of the npm_* environment variables that are added when // executing through yarn. This works around an issue where these variables // incorrectly override local yarn or npm config in the project directory. ...Object.fromEntries( Object.entries(process.env).map( ([name, value]) => name.startsWith("npm_") ? [name, void 0] : [name, value] ) ) }, stdoutLogFunc: (data) => installOutput.push(data), stderrLogFunc: (data) => installOutput.push(data) }); spinner.succeed(); } catch (error) { spinner.fail(); process.stdout.write(Buffer.concat(installOutput)); throw error; } } var bump$1 = /*#__PURE__*/Object.freeze({ __proto__: null, bumpBackstageJsonVersion: bumpBackstageJsonVersion, createStrictVersionFinder: createStrictVersionFinder, createVersionFinder: createVersionFinder, default: bump, runYarnInstall: runYarnInstall }); exports.bump = bump$1; exports.migrate = migrate$1; //# sourceMappingURL=bump-XGQA1gKg.cjs.js.map