From bfb31ce02f43eef95fbd444e8dead738a54618f7 Mon Sep 17 00:00:00 2001 From: Miki Date: Thu, 4 Jan 2024 10:18:19 -0800 Subject: [PATCH] [PM] Enhance single version requirements imposed during bootstrapping Add `--single-version` switch to `bootstrap` to manipulate the behavior of single-version validation Signed-off-by: Miki --- CHANGELOG.md | 1 + packages/osd-pm/README.md | 28 + packages/osd-pm/dist/index.js | 1034 ++++++++++------- packages/osd-pm/package.json | 1 + packages/osd-pm/src/cli.ts | 4 +- packages/osd-pm/src/commands/bootstrap.ts | 2 +- packages/osd-pm/src/utils/project.ts | 68 +- packages/osd-pm/src/utils/scripts.ts | 40 +- .../osd-pm/src/utils/validate_dependencies.ts | 235 +++- 9 files changed, 961 insertions(+), 452 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 163565d81c03..d15ff90d6de7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Decouple] Add new cross compatibility check core service which export functionality for plugins to verify if their OpenSearch plugin counterpart is installed on the cluster or has incompatible version to configure the plugin behavior([#4710](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4710)) - [Discover] Display inner properties in the left navigation bar [#5429](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5429) - [Chrome] Introduce registerCollapsibleNavHeader to allow plugins to customize the rendering of nav menu header ([#5244](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5244)) +- [PM] Enhance single version requirements imposed during bootstrapping ([#5675](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5675)) - [Custom Branding] Relative URL should be allowed for logos ([#5572](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5572)) ### 🐛 Bug Fixes diff --git a/packages/osd-pm/README.md b/packages/osd-pm/README.md index 8e30c9a51058..9ecb4030b70b 100644 --- a/packages/osd-pm/README.md +++ b/packages/osd-pm/README.md @@ -141,6 +141,34 @@ yarn osd Bootstrapping also calls the `osd:bootstrap` script for every included project. This is intended for packages that need to be built/transpiled to be usable. +#### Single-version validation + +Bootstrapping, by default, applies a `strict` single-version validation where it requires all the dependencies defined +more than once to have the same version-range in the `package.json` files of Dashboards, packages, and plugins. If a +violation is identified, bootstrapping terminates with an error. This behavior can be controlled using the +`--single-version` switch. Using any switch other than the default can result in the installation of versions of the +dependencies that were never tested and this could lead to unexpected results. + +``` +yarn osd bootstrap --single-version=loose +``` +In `loose` mode, bootstrapping reconciles the various versions installed as a result of having multiple ranges for a +dependency, by choosing one that satisfies all said ranges. Even though installing the chosen version updates the +`yarn.lock` files, no `package.json` changes would be needed. + +``` +yarn osd bootstrap --single-version=brute-force +``` +In `brute-force` mode, bootstrapping chooses the newest of the various versions installed, irrespective of whether it +satisfies any of the ranges. Installing the chosen version, bootstrapping updates the `yarn.lock` files and applies a +range, in the form of `^`, to all `package.json` files that declared the dependency. + +``` +yarn osd bootstrap --single-version=ignore +``` +In `ignore` mode, bootstrapping behaves very similar to the `strict` mode by showing errors when different ranges of a +package are marked as dependencies, but without terminating. + ### Running scripts Some times you want to run the same script across multiple packages and plugins, diff --git a/packages/osd-pm/dist/index.js b/packages/osd-pm/dist/index.js index 616c0dd854f4..752cd26070c6 100644 --- a/packages/osd-pm/dist/index.js +++ b/packages/osd-pm/dist/index.js @@ -135,8 +135,8 @@ var _cli = __webpack_require__(1); var _production = __webpack_require__(563); var _projects = __webpack_require__(147); var _project = __webpack_require__(165); -var _workspaces = __webpack_require__(329); -var _config = __webpack_require__(330); +var _workspaces = __webpack_require__(330); +var _config = __webpack_require__(331); /***/ }), /* 1 */ @@ -191,7 +191,7 @@ function help() { _log.log.info((0, _dedent.default)` usage: osd [] - By default commands are run for OpenSearch Dashboards itself, all packages in the 'packages/' + By default, commands are run for OpenSearch Dashboards itself, all packages in the 'packages/' folder and for all plugins in './plugins' and '../opensearch-dashboards-extra'. Available commands: @@ -204,6 +204,7 @@ function help() { -i, --include Include only specified projects. If left unspecified, it defaults to including all projects. --skip-opensearch-dashboards-plugins Filter all plugins in ./plugins and ../opensearch-dashboards-extra when running command. --no-cache Disable the bootstrap cache + --single-version Set single version validation method: 'strict', 'loose', 'ignore', or 'brute-force' --verbose Set log level to verbose --debug Set log level to debug --quiet Set log level to error @@ -231,7 +232,8 @@ async function run(argv) { default: { cache: true }, - boolean: ['prefer-offline', 'frozen-lockfile', 'cache'] + boolean: ['prefer-offline', 'frozen-lockfile', 'cache'], + string: ['single-version'] }); const args = options._; if (options.help || args.length === 0) { @@ -8978,7 +8980,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.commands = void 0; var _bootstrap = __webpack_require__(129); -var _clean = __webpack_require__(344); +var _clean = __webpack_require__(345); var _run = __webpack_require__(457); var _watch = __webpack_require__(458); /* @@ -9033,10 +9035,10 @@ var _link_project_executables = __webpack_require__(130); var _log = __webpack_require__(145); var _parallelize = __webpack_require__(146); var _projects = __webpack_require__(147); -var _project_checksums = __webpack_require__(331); -var _bootstrap_cache_file = __webpack_require__(341); -var _yarn_lock = __webpack_require__(333); -var _validate_dependencies = __webpack_require__(342); +var _project_checksums = __webpack_require__(332); +var _bootstrap_cache_file = __webpack_require__(342); +var _yarn_lock = __webpack_require__(334); +var _validate_dependencies = __webpack_require__(343); /* * SPDX-License-Identifier: Apache-2.0 * @@ -9074,6 +9076,7 @@ const BootstrapCommand = exports.BootstrapCommand = { options, osd }) { + var _options$singleVersi, _options$singleVersi$; const batchedProjectsByWorkspace = (0, _projects.topologicallyBatchProjects)(projects, projectGraph, { batchByWorkspace: true }); @@ -9093,7 +9096,7 @@ const BootstrapCommand = exports.BootstrapCommand = { } } const yarnLock = await (0, _yarn_lock.readYarnLock)(osd); - await (0, _validate_dependencies.validateDependencies)(osd, yarnLock); + await (0, _validate_dependencies.validateDependencies)(osd, yarnLock, (_options$singleVersi = options['single-version']) === null || _options$singleVersi === void 0 || (_options$singleVersi$ = _options$singleVersi.toLowerCase) === null || _options$singleVersi$ === void 0 ? void 0 : _options$singleVersi$.call(_options$singleVersi)); await (0, _link_project_executables.linkProjectExecutables)(projects, projectGraph); /** @@ -11229,7 +11232,7 @@ var _path = _interopRequireDefault(__webpack_require__(4)); var _util = __webpack_require__(112); var _errors = __webpack_require__(164); var _project = __webpack_require__(165); -var _workspaces = __webpack_require__(329); +var _workspaces = __webpack_require__(330); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* * SPDX-License-Identifier: Apache-2.0 @@ -14851,15 +14854,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Project = void 0; -var _fs = _interopRequireDefault(__webpack_require__(134)); -var _path = _interopRequireDefault(__webpack_require__(4)); +var _fs = __webpack_require__(134); +var _path = __webpack_require__(4); var _util = __webpack_require__(112); var _errors = __webpack_require__(164); var _log = __webpack_require__(145); var _package_json = __webpack_require__(166); var _scripts = __webpack_require__(282); -var _targeted_build = __webpack_require__(328); -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +var _targeted_build = __webpack_require__(329); function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } /* @@ -14925,9 +14927,9 @@ class Project { _defineProperty(this, "isWorkspaceProject", false); this.json = Object.freeze(packageJson); this.path = projectPath; - this.packageJsonLocation = _path.default.resolve(this.path, 'package.json'); - this.nodeModulesLocation = _path.default.resolve(this.path, 'node_modules'); - this.targetLocation = _path.default.resolve(this.path, 'target'); + this.packageJsonLocation = (0, _path.resolve)(this.path, 'package.json'); + this.nodeModulesLocation = (0, _path.resolve)(this.path, 'node_modules'); + this.targetLocation = (0, _path.resolve)(this.path, 'target'); this.version = this.json.version; this.productionDependencies = this.json.dependencies || {}; this.devDependencies = this.json.devDependencies || {}; @@ -14952,7 +14954,7 @@ class Project { if (dependentProjectIsInWorkspace) { expectedVersionInPackageJson = project.json.version; } else { - const relativePathToProject = normalizePath(_path.default.relative(this.path, project.path)); + const relativePathToProject = normalizePath((0, _path.relative)(this.path, project.path)); expectedVersionInPackageJson = `link:${relativePathToProject}`; } @@ -14984,7 +14986,7 @@ class Project { * instead of everything located in the project directory. */ getIntermediateBuildDirectory() { - return _path.default.resolve(this.path, this.getBuildConfig().intermediateBuildDirectory || '.'); + return (0, _path.resolve)(this.path, this.getBuildConfig().intermediateBuildDirectory || '.'); } getCleanConfig() { return this.json.opensearchDashboards && this.json.opensearchDashboards.clean || {}; @@ -15005,13 +15007,13 @@ class Project { } if (typeof raw === 'string') { return { - [this.name]: _path.default.resolve(this.path, raw) + [this.name]: (0, _path.resolve)(this.path, raw) }; } if (typeof raw === 'object') { const binsConfig = {}; for (const binName of Object.keys(raw)) { - binsConfig[binName] = _path.default.resolve(this.path, raw[binName]); + binsConfig[binName] = (0, _path.resolve)(this.path, raw[binName]); } return binsConfig; } @@ -15055,6 +15057,29 @@ class Project { await this.removeExtraneousNodeModules(); } + /** + * Install a specific version of a dependency and update the package.json. + * When a range is not specified, ^ is used. The range is then + * placed in the package.json with intentionally no validation. + */ + async installDependencyVersion(depName, version, dev = false, range) { + _log.log.info(`[${this.name}] running yarn to install ${depName}@${version}`); + _log.log.write(''); + const rangeToUse = range || `^${version}`; + const extraArgs = [`${depName}@${version}`]; + if (dev) extraArgs.push('--dev'); + if (this.isWorkspaceProject) { + await (0, _scripts.installInDir)(this.path); + } else { + await (0, _scripts.installInDir)(this.path, extraArgs, true); + } + await (0, _scripts.patchFile)(this.packageJsonLocation, `"${depName}": "${version}"`, `"${depName}": "${rangeToUse}"`); + // The lock-file of workspace packages are symlinked to the root project's and editing the one in the project suffices + await (0, _scripts.patchFile)((0, _path.resolve)(this.path, 'yarn.lock'), `${depName}@${version}`, `${depName}@${rangeToUse}`); + _log.log.write(''); + await this.removeExtraneousNodeModules(); + } + /** * Yarn workspaces symlinks workspace projects to the root node_modules, even * when there is no depenency on the project. This results in unnecicary, and @@ -15078,12 +15103,12 @@ class Project { dependencies, devDependencies } = this.json; - const nodeModulesPath = _path.default.resolve(this.nodeModulesLocation, name); + const nodeModulesPath = (0, _path.resolve)(this.nodeModulesLocation, name); const isDependency = dependencies && dependencies.hasOwnProperty(name); const isDevDependency = devDependencies && devDependencies.hasOwnProperty(name); - if (!isDependency && !isDevDependency && _fs.default.existsSync(nodeModulesPath)) { + if (!isDependency && !isDevDependency && (0, _fs.existsSync)(nodeModulesPath)) { _log.log.debug(`No dependency on ${name}, removing link in node_modules`); - _fs.default.unlinkSync(nodeModulesPath); + (0, _fs.unlinkSync)(nodeModulesPath); } }); } @@ -25252,10 +25277,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.installInDir = installInDir; +exports.patchFile = patchFile; exports.runScriptInPackage = runScriptInPackage; exports.runScriptInPackageStreaming = runScriptInPackageStreaming; exports.yarnWorkspacesInfo = yarnWorkspacesInfo; -var _child_process = __webpack_require__(283); +var _fs = __webpack_require__(134); +var _readline = __webpack_require__(283); +var _child_process = __webpack_require__(284); /* * SPDX-License-Identifier: Apache-2.0 * @@ -25290,8 +25318,8 @@ const YARN_EXEC = process.env.npm_execpath || 'yarn'; /** * Install all dependencies in the given directory */ -async function installInDir(directory, extraArgs = []) { - const options = ['install', '--non-interactive', ...extraArgs]; +async function installInDir(directory, extraArgs = [], useAdd = false) { + const options = [useAdd ? 'add' : 'install', '--non-interactive', ...extraArgs]; // We pass the mutex flag to ensure only one instance of yarn runs at any // given time (e.g. to avoid conflicts). @@ -25300,6 +25328,34 @@ async function installInDir(directory, extraArgs = []) { }); } +/** + * Patch a file by replacing a given string + */ +function patchFile(filePath, searchValue, replacement) { + return new Promise(async (resolve, reject) => { + const patchWriter = (0, _fs.createWriteStream)(`${filePath}.patched`, { + flags: 'w' + }); + const fileReader = (0, _readline.createInterface)({ + input: (0, _fs.createReadStream)(filePath), + crlfDelay: Infinity + }); + for await (const line of fileReader) { + if (line.includes(searchValue)) { + patchWriter.write(line.replace(searchValue, replacement) + '\n', 'utf8'); + } else { + patchWriter.write(line + '\n', 'utf8'); + } + } + patchWriter.on('finish', () => resolve()); + patchWriter.on('error', reject); + fileReader.close(); + patchWriter.end(); + (0, _fs.unlinkSync)(filePath); + (0, _fs.renameSync)(`${filePath}.patched`, filePath); + }); +} + /** * Run script in the given directory */ @@ -25343,6 +25399,12 @@ async function yarnWorkspacesInfo(directory) { /***/ }), /* 283 */ +/***/ (function(module, exports) { + +module.exports = require("readline"); + +/***/ }), +/* 284 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25355,8 +25417,8 @@ exports.spawn = spawn; exports.spawnStreaming = spawnStreaming; var _stream = __webpack_require__(138); var _chalk = _interopRequireDefault(__webpack_require__(113)); -var _execa = _interopRequireDefault(__webpack_require__(284)); -var _strongLogTransformer = _interopRequireDefault(__webpack_require__(320)); +var _execa = _interopRequireDefault(__webpack_require__(285)); +var _strongLogTransformer = _interopRequireDefault(__webpack_require__(321)); var _log = __webpack_require__(145); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* @@ -25438,23 +25500,23 @@ function spawnStreaming(command, args, opts, { } /***/ }), -/* 284 */ +/* 285 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const childProcess = __webpack_require__(285); -const crossSpawn = __webpack_require__(286); -const stripFinalNewline = __webpack_require__(299); -const npmRunPath = __webpack_require__(300); -const onetime = __webpack_require__(301); -const makeError = __webpack_require__(303); -const normalizeStdio = __webpack_require__(308); -const {spawnedKill, spawnedCancel, setupTimeout, setExitHandler} = __webpack_require__(309); -const {handleInput, getSpawnedResult, makeAllStream, validateInputSync} = __webpack_require__(310); -const {mergePromise, getSpawnedPromise} = __webpack_require__(318); -const {joinCommand, parseCommand} = __webpack_require__(319); +const childProcess = __webpack_require__(286); +const crossSpawn = __webpack_require__(287); +const stripFinalNewline = __webpack_require__(300); +const npmRunPath = __webpack_require__(301); +const onetime = __webpack_require__(302); +const makeError = __webpack_require__(304); +const normalizeStdio = __webpack_require__(309); +const {spawnedKill, spawnedCancel, setupTimeout, setExitHandler} = __webpack_require__(310); +const {handleInput, getSpawnedResult, makeAllStream, validateInputSync} = __webpack_require__(311); +const {mergePromise, getSpawnedPromise} = __webpack_require__(319); +const {joinCommand, parseCommand} = __webpack_require__(320); const DEFAULT_MAX_BUFFER = 1000 * 1000 * 100; @@ -25705,21 +25767,21 @@ module.exports.node = (scriptPath, args, options = {}) => { /***/ }), -/* 285 */ +/* 286 */ /***/ (function(module, exports) { module.exports = require("child_process"); /***/ }), -/* 286 */ +/* 287 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const cp = __webpack_require__(285); -const parse = __webpack_require__(287); -const enoent = __webpack_require__(298); +const cp = __webpack_require__(286); +const parse = __webpack_require__(288); +const enoent = __webpack_require__(299); function spawn(command, args, options) { // Parse the arguments @@ -25757,16 +25819,16 @@ module.exports._enoent = enoent; /***/ }), -/* 287 */ +/* 288 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const resolveCommand = __webpack_require__(288); -const escape = __webpack_require__(294); -const readShebang = __webpack_require__(295); +const resolveCommand = __webpack_require__(289); +const escape = __webpack_require__(295); +const readShebang = __webpack_require__(296); const isWin = process.platform === 'win32'; const isExecutableRegExp = /\.(?:com|exe)$/i; @@ -25855,15 +25917,15 @@ module.exports = parse; /***/ }), -/* 288 */ +/* 289 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const which = __webpack_require__(289); -const getPathKey = __webpack_require__(293); +const which = __webpack_require__(290); +const getPathKey = __webpack_require__(294); function resolveCommandAttempt(parsed, withoutPathExt) { const env = parsed.options.env || process.env; @@ -25914,7 +25976,7 @@ module.exports = resolveCommand; /***/ }), -/* 289 */ +/* 290 */ /***/ (function(module, exports, __webpack_require__) { const isWindows = process.platform === 'win32' || @@ -25923,7 +25985,7 @@ const isWindows = process.platform === 'win32' || const path = __webpack_require__(4) const COLON = isWindows ? ';' : ':' -const isexe = __webpack_require__(290) +const isexe = __webpack_require__(291) const getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }) @@ -26045,15 +26107,15 @@ which.sync = whichSync /***/ }), -/* 290 */ +/* 291 */ /***/ (function(module, exports, __webpack_require__) { var fs = __webpack_require__(134) var core if (process.platform === 'win32' || global.TESTING_WINDOWS) { - core = __webpack_require__(291) -} else { core = __webpack_require__(292) +} else { + core = __webpack_require__(293) } module.exports = isexe @@ -26108,7 +26170,7 @@ function sync (path, options) { /***/ }), -/* 291 */ +/* 292 */ /***/ (function(module, exports, __webpack_require__) { module.exports = isexe @@ -26156,7 +26218,7 @@ function sync (path, options) { /***/ }), -/* 292 */ +/* 293 */ /***/ (function(module, exports, __webpack_require__) { module.exports = isexe @@ -26203,7 +26265,7 @@ function checkMode (stat, options) { /***/ }), -/* 293 */ +/* 294 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26226,7 +26288,7 @@ module.exports.default = pathKey; /***/ }), -/* 294 */ +/* 295 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26278,14 +26340,14 @@ module.exports.argument = escapeArgument; /***/ }), -/* 295 */ +/* 296 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const shebangCommand = __webpack_require__(296); +const shebangCommand = __webpack_require__(297); function readShebang(command) { // Read the first 150 bytes from the file @@ -26308,12 +26370,12 @@ module.exports = readShebang; /***/ }), -/* 296 */ +/* 297 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const shebangRegex = __webpack_require__(297); +const shebangRegex = __webpack_require__(298); module.exports = (string = '') => { const match = string.match(shebangRegex); @@ -26334,7 +26396,7 @@ module.exports = (string = '') => { /***/ }), -/* 297 */ +/* 298 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26343,7 +26405,7 @@ module.exports = /^#!(.*)/; /***/ }), -/* 298 */ +/* 299 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26409,7 +26471,7 @@ module.exports = { /***/ }), -/* 299 */ +/* 300 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26432,13 +26494,13 @@ module.exports = input => { /***/ }), -/* 300 */ +/* 301 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathKey = __webpack_require__(293); +const pathKey = __webpack_require__(294); const npmRunPath = options => { options = { @@ -26486,12 +26548,12 @@ module.exports.env = options => { /***/ }), -/* 301 */ +/* 302 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(302); +const mimicFn = __webpack_require__(303); const calledFunctions = new WeakMap(); @@ -26537,7 +26599,7 @@ module.exports.callCount = function_ => { /***/ }), -/* 302 */ +/* 303 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26557,12 +26619,12 @@ module.exports.default = mimicFn; /***/ }), -/* 303 */ +/* 304 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const {signalsByName} = __webpack_require__(304); +const {signalsByName} = __webpack_require__(305); const getErrorPrefix = ({timedOut, timeout, errorCode, signal, signalDescription, exitCode, isCanceled}) => { if (timedOut) { @@ -26650,14 +26712,14 @@ module.exports = makeError; /***/ }), -/* 304 */ +/* 305 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports,"__esModule",{value:true});exports.signalsByNumber=exports.signalsByName=void 0;var _os=__webpack_require__(121); -var _signals=__webpack_require__(305); -var _realtime=__webpack_require__(307); +var _signals=__webpack_require__(306); +var _realtime=__webpack_require__(308); @@ -26727,14 +26789,14 @@ const signalsByNumber=getSignalsByNumber();exports.signalsByNumber=signalsByNumb //# sourceMappingURL=main.js.map /***/ }), -/* 305 */ +/* 306 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports,"__esModule",{value:true});exports.getSignals=void 0;var _os=__webpack_require__(121); -var _core=__webpack_require__(306); -var _realtime=__webpack_require__(307); +var _core=__webpack_require__(307); +var _realtime=__webpack_require__(308); @@ -26768,7 +26830,7 @@ return{name,number,description,supported,action,forced,standard}; //# sourceMappingURL=signals.js.map /***/ }), -/* 306 */ +/* 307 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27047,7 +27109,7 @@ standard:"other"}];exports.SIGNALS=SIGNALS; //# sourceMappingURL=core.js.map /***/ }), -/* 307 */ +/* 308 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27072,7 +27134,7 @@ const SIGRTMAX=64;exports.SIGRTMAX=SIGRTMAX; //# sourceMappingURL=realtime.js.map /***/ }), -/* 308 */ +/* 309 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27131,7 +27193,7 @@ module.exports.node = opts => { /***/ }), -/* 309 */ +/* 310 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27250,14 +27312,14 @@ module.exports = { /***/ }), -/* 310 */ +/* 311 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const isStream = __webpack_require__(311); -const getStream = __webpack_require__(312); -const mergeStream = __webpack_require__(317); +const isStream = __webpack_require__(312); +const getStream = __webpack_require__(313); +const mergeStream = __webpack_require__(318); // `input` option const handleInput = (spawned, input) => { @@ -27354,7 +27416,7 @@ module.exports = { /***/ }), -/* 311 */ +/* 312 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27389,14 +27451,14 @@ module.exports = isStream; /***/ }), -/* 312 */ +/* 313 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const {constants: BufferConstants} = __webpack_require__(313); -const pump = __webpack_require__(314); -const bufferStream = __webpack_require__(316); +const {constants: BufferConstants} = __webpack_require__(314); +const pump = __webpack_require__(315); +const bufferStream = __webpack_require__(317); class MaxBufferError extends Error { constructor() { @@ -27456,17 +27518,17 @@ module.exports.MaxBufferError = MaxBufferError; /***/ }), -/* 313 */ +/* 314 */ /***/ (function(module, exports) { module.exports = require("buffer"); /***/ }), -/* 314 */ +/* 315 */ /***/ (function(module, exports, __webpack_require__) { var once = __webpack_require__(163) -var eos = __webpack_require__(315) +var eos = __webpack_require__(316) var fs = __webpack_require__(134) // we only need fs to get the ReadStream and WriteStream prototypes var noop = function () {} @@ -27550,7 +27612,7 @@ module.exports = pump /***/ }), -/* 315 */ +/* 316 */ /***/ (function(module, exports, __webpack_require__) { var once = __webpack_require__(163); @@ -27650,7 +27712,7 @@ module.exports = eos; /***/ }), -/* 316 */ +/* 317 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27709,7 +27771,7 @@ module.exports = options => { /***/ }), -/* 317 */ +/* 318 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27757,7 +27819,7 @@ module.exports = function (/*streams...*/) { /***/ }), -/* 318 */ +/* 319 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27810,7 +27872,7 @@ module.exports = { /***/ }), -/* 319 */ +/* 320 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27849,7 +27911,7 @@ module.exports = { /***/ }), -/* 320 */ +/* 321 */ /***/ (function(module, exports, __webpack_require__) { // Copyright IBM Corp. 2014,2018. All Rights Reserved. @@ -27857,12 +27919,12 @@ module.exports = { // This file is licensed under the Apache License 2.0. // License text available at https://opensource.org/licenses/Apache-2.0 -module.exports = __webpack_require__(321); -module.exports.cli = __webpack_require__(325); +module.exports = __webpack_require__(322); +module.exports.cli = __webpack_require__(326); /***/ }), -/* 321 */ +/* 322 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27877,9 +27939,9 @@ var stream = __webpack_require__(138); var util = __webpack_require__(112); var fs = __webpack_require__(134); -var through = __webpack_require__(322); -var duplexer = __webpack_require__(323); -var StringDecoder = __webpack_require__(324).StringDecoder; +var through = __webpack_require__(323); +var duplexer = __webpack_require__(324); +var StringDecoder = __webpack_require__(325).StringDecoder; module.exports = Logger; @@ -28068,7 +28130,7 @@ function lineMerger(host) { /***/ }), -/* 322 */ +/* 323 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(138) @@ -28182,7 +28244,7 @@ function through (write, end, opts) { /***/ }), -/* 323 */ +/* 324 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(138) @@ -28275,13 +28337,13 @@ function duplex(writer, reader) { /***/ }), -/* 324 */ +/* 325 */ /***/ (function(module, exports) { module.exports = require("string_decoder"); /***/ }), -/* 325 */ +/* 326 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -28292,11 +28354,11 @@ module.exports = require("string_decoder"); -var minimist = __webpack_require__(326); +var minimist = __webpack_require__(327); var path = __webpack_require__(4); -var Logger = __webpack_require__(321); -var pkg = __webpack_require__(327); +var Logger = __webpack_require__(322); +var pkg = __webpack_require__(328); module.exports = cli; @@ -28350,7 +28412,7 @@ function usage($0, p) { /***/ }), -/* 326 */ +/* 327 */ /***/ (function(module, exports) { module.exports = function (args, opts) { @@ -28605,13 +28667,13 @@ function isConstructorOrProto (obj, key) { /***/ }), -/* 327 */ +/* 328 */ /***/ (function(module) { module.exports = JSON.parse("{\"name\":\"strong-log-transformer\",\"version\":\"2.1.0\",\"description\":\"Stream transformer that prefixes lines with timestamps and other things.\",\"author\":\"Ryan Graham \",\"license\":\"Apache-2.0\",\"repository\":{\"type\":\"git\",\"url\":\"git://github.com/strongloop/strong-log-transformer\"},\"keywords\":[\"logging\",\"streams\"],\"bugs\":{\"url\":\"https://github.com/strongloop/strong-log-transformer/issues\"},\"homepage\":\"https://github.com/strongloop/strong-log-transformer\",\"directories\":{\"test\":\"test\"},\"bin\":{\"sl-log-transformer\":\"bin/sl-log-transformer.js\"},\"main\":\"index.js\",\"scripts\":{\"test\":\"tap --100 test/test-*\"},\"dependencies\":{\"duplexer\":\"^0.1.1\",\"minimist\":\"^1.2.0\",\"through\":\"^2.3.4\"},\"devDependencies\":{\"tap\":\"^12.0.1\"},\"engines\":{\"node\":\">=4\"}}"); /***/ }), -/* 328 */ +/* 329 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -28624,7 +28686,7 @@ exports.BuildTargets = void 0; exports.buildTargetedPackage = buildTargetedPackage; var _promises = __webpack_require__(143); var _path = __webpack_require__(4); -var _child_process = __webpack_require__(283); +var _child_process = __webpack_require__(284); var _log = __webpack_require__(145); /* * Copyright OpenSearch Contributors @@ -28666,7 +28728,7 @@ async function buildTargetedPackage({ } /***/ }), -/* 329 */ +/* 330 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -28680,7 +28742,7 @@ exports.workspacePackagePaths = workspacePackagePaths; var _glob = _interopRequireDefault(__webpack_require__(148)); var _path = _interopRequireDefault(__webpack_require__(4)); var _util = __webpack_require__(112); -var _config = __webpack_require__(330); +var _config = __webpack_require__(331); var _fs = __webpack_require__(131); var _package_json = __webpack_require__(166); var _projects = __webpack_require__(147); @@ -28775,7 +28837,7 @@ function packagesFromGlobPattern({ } /***/ }), -/* 330 */ +/* 331 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -28850,7 +28912,7 @@ function getProjectPaths({ } /***/ }), -/* 331 */ +/* 332 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -28861,9 +28923,9 @@ Object.defineProperty(exports, "__esModule", { }); exports.getAllChecksums = getAllChecksums; var _promises = __webpack_require__(143); -var _crypto = _interopRequireDefault(__webpack_require__(332)); -var _execa = _interopRequireDefault(__webpack_require__(284)); -var _yarn_lock = __webpack_require__(333); +var _crypto = _interopRequireDefault(__webpack_require__(333)); +var _execa = _interopRequireDefault(__webpack_require__(285)); +var _yarn_lock = __webpack_require__(334); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* * SPDX-License-Identifier: Apache-2.0 @@ -29044,13 +29106,13 @@ async function getAllChecksums(osd, log, yarnLock) { } /***/ }), -/* 332 */ +/* 333 */ /***/ (function(module, exports) { module.exports = require("crypto"); /***/ }), -/* 333 */ +/* 334 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -29061,8 +29123,8 @@ Object.defineProperty(exports, "__esModule", { }); exports.readYarnLock = readYarnLock; exports.resolveDepsForProject = resolveDepsForProject; -var _lockfile = __webpack_require__(334); -var _crossPlatform = __webpack_require__(335); +var _lockfile = __webpack_require__(335); +var _crossPlatform = __webpack_require__(336); var _path = __webpack_require__(4); var _fs = __webpack_require__(131); /* @@ -29194,7 +29256,7 @@ function resolveDepsForProject({ } /***/ }), -/* 334 */ +/* 335 */ /***/ (function(module, exports, __webpack_require__) { module.exports = @@ -30753,7 +30815,7 @@ module.exports = invariant; /* 9 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(332); +module.exports = __webpack_require__(333); /***/ }), /* 10 */, @@ -33077,7 +33139,7 @@ function onceStrict (fn) { /* 63 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(313); +module.exports = __webpack_require__(314); /***/ }), /* 64 */, @@ -39472,7 +39534,7 @@ module.exports = process && support(supportLevel); /******/ ]); /***/ }), -/* 335 */ +/* 336 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39486,12 +39548,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = __webpack_require__(7); -tslib_1.__exportStar(__webpack_require__(336), exports); tslib_1.__exportStar(__webpack_require__(337), exports); tslib_1.__exportStar(__webpack_require__(338), exports); +tslib_1.__exportStar(__webpack_require__(339), exports); /***/ }), -/* 336 */ +/* 337 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39505,7 +39567,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.realshortpathSync = exports.realShortPathSync = exports.realpathSync = exports.realPathSync = exports.resolveToShortNameSync = exports.resolveToShortPathSync = exports.resolveToFullNameSync = exports.resolveToFullPathSync = exports.shortNameSupportedSync = exports.shortNamesSupportedSync = exports.standardize = exports.NAMESPACE_PREFIX = void 0; -const child_process_1 = __webpack_require__(285); +const child_process_1 = __webpack_require__(286); const path_1 = __webpack_require__(4); const fs_1 = __webpack_require__(134); exports.NAMESPACE_PREFIX = process.platform === 'win32' ? '\\\\?\\' : ''; @@ -39627,7 +39689,7 @@ exports.realShortPathSync = realShortPathSync; exports.realshortpathSync = exports.realShortPathSync; /***/ }), -/* 337 */ +/* 338 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39641,7 +39703,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.PROCESS_POSIX_WORKING_DIR = exports.PROCESS_WORKING_DIR = void 0; -const path_1 = __webpack_require__(336); +const path_1 = __webpack_require__(337); /** * The full pathname of the working directory of the process * @constant @@ -39656,7 +39718,7 @@ exports.PROCESS_WORKING_DIR = (0, path_1.resolveToFullPathSync)(process.cwd()); exports.PROCESS_POSIX_WORKING_DIR = (0, path_1.standardize)(exports.PROCESS_WORKING_DIR); /***/ }), -/* 338 */ +/* 339 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39696,8 +39758,8 @@ const tslib_1 = __webpack_require__(7); * under the License. */ const path_1 = __webpack_require__(4); -const load_json_file_1 = tslib_1.__importDefault(__webpack_require__(339)); -const path_2 = __webpack_require__(336); +const load_json_file_1 = tslib_1.__importDefault(__webpack_require__(340)); +const path_2 = __webpack_require__(337); const readOpenSearchDashboardsPkgJson = dir => { try { const path = (0, path_1.resolve)(dir, 'package.json'); @@ -39762,7 +39824,7 @@ const relativeToRepoRoot = path => { exports.relativeToRepoRoot = relativeToRepoRoot; /***/ }), -/* 339 */ +/* 340 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39770,7 +39832,7 @@ exports.relativeToRepoRoot = relativeToRepoRoot; const path = __webpack_require__(4); const {promisify} = __webpack_require__(112); const fs = __webpack_require__(133); -const stripBom = __webpack_require__(340); +const stripBom = __webpack_require__(341); const parseJson = __webpack_require__(168); const parse = (data, filePath, options = {}) => { @@ -39788,7 +39850,7 @@ module.exports.sync = (filePath, options) => parse(fs.readFileSync(filePath, 'ut /***/ }), -/* 340 */ +/* 341 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39810,7 +39872,7 @@ module.exports = string => { /***/ }), -/* 341 */ +/* 342 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39909,7 +39971,7 @@ class BootstrapCacheFile { exports.BootstrapCacheFile = BootstrapCacheFile; /***/ }), -/* 342 */ +/* 343 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39919,12 +39981,15 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.validateDependencies = validateDependencies; -var _lockfile = __webpack_require__(334); +var _lockfile = __webpack_require__(335); var _dedent = _interopRequireDefault(__webpack_require__(2)); var _chalk = _interopRequireDefault(__webpack_require__(113)); -var _fs = __webpack_require__(131); +var _path = _interopRequireDefault(__webpack_require__(4)); +var _fs = __webpack_require__(134); +var _semver = __webpack_require__(191); +var _fs2 = __webpack_require__(131); var _log = __webpack_require__(145); -var _projects_tree = __webpack_require__(343); +var _projects_tree = __webpack_require__(344); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* * SPDX-License-Identifier: Apache-2.0 @@ -39936,7 +40001,6 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * Any modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ - /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -39955,11 +40019,37 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * specific language governing permissions and limitations * under the License. */ - // @ts-expect-error published types are useless - -async function validateDependencies(osd, yarnLock) { - // look through all of the packages in the yarn.lock file to see if +var SingleVersionResolution = /*#__PURE__*/function (SingleVersionResolution) { + SingleVersionResolution["STRICT"] = "strict"; + SingleVersionResolution["LOOSE"] = "loose"; + SingleVersionResolution["BRUTE_FORCE"] = "brute-force"; + SingleVersionResolution["IGNORE"] = "ignore"; + return SingleVersionResolution; +}(SingleVersionResolution || {}); +async function validateDependencies(osd, yarnLock, +/* `singleVersionResolution` controls how violations of single-version-dependencies is applied. + * STRICT (default): throw an error and exit + * LOOSE: identify and install a single version that satisfies all ranges + * BRUTE_FORCE: identify and install the newest version + * IGNORE: show all errors without exiting + * + * `LOOSE`: + * Reconciles the various versions installed as a result of having multiple ranges for a dependency, by + * choosing one that satisfies all said ranges. Even though installing the chosen version updates the + * lock-files, no package.json changes would be needed. + * + * `BRUTE_FORCE`: + * With no care for reconciliation, the newest of the various versions installed is chosen, irrespective of + * whether it satisfies any of the ranges. Installing the chosen version updates the lock-files and a range + * in the form of `^` is applied to all `package.json` files that declared the dependency. + * + * `IGNORE`: + * Behaves just like `strict` by showing errors when different ranges of a package are marked as + * dependencies, but it does not terminate the script. + */ +singleVersionResolution = SingleVersionResolution.STRICT) { + // look through all the packages in the yarn.lock file to see if // we have accidentally installed multiple lodash v4 versions const lodash4Versions = new Set(); const lodash4Reqs = new Set(); @@ -39977,7 +40067,7 @@ async function validateDependencies(osd, yarnLock) { for (const req of lodash4Reqs) { delete yarnLock[req]; } - await (0, _fs.writeFile)(osd.getAbsolute('yarn.lock'), (0, _lockfile.stringify)(yarnLock), 'utf8'); + await (0, _fs2.writeFile)(osd.getAbsolute('yarn.lock'), (0, _lockfile.stringify)(yarnLock), 'utf8'); _log.log.error((0, _dedent.default)` Multiple version of lodash v4 were detected, so they have been removed @@ -40022,12 +40112,14 @@ async function validateDependencies(osd, yarnLock) { `); process.exit(1); } + let hasIssues = false; - // TODO: remove this once we move into a single package.json // look through all the package.json files to find packages which have mismatched version ranges const depRanges = new Map(); for (const project of osd.getAllProjects().values()) { - for (const [dep, range] of Object.entries(project.allDependencies)) { + for (const [dep, range] of Object.entries( + // Don't be bothered with validating dev-deps when validating single-version loosely + singleVersionResolution === SingleVersionResolution.LOOSE ? project.productionDependencies : project.allDependencies)) { const existingDep = depRanges.get(dep); if (!existingDep) { depRanges.set(dep, [{ @@ -40047,11 +40139,131 @@ async function validateDependencies(osd, yarnLock) { existingRange.projects.push(project); } } - const duplicateRanges = Array.from(depRanges.entries()).filter(([, ranges]) => ranges.length > 1).reduce((acc, [dep, ranges]) => [...acc, dep, ...ranges.map(({ - range, - projects - }) => ` ${range} => ${projects.map(p => p.name).join(', ')}`)], []).join('\n '); - if (duplicateRanges) { + const cachedManifests = new Map(); + const violatingSingleVersionDepRanges = new Map(); + for (const [depName, ranges] of depRanges) { + // No violation if just a single range of a dependency is used + if (ranges.length === 1) continue; + const installedVersions = new Set(); + const installedDepVersionsCache = new Map(); + const desiredRanges = new Map(); + depLoop: for (const { + range, + projects + } of ranges) { + for (const project of projects) { + var _deps; + if (!cachedManifests.has(project.path)) cachedManifests.set(project.path, + // If there are errors reading or parsing the lockfiles, don't catch and let them fall through + (0, _lockfile.parse)((0, _fs.readFileSync)(_path.default.join(project.path, 'yarn.lock'), 'utf-8'))); + const { + object: deps + } = cachedManifests.get(project.path); + if (deps !== null && deps !== void 0 && (_deps = deps[`${depName}@${range}`]) !== null && _deps !== void 0 && _deps.version) { + installedVersions.add(deps[`${depName}@${range}`].version); + installedDepVersionsCache.set(`${project.name}#${depName}`, deps[`${depName}@${range}`].version); + } else { + _log.log.warning(`Failed to find the installed version for ${depName}@${range}`); + // If we cannot read any one of the installed versions of a depName, there is no point in continuing with it + installedVersions.clear(); + desiredRanges.clear(); + break depLoop; + } + } + desiredRanges.set(range, projects); + } + if (installedVersions.size === 0) { + // More than one range is used but couldn't get all the installed versions: call out violation + violatingSingleVersionDepRanges.set(depName, ranges); + } else if (singleVersionResolution === SingleVersionResolution.LOOSE && installedVersions.size === 1) { + hasIssues = true; + + /* When validating single-version loosely, ignore multiple ranges when they result in the installation of + * a single version. + */ + _log.log.info(`Ignored single version requirement for ${depName} as all installations are using v${installedVersions.values().next().value}.`); + } else { + const sortedInstalledVersion = Array.from(installedVersions).sort(_semver.rcompare); + const rangePatterns = Array.from(desiredRanges.keys()); + if (singleVersionResolution === SingleVersionResolution.BRUTE_FORCE) { + hasIssues = true; + const suitableVersion = sortedInstalledVersion[0]; + const suitableRange = `^${suitableVersion}`; + + // Install the version on all projects that have this dep; use the suitable range. + for (const { + projects + } of ranges) { + for (const project of projects) { + await project.installDependencyVersion(depName, suitableVersion, depName in project.devDependencies, suitableRange); + } + } + const conflictingRanges = ranges.map(({ + range, + projects + }) => `${range} => ${projects.map(p => p.name).join(', ')}`).join('\n '); + _log.log.warning((0, _dedent.default)` + + [single_version_dependencies] Multiple version ranges for package "${depName}" + were found across different package.json files. A version, v${suitableVersion}, was identified as the most recent + already installed replacement. All package.json files have been updated to indicate a dependency on \`${depName}@${suitableRange}\`. + + The conflicting version ranges are: + ${conflictingRanges} + `); + } else if (singleVersionResolution === SingleVersionResolution.LOOSE) { + let isCommonGroundFound = false; + for (const installedVersion of sortedInstalledVersion) { + if (rangePatterns.every(range => (0, _semver.satisfies)(installedVersion, range))) { + isCommonGroundFound = true; + + // Install the version on all projects that have this dep; keep the original range. + for (const { + range, + projects + } of ranges) { + for (const project of projects) { + // Don't bother updating anything if the desired version is already installed + if (installedDepVersionsCache.get(`${project.name}#${depName}`) === installedVersion) continue; + await project.installDependencyVersion(depName, installedVersion, depName in project.devDependencies, + // When validating single-version loosely, when a version change is needed, the range shouldn't change + range); + } + } + hasIssues = true; + const conflictingRanges = ranges.map(({ + range, + projects + }) => `${range} => ${projects.map(p => p.name).join(', ')}`).join('\n '); + _log.log.warning((0, _dedent.default)` + + [single_version_dependencies] Multiple version ranges for package "${depName}" + were found across different package.json files. A suitable version, v${installedVersion}, was + identified and installed. + + The conflicting version ranges are: + ${conflictingRanges} + `); + + // A usable version was identified so no need to check the lower versions + break; + } + } + if (!isCommonGroundFound) { + // When validating single-version loosely and no installed version satisfies all ranges, call out violation + violatingSingleVersionDepRanges.set(depName, ranges); + } + } else { + // When validating single-version, not loosly or with brute-force, call out violation + violatingSingleVersionDepRanges.set(depName, ranges); + } + } + } + if (violatingSingleVersionDepRanges.size > 0) { + const duplicateRanges = Array.from(violatingSingleVersionDepRanges.entries()).reduce((acc, [dep, ranges]) => [...acc, dep, ...ranges.map(({ + range, + projects + }) => ` ${range} => ${projects.map(p => p.name).join(', ')}`)], []).join('\n '); _log.log.error((0, _dedent.default)` [single_version_dependencies] Multiple version ranges for the same dependency @@ -40065,10 +40277,12 @@ async function validateDependencies(osd, yarnLock) { ${duplicateRanges} `); - process.exit(1); + if (singleVersionResolution !== SingleVersionResolution.IGNORE) { + process.exit(1); + } } - // look for packages that have the the `opensearchDashboards.devOnly` flag in their package.json + // look for packages that have the `opensearchDashboards.devOnly` flag in their package.json // and make sure they aren't included in the production dependencies of OpenSearch Dashboards const devOnlyProjectsInProduction = getDevOnlyProductionDepsTree(osd, 'opensearch-dashboards'); if (devOnlyProjectsInProduction) { @@ -40083,7 +40297,7 @@ async function validateDependencies(osd, yarnLock) { `); process.exit(1); } - _log.log.success('yarn.lock analysis completed without any issues'); + _log.log.success(hasIssues ? 'yarn.lock analysis completed' : 'yarn.lock analysis completed without any issues'); } function getDevOnlyProductionDepsTree(osd, projectName) { const project = osd.getProject(projectName); @@ -40100,7 +40314,7 @@ function getDevOnlyProductionDepsTree(osd, projectName) { } /***/ }), -/* 343 */ +/* 344 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40113,7 +40327,7 @@ exports.renderProjectsTree = renderProjectsTree; exports.treeToString = treeToString; var _chalk = _interopRequireDefault(__webpack_require__(113)); var _path = _interopRequireDefault(__webpack_require__(4)); -var _crossPlatform = __webpack_require__(335); +var _crossPlatform = __webpack_require__(336); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* * SPDX-License-Identifier: Apache-2.0 @@ -40259,7 +40473,7 @@ function addProjectToTree(tree, pathParts, project) { } /***/ }), -/* 344 */ +/* 345 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40269,8 +40483,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.CleanCommand = void 0; -var _del = _interopRequireDefault(__webpack_require__(345)); -var _ora = _interopRequireDefault(__webpack_require__(434)); +var _del = _interopRequireDefault(__webpack_require__(346)); +var _ora = _interopRequireDefault(__webpack_require__(435)); var _path = __webpack_require__(4); var _fs = __webpack_require__(131); var _log = __webpack_require__(145); @@ -40366,21 +40580,21 @@ const CleanCommand = exports.CleanCommand = { }; /***/ }), -/* 345 */ +/* 346 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(112); const path = __webpack_require__(4); -const globby = __webpack_require__(346); -const isGlob = __webpack_require__(358); -const slash = __webpack_require__(425); +const globby = __webpack_require__(347); +const isGlob = __webpack_require__(359); +const slash = __webpack_require__(426); const gracefulFs = __webpack_require__(133); -const isPathCwd = __webpack_require__(427); -const isPathInside = __webpack_require__(428); -const rimraf = __webpack_require__(429); -const pMap = __webpack_require__(430); +const isPathCwd = __webpack_require__(428); +const isPathInside = __webpack_require__(429); +const rimraf = __webpack_require__(430); +const pMap = __webpack_require__(431); const rimrafP = promisify(rimraf); @@ -40512,18 +40726,18 @@ module.exports.sync = (patterns, {force, dryRun, cwd = process.cwd(), ...options /***/ }), -/* 346 */ +/* 347 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const arrayUnion = __webpack_require__(347); -const merge2 = __webpack_require__(348); -const fastGlob = __webpack_require__(349); -const dirGlob = __webpack_require__(421); -const gitignore = __webpack_require__(423); -const {FilterStream, UniqueStream} = __webpack_require__(426); +const arrayUnion = __webpack_require__(348); +const merge2 = __webpack_require__(349); +const fastGlob = __webpack_require__(350); +const dirGlob = __webpack_require__(422); +const gitignore = __webpack_require__(424); +const {FilterStream, UniqueStream} = __webpack_require__(427); const DEFAULT_FILTER = () => false; @@ -40700,7 +40914,7 @@ module.exports.gitignore = gitignore; /***/ }), -/* 347 */ +/* 348 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40712,7 +40926,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 348 */ +/* 349 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40863,18 +41077,18 @@ function pauseStreams (streams, options) { /***/ }), -/* 349 */ +/* 350 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const taskManager = __webpack_require__(350); -const patternManager = __webpack_require__(379); -const async_1 = __webpack_require__(380); -const stream_1 = __webpack_require__(417); -const sync_1 = __webpack_require__(418); -const settings_1 = __webpack_require__(420); -const utils = __webpack_require__(351); +const taskManager = __webpack_require__(351); +const patternManager = __webpack_require__(380); +const async_1 = __webpack_require__(381); +const stream_1 = __webpack_require__(418); +const sync_1 = __webpack_require__(419); +const settings_1 = __webpack_require__(421); +const utils = __webpack_require__(352); async function FastGlob(source, options) { assertPatternsInput(source); const works = getWorks(source, async_1.default, options); @@ -40938,14 +41152,14 @@ module.exports = FastGlob; /***/ }), -/* 350 */ +/* 351 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.convertPatternGroupToTask = exports.convertPatternGroupsToTasks = exports.groupPatternsByBaseDirectory = exports.getNegativePatternsAsPositive = exports.getPositivePatterns = exports.convertPatternsToTasks = exports.generate = void 0; -const utils = __webpack_require__(351); +const utils = __webpack_require__(352); function generate(patterns, settings) { const positivePatterns = getPositivePatterns(patterns); const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); @@ -41025,31 +41239,31 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 351 */ +/* 352 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.string = exports.stream = exports.pattern = exports.path = exports.fs = exports.errno = exports.array = void 0; -const array = __webpack_require__(352); +const array = __webpack_require__(353); exports.array = array; -const errno = __webpack_require__(353); +const errno = __webpack_require__(354); exports.errno = errno; -const fs = __webpack_require__(354); +const fs = __webpack_require__(355); exports.fs = fs; -const path = __webpack_require__(355); +const path = __webpack_require__(356); exports.path = path; -const pattern = __webpack_require__(356); +const pattern = __webpack_require__(357); exports.pattern = pattern; -const stream = __webpack_require__(377); +const stream = __webpack_require__(378); exports.stream = stream; -const string = __webpack_require__(378); +const string = __webpack_require__(379); exports.string = string; /***/ }), -/* 352 */ +/* 353 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41078,7 +41292,7 @@ exports.splitWhen = splitWhen; /***/ }), -/* 353 */ +/* 354 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41092,7 +41306,7 @@ exports.isEnoentCodeError = isEnoentCodeError; /***/ }), -/* 354 */ +/* 355 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41118,7 +41332,7 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 355 */ +/* 356 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41158,7 +41372,7 @@ exports.removeLeadingDotSegment = removeLeadingDotSegment; /***/ }), -/* 356 */ +/* 357 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41166,8 +41380,8 @@ exports.removeLeadingDotSegment = removeLeadingDotSegment; Object.defineProperty(exports, "__esModule", { value: true }); exports.matchAny = exports.convertPatternsToRe = exports.makeRe = exports.getPatternParts = exports.expandBraceExpansion = exports.expandPatternsWithBraceExpansion = exports.isAffectDepthOfReadingPattern = exports.endsWithSlashGlobStar = exports.hasGlobStar = exports.getBaseDirectory = exports.isPatternRelatedToParentDirectory = exports.getPatternsOutsideCurrentDirectory = exports.getPatternsInsideCurrentDirectory = exports.getPositivePatterns = exports.getNegativePatterns = exports.isPositivePattern = exports.isNegativePattern = exports.convertToNegativePattern = exports.convertToPositivePattern = exports.isDynamicPattern = exports.isStaticPattern = void 0; const path = __webpack_require__(4); -const globParent = __webpack_require__(357); -const micromatch = __webpack_require__(360); +const globParent = __webpack_require__(358); +const micromatch = __webpack_require__(361); const GLOBSTAR = '**'; const ESCAPE_SYMBOL = '\\'; const COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/; @@ -41334,13 +41548,13 @@ exports.matchAny = matchAny; /***/ }), -/* 357 */ +/* 358 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isGlob = __webpack_require__(358); +var isGlob = __webpack_require__(359); var pathPosixDirname = __webpack_require__(4).posix.dirname; var isWin32 = __webpack_require__(121).platform() === 'win32'; @@ -41416,7 +41630,7 @@ function isGlobby(str) { /***/ }), -/* 358 */ +/* 359 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -41426,7 +41640,7 @@ function isGlobby(str) { * Released under the MIT License. */ -var isExtglob = __webpack_require__(359); +var isExtglob = __webpack_require__(360); var chars = { '{': '}', '(': ')', '[': ']'}; var strictCheck = function(str) { if (str[0] === '!') { @@ -41572,7 +41786,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 359 */ +/* 360 */ /***/ (function(module, exports) { /*! @@ -41598,16 +41812,16 @@ module.exports = function isExtglob(str) { /***/ }), -/* 360 */ +/* 361 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const util = __webpack_require__(112); -const braces = __webpack_require__(361); -const picomatch = __webpack_require__(371); -const utils = __webpack_require__(374); +const braces = __webpack_require__(362); +const picomatch = __webpack_require__(372); +const utils = __webpack_require__(375); const isEmptyString = val => val === '' || val === './'; /** @@ -42072,16 +42286,16 @@ module.exports = micromatch; /***/ }), -/* 361 */ +/* 362 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(362); -const compile = __webpack_require__(364); -const expand = __webpack_require__(368); -const parse = __webpack_require__(369); +const stringify = __webpack_require__(363); +const compile = __webpack_require__(365); +const expand = __webpack_require__(369); +const parse = __webpack_require__(370); /** * Expand the given pattern or create a regex-compatible string. @@ -42249,13 +42463,13 @@ module.exports = braces; /***/ }), -/* 362 */ +/* 363 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(363); +const utils = __webpack_require__(364); module.exports = (ast, options = {}) => { let stringify = (node, parent = {}) => { @@ -42288,7 +42502,7 @@ module.exports = (ast, options = {}) => { /***/ }), -/* 363 */ +/* 364 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -42407,14 +42621,14 @@ exports.flatten = (...args) => { /***/ }), -/* 364 */ +/* 365 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(365); -const utils = __webpack_require__(363); +const fill = __webpack_require__(366); +const utils = __webpack_require__(364); const compile = (ast, options = {}) => { let walk = (node, parent = {}) => { @@ -42471,7 +42685,7 @@ module.exports = compile; /***/ }), -/* 365 */ +/* 366 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -42485,7 +42699,7 @@ module.exports = compile; const util = __webpack_require__(112); -const toRegexRange = __webpack_require__(366); +const toRegexRange = __webpack_require__(367); const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); @@ -42727,7 +42941,7 @@ module.exports = fill; /***/ }), -/* 366 */ +/* 367 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -42740,7 +42954,7 @@ module.exports = fill; -const isNumber = __webpack_require__(367); +const isNumber = __webpack_require__(368); const toRegexRange = (min, max, options) => { if (isNumber(min) === false) { @@ -43022,7 +43236,7 @@ module.exports = toRegexRange; /***/ }), -/* 367 */ +/* 368 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43047,15 +43261,15 @@ module.exports = function(num) { /***/ }), -/* 368 */ +/* 369 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(365); -const stringify = __webpack_require__(362); -const utils = __webpack_require__(363); +const fill = __webpack_require__(366); +const stringify = __webpack_require__(363); +const utils = __webpack_require__(364); const append = (queue = '', stash = '', enclose = false) => { let result = []; @@ -43167,13 +43381,13 @@ module.exports = expand; /***/ }), -/* 369 */ +/* 370 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(362); +const stringify = __webpack_require__(363); /** * Constants @@ -43195,7 +43409,7 @@ const { CHAR_SINGLE_QUOTE, /* ' */ CHAR_NO_BREAK_SPACE, CHAR_ZERO_WIDTH_NOBREAK_SPACE -} = __webpack_require__(370); +} = __webpack_require__(371); /** * parse @@ -43507,7 +43721,7 @@ module.exports = parse; /***/ }), -/* 370 */ +/* 371 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43571,27 +43785,27 @@ module.exports = { /***/ }), -/* 371 */ +/* 372 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(372); +module.exports = __webpack_require__(373); /***/ }), -/* 372 */ +/* 373 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const scan = __webpack_require__(373); -const parse = __webpack_require__(376); -const utils = __webpack_require__(374); -const constants = __webpack_require__(375); +const scan = __webpack_require__(374); +const parse = __webpack_require__(377); +const utils = __webpack_require__(375); +const constants = __webpack_require__(376); const isObject = val => val && typeof val === 'object' && !Array.isArray(val); /** @@ -43930,13 +44144,13 @@ module.exports = picomatch; /***/ }), -/* 373 */ +/* 374 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(374); +const utils = __webpack_require__(375); const { CHAR_ASTERISK, /* * */ CHAR_AT, /* @ */ @@ -43953,7 +44167,7 @@ const { CHAR_RIGHT_CURLY_BRACE, /* } */ CHAR_RIGHT_PARENTHESES, /* ) */ CHAR_RIGHT_SQUARE_BRACKET /* ] */ -} = __webpack_require__(375); +} = __webpack_require__(376); const isPathSeparator = code => { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; @@ -44328,7 +44542,7 @@ module.exports = scan; /***/ }), -/* 374 */ +/* 375 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44341,7 +44555,7 @@ const { REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL -} = __webpack_require__(375); +} = __webpack_require__(376); exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); @@ -44399,7 +44613,7 @@ exports.wrapOutput = (input, state = {}, options = {}) => { /***/ }), -/* 375 */ +/* 376 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44585,14 +44799,14 @@ module.exports = { /***/ }), -/* 376 */ +/* 377 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const constants = __webpack_require__(375); -const utils = __webpack_require__(374); +const constants = __webpack_require__(376); +const utils = __webpack_require__(375); /** * Constants @@ -45683,14 +45897,14 @@ module.exports = parse; /***/ }), -/* 377 */ +/* 378 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.merge = void 0; -const merge2 = __webpack_require__(348); +const merge2 = __webpack_require__(349); function merge(streams) { const mergedStream = merge2(streams); streams.forEach((stream) => { @@ -45707,7 +45921,7 @@ function propagateCloseEventToSources(streams) { /***/ }), -/* 378 */ +/* 379 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45725,7 +45939,7 @@ exports.isEmpty = isEmpty; /***/ }), -/* 379 */ +/* 380 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45753,14 +45967,14 @@ exports.removeDuplicateSlashes = removeDuplicateSlashes; /***/ }), -/* 380 */ +/* 381 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(381); -const provider_1 = __webpack_require__(410); +const stream_1 = __webpack_require__(382); +const provider_1 = __webpack_require__(411); class ProviderAsync extends provider_1.default { constructor() { super(...arguments); @@ -45788,16 +46002,16 @@ exports.default = ProviderAsync; /***/ }), -/* 381 */ +/* 382 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(138); -const fsStat = __webpack_require__(382); -const fsWalk = __webpack_require__(387); -const reader_1 = __webpack_require__(409); +const fsStat = __webpack_require__(383); +const fsWalk = __webpack_require__(388); +const reader_1 = __webpack_require__(410); class ReaderStream extends reader_1.default { constructor() { super(...arguments); @@ -45850,16 +46064,16 @@ exports.default = ReaderStream; /***/ }), -/* 382 */ +/* 383 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.statSync = exports.stat = exports.Settings = void 0; -const async = __webpack_require__(383); -const sync = __webpack_require__(384); -const settings_1 = __webpack_require__(385); +const async = __webpack_require__(384); +const sync = __webpack_require__(385); +const settings_1 = __webpack_require__(386); exports.Settings = settings_1.default; function stat(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -45883,7 +46097,7 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 383 */ +/* 384 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45926,7 +46140,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 384 */ +/* 385 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45956,13 +46170,13 @@ exports.read = read; /***/ }), -/* 385 */ +/* 386 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(386); +const fs = __webpack_require__(387); class Settings { constructor(_options = {}) { this._options = _options; @@ -45979,7 +46193,7 @@ exports.default = Settings; /***/ }), -/* 386 */ +/* 387 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46003,17 +46217,17 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 387 */ +/* 388 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Settings = exports.walkStream = exports.walkSync = exports.walk = void 0; -const async_1 = __webpack_require__(388); -const stream_1 = __webpack_require__(405); -const sync_1 = __webpack_require__(406); -const settings_1 = __webpack_require__(408); +const async_1 = __webpack_require__(389); +const stream_1 = __webpack_require__(406); +const sync_1 = __webpack_require__(407); +const settings_1 = __webpack_require__(409); exports.Settings = settings_1.default; function walk(directory, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -46044,13 +46258,13 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 388 */ +/* 389 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(389); +const async_1 = __webpack_require__(390); class AsyncProvider { constructor(_root, _settings) { this._root = _root; @@ -46081,17 +46295,17 @@ function callSuccessCallback(callback, entries) { /***/ }), -/* 389 */ +/* 390 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = __webpack_require__(157); -const fsScandir = __webpack_require__(390); -const fastq = __webpack_require__(401); -const common = __webpack_require__(403); -const reader_1 = __webpack_require__(404); +const fsScandir = __webpack_require__(391); +const fastq = __webpack_require__(402); +const common = __webpack_require__(404); +const reader_1 = __webpack_require__(405); class AsyncReader extends reader_1.default { constructor(_root, _settings) { super(_root, _settings); @@ -46185,16 +46399,16 @@ exports.default = AsyncReader; /***/ }), -/* 390 */ +/* 391 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Settings = exports.scandirSync = exports.scandir = void 0; -const async = __webpack_require__(391); -const sync = __webpack_require__(398); -const settings_1 = __webpack_require__(399); +const async = __webpack_require__(392); +const sync = __webpack_require__(399); +const settings_1 = __webpack_require__(400); exports.Settings = settings_1.default; function scandir(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -46218,18 +46432,18 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 391 */ +/* 392 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.readdir = exports.readdirWithFileTypes = exports.read = void 0; -const fsStat = __webpack_require__(382); -const rpl = __webpack_require__(392); -const constants_1 = __webpack_require__(394); -const utils = __webpack_require__(395); -const common = __webpack_require__(397); +const fsStat = __webpack_require__(383); +const rpl = __webpack_require__(393); +const constants_1 = __webpack_require__(395); +const utils = __webpack_require__(396); +const common = __webpack_require__(398); function read(directory, settings, callback) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { readdirWithFileTypes(directory, settings, callback); @@ -46329,13 +46543,13 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 392 */ +/* 393 */ /***/ (function(module, exports, __webpack_require__) { /*! run-parallel. MIT License. Feross Aboukhadijeh */ module.exports = runParallel -const queueMicrotask = __webpack_require__(393) +const queueMicrotask = __webpack_require__(394) function runParallel (tasks, cb) { let results, pending, keys @@ -46386,7 +46600,7 @@ function runParallel (tasks, cb) { /***/ }), -/* 393 */ +/* 394 */ /***/ (function(module, exports) { /*! queue-microtask. MIT License. Feross Aboukhadijeh */ @@ -46401,7 +46615,7 @@ module.exports = typeof queueMicrotask === 'function' /***/ }), -/* 394 */ +/* 395 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46425,19 +46639,19 @@ exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = IS_MATCHED_BY_MAJOR || IS_MATCHED_B /***/ }), -/* 395 */ +/* 396 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fs = void 0; -const fs = __webpack_require__(396); +const fs = __webpack_require__(397); exports.fs = fs; /***/ }), -/* 396 */ +/* 397 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46463,7 +46677,7 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 397 */ +/* 398 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46483,17 +46697,17 @@ exports.joinPathSegments = joinPathSegments; /***/ }), -/* 398 */ +/* 399 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.readdir = exports.readdirWithFileTypes = exports.read = void 0; -const fsStat = __webpack_require__(382); -const constants_1 = __webpack_require__(394); -const utils = __webpack_require__(395); -const common = __webpack_require__(397); +const fsStat = __webpack_require__(383); +const constants_1 = __webpack_require__(395); +const utils = __webpack_require__(396); +const common = __webpack_require__(398); function read(directory, settings) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(directory, settings); @@ -46544,15 +46758,15 @@ exports.readdir = readdir; /***/ }), -/* 399 */ +/* 400 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsStat = __webpack_require__(382); -const fs = __webpack_require__(400); +const fsStat = __webpack_require__(383); +const fs = __webpack_require__(401); class Settings { constructor(_options = {}) { this._options = _options; @@ -46575,7 +46789,7 @@ exports.default = Settings; /***/ }), -/* 400 */ +/* 401 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46601,7 +46815,7 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 401 */ +/* 402 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46609,7 +46823,7 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /* eslint-disable no-var */ -var reusify = __webpack_require__(402) +var reusify = __webpack_require__(403) function fastqueue (context, worker, concurrency) { if (typeof context === 'function') { @@ -46891,7 +47105,7 @@ module.exports.promise = queueAsPromised /***/ }), -/* 402 */ +/* 403 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46931,7 +47145,7 @@ module.exports = reusify /***/ }), -/* 403 */ +/* 404 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46969,13 +47183,13 @@ exports.joinPathSegments = joinPathSegments; /***/ }), -/* 404 */ +/* 405 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const common = __webpack_require__(403); +const common = __webpack_require__(404); class Reader { constructor(_root, _settings) { this._root = _root; @@ -46987,14 +47201,14 @@ exports.default = Reader; /***/ }), -/* 405 */ +/* 406 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(138); -const async_1 = __webpack_require__(389); +const async_1 = __webpack_require__(390); class StreamProvider { constructor(_root, _settings) { this._root = _root; @@ -47028,13 +47242,13 @@ exports.default = StreamProvider; /***/ }), -/* 406 */ +/* 407 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(407); +const sync_1 = __webpack_require__(408); class SyncProvider { constructor(_root, _settings) { this._root = _root; @@ -47049,15 +47263,15 @@ exports.default = SyncProvider; /***/ }), -/* 407 */ +/* 408 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsScandir = __webpack_require__(390); -const common = __webpack_require__(403); -const reader_1 = __webpack_require__(404); +const fsScandir = __webpack_require__(391); +const common = __webpack_require__(404); +const reader_1 = __webpack_require__(405); class SyncReader extends reader_1.default { constructor() { super(...arguments); @@ -47115,14 +47329,14 @@ exports.default = SyncReader; /***/ }), -/* 408 */ +/* 409 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsScandir = __webpack_require__(390); +const fsScandir = __webpack_require__(391); class Settings { constructor(_options = {}) { this._options = _options; @@ -47148,15 +47362,15 @@ exports.default = Settings; /***/ }), -/* 409 */ +/* 410 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsStat = __webpack_require__(382); -const utils = __webpack_require__(351); +const fsStat = __webpack_require__(383); +const utils = __webpack_require__(352); class Reader { constructor(_settings) { this._settings = _settings; @@ -47188,17 +47402,17 @@ exports.default = Reader; /***/ }), -/* 410 */ +/* 411 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const deep_1 = __webpack_require__(411); -const entry_1 = __webpack_require__(414); -const error_1 = __webpack_require__(415); -const entry_2 = __webpack_require__(416); +const deep_1 = __webpack_require__(412); +const entry_1 = __webpack_require__(415); +const error_1 = __webpack_require__(416); +const entry_2 = __webpack_require__(417); class Provider { constructor(_settings) { this._settings = _settings; @@ -47243,14 +47457,14 @@ exports.default = Provider; /***/ }), -/* 411 */ +/* 412 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(351); -const partial_1 = __webpack_require__(412); +const utils = __webpack_require__(352); +const partial_1 = __webpack_require__(413); class DeepFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -47312,13 +47526,13 @@ exports.default = DeepFilter; /***/ }), -/* 412 */ +/* 413 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const matcher_1 = __webpack_require__(413); +const matcher_1 = __webpack_require__(414); class PartialMatcher extends matcher_1.default { match(filepath) { const parts = filepath.split('/'); @@ -47357,13 +47571,13 @@ exports.default = PartialMatcher; /***/ }), -/* 413 */ +/* 414 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(351); +const utils = __webpack_require__(352); class Matcher { constructor(_patterns, _settings, _micromatchOptions) { this._patterns = _patterns; @@ -47414,13 +47628,13 @@ exports.default = Matcher; /***/ }), -/* 414 */ +/* 415 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(351); +const utils = __webpack_require__(352); class EntryFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -47481,13 +47695,13 @@ exports.default = EntryFilter; /***/ }), -/* 415 */ +/* 416 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(351); +const utils = __webpack_require__(352); class ErrorFilter { constructor(_settings) { this._settings = _settings; @@ -47503,13 +47717,13 @@ exports.default = ErrorFilter; /***/ }), -/* 416 */ +/* 417 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(351); +const utils = __webpack_require__(352); class EntryTransformer { constructor(_settings) { this._settings = _settings; @@ -47536,15 +47750,15 @@ exports.default = EntryTransformer; /***/ }), -/* 417 */ +/* 418 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(138); -const stream_2 = __webpack_require__(381); -const provider_1 = __webpack_require__(410); +const stream_2 = __webpack_require__(382); +const provider_1 = __webpack_require__(411); class ProviderStream extends provider_1.default { constructor() { super(...arguments); @@ -47574,14 +47788,14 @@ exports.default = ProviderStream; /***/ }), -/* 418 */ +/* 419 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(419); -const provider_1 = __webpack_require__(410); +const sync_1 = __webpack_require__(420); +const provider_1 = __webpack_require__(411); class ProviderSync extends provider_1.default { constructor() { super(...arguments); @@ -47604,15 +47818,15 @@ exports.default = ProviderSync; /***/ }), -/* 419 */ +/* 420 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(382); -const fsWalk = __webpack_require__(387); -const reader_1 = __webpack_require__(409); +const fsStat = __webpack_require__(383); +const fsWalk = __webpack_require__(388); +const reader_1 = __webpack_require__(410); class ReaderSync extends reader_1.default { constructor() { super(...arguments); @@ -47654,7 +47868,7 @@ exports.default = ReaderSync; /***/ }), -/* 420 */ +/* 421 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47718,13 +47932,13 @@ exports.default = Settings; /***/ }), -/* 421 */ +/* 422 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(422); +const pathType = __webpack_require__(423); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -47800,7 +48014,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 422 */ +/* 423 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47850,7 +48064,7 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 423 */ +/* 424 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47858,9 +48072,9 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); const {promisify} = __webpack_require__(112); const fs = __webpack_require__(134); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(349); -const gitIgnore = __webpack_require__(424); -const slash = __webpack_require__(425); +const fastGlob = __webpack_require__(350); +const gitIgnore = __webpack_require__(425); +const slash = __webpack_require__(426); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -47977,7 +48191,7 @@ module.exports.sync = options => { /***/ }), -/* 424 */ +/* 425 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -48586,7 +48800,7 @@ if ( /***/ }), -/* 425 */ +/* 426 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48604,7 +48818,7 @@ module.exports = path => { /***/ }), -/* 426 */ +/* 427 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48657,7 +48871,7 @@ module.exports = { /***/ }), -/* 427 */ +/* 428 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48679,7 +48893,7 @@ module.exports = path_ => { /***/ }), -/* 428 */ +/* 429 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48698,7 +48912,7 @@ module.exports = (childPath, parentPath) => { /***/ }), -/* 429 */ +/* 430 */ /***/ (function(module, exports, __webpack_require__) { const assert = __webpack_require__(140) @@ -49064,12 +49278,12 @@ rimraf.sync = rimrafSync /***/ }), -/* 430 */ +/* 431 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(431); +const AggregateError = __webpack_require__(432); module.exports = async ( iterable, @@ -49152,13 +49366,13 @@ module.exports = async ( /***/ }), -/* 431 */ +/* 432 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(432); -const cleanStack = __webpack_require__(433); +const indentString = __webpack_require__(433); +const cleanStack = __webpack_require__(434); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); @@ -49206,7 +49420,7 @@ module.exports = AggregateError; /***/ }), -/* 432 */ +/* 433 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -49248,7 +49462,7 @@ module.exports = (string, count = 1, options) => { /***/ }), -/* 433 */ +/* 434 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -49295,12 +49509,12 @@ module.exports = (stack, options) => { /***/ }), -/* 434 */ +/* 435 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readline = __webpack_require__(435); +const readline = __webpack_require__(283); const chalk = __webpack_require__(436); const cliCursor = __webpack_require__(439); const cliSpinners = __webpack_require__(441); @@ -49660,12 +49874,6 @@ module.exports.promise = (action, options) => { }; -/***/ }), -/* 435 */ -/***/ (function(module, exports) { - -module.exports = require("readline"); - /***/ }), /* 436 */ /***/ (function(module, exports, __webpack_require__) { @@ -50141,7 +50349,7 @@ exports.toggle = (force, writableStream) => { "use strict"; -const onetime = __webpack_require__(301); +const onetime = __webpack_require__(302); const signalExit = __webpack_require__(274); module.exports = onetime(() => { @@ -57750,7 +57958,7 @@ exports.runCommand = runCommand; var _errors = __webpack_require__(164); var _log = __webpack_require__(145); var _projects = __webpack_require__(147); -var _projects_tree = __webpack_require__(343); +var _projects_tree = __webpack_require__(344); var _opensearch_dashboards = __webpack_require__(559); /* * SPDX-License-Identifier: Apache-2.0 @@ -57840,10 +58048,10 @@ Object.defineProperty(exports, "__esModule", { exports.OpenSearchDashboards = void 0; var _path = _interopRequireDefault(__webpack_require__(4)); var _multimatch = _interopRequireDefault(__webpack_require__(560)); -var _isPathInside = _interopRequireDefault(__webpack_require__(428)); -var _yarn_lock = __webpack_require__(333); +var _isPathInside = _interopRequireDefault(__webpack_require__(429)); +var _yarn_lock = __webpack_require__(334); var _projects = __webpack_require__(147); -var _config = __webpack_require__(330); +var _config = __webpack_require__(331); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } @@ -57983,7 +58191,7 @@ exports.OpenSearchDashboards = OpenSearchDashboards; "use strict"; const minimatch = __webpack_require__(151); -const arrayUnion = __webpack_require__(347); +const arrayUnion = __webpack_require__(348); const arrayDiffer = __webpack_require__(561); const arrify = __webpack_require__(562); @@ -58083,9 +58291,9 @@ Object.defineProperty(exports, "__esModule", { }); exports.buildProductionProjects = buildProductionProjects; var _cpy = _interopRequireDefault(__webpack_require__(565)); -var _del = _interopRequireDefault(__webpack_require__(345)); +var _del = _interopRequireDefault(__webpack_require__(346)); var _path = __webpack_require__(4); -var _config = __webpack_require__(330); +var _config = __webpack_require__(331); var _fs = __webpack_require__(131); var _log = __webpack_require__(145); var _package_json = __webpack_require__(166); @@ -58387,7 +58595,7 @@ module.exports = (source, destination, { "use strict"; -const AggregateError = __webpack_require__(431); +const AggregateError = __webpack_require__(432); module.exports = async ( iterable, @@ -58943,8 +59151,8 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var globParent = __webpack_require__(357); -var isGlob = __webpack_require__(358); +var globParent = __webpack_require__(358); +var isGlob = __webpack_require__(359); var micromatch = __webpack_require__(575); var GLOBSTAR = '**'; /** @@ -81438,7 +81646,7 @@ exports.flatten = flatten; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(348); +var merge2 = __webpack_require__(349); /** * Merge multiple streams and propagate their errors into one stream in parallel. */ @@ -82303,7 +82511,7 @@ module.exports = function hasGlob(val) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(359); +var isExtglob = __webpack_require__(360); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { diff --git a/packages/osd-pm/package.json b/packages/osd-pm/package.json index 94b2c327274d..f6c25309e992 100644 --- a/packages/osd-pm/package.json +++ b/packages/osd-pm/package.json @@ -56,6 +56,7 @@ "prettier": "^2.1.1", "read-pkg": "^5.2.0", "rxjs": "^6.5.5", + "semver": "^7.5.3", "strip-ansi": "^6.0.0", "strong-log-transformer": "^2.1.0", "tempy": "^0.3.0", diff --git a/packages/osd-pm/src/cli.ts b/packages/osd-pm/src/cli.ts index 420298aefb0d..63e9a1a274e7 100644 --- a/packages/osd-pm/src/cli.ts +++ b/packages/osd-pm/src/cli.ts @@ -42,7 +42,7 @@ function help() { dedent` usage: osd [] - By default commands are run for OpenSearch Dashboards itself, all packages in the 'packages/' + By default, commands are run for OpenSearch Dashboards itself, all packages in the 'packages/' folder and for all plugins in './plugins' and '../opensearch-dashboards-extra'. Available commands: @@ -57,6 +57,7 @@ function help() { -i, --include Include only specified projects. If left unspecified, it defaults to including all projects. --skip-opensearch-dashboards-plugins Filter all plugins in ./plugins and ../opensearch-dashboards-extra when running command. --no-cache Disable the bootstrap cache + --single-version Set single version validation method: 'strict', 'loose', 'ignore', or 'brute-force' --verbose Set log level to verbose --debug Set log level to debug --quiet Set log level to error @@ -92,6 +93,7 @@ export async function run(argv: string[]) { cache: true, }, boolean: ['prefer-offline', 'frozen-lockfile', 'cache'], + string: ['single-version'], }); const args = options._; diff --git a/packages/osd-pm/src/commands/bootstrap.ts b/packages/osd-pm/src/commands/bootstrap.ts index 54d48daa5f54..b3a0551f6111 100644 --- a/packages/osd-pm/src/commands/bootstrap.ts +++ b/packages/osd-pm/src/commands/bootstrap.ts @@ -69,7 +69,7 @@ export const BootstrapCommand: ICommand = { const yarnLock = await readYarnLock(osd); - await validateDependencies(osd, yarnLock); + await validateDependencies(osd, yarnLock, options['single-version']?.toLowerCase?.()); await linkProjectExecutables(projects, projectGraph); diff --git a/packages/osd-pm/src/utils/project.ts b/packages/osd-pm/src/utils/project.ts index 3eddcfd472bb..4d3c545dcaea 100644 --- a/packages/osd-pm/src/utils/project.ts +++ b/packages/osd-pm/src/utils/project.ts @@ -28,8 +28,8 @@ * under the License. */ -import fs from 'fs'; -import Path from 'path'; +import { existsSync, unlinkSync } from 'fs'; +import { resolve, relative } from 'path'; import { inspect } from 'util'; import { CliError } from './errors'; @@ -43,6 +43,7 @@ import { } from './package_json'; import { installInDir, + patchFile, runScriptInPackage, runScriptInPackageStreaming, yarnWorkspacesInfo, @@ -97,9 +98,9 @@ export class Project { this.json = Object.freeze(packageJson); this.path = projectPath; - this.packageJsonLocation = Path.resolve(this.path, 'package.json'); - this.nodeModulesLocation = Path.resolve(this.path, 'node_modules'); - this.targetLocation = Path.resolve(this.path, 'target'); + this.packageJsonLocation = resolve(this.path, 'package.json'); + this.nodeModulesLocation = resolve(this.path, 'node_modules'); + this.targetLocation = resolve(this.path, 'target'); this.version = this.json.version; this.productionDependencies = this.json.dependencies || {}; @@ -130,7 +131,7 @@ export class Project { if (dependentProjectIsInWorkspace) { expectedVersionInPackageJson = project.json.version; } else { - const relativePathToProject = normalizePath(Path.relative(this.path, project.path)); + const relativePathToProject = normalizePath(relative(this.path, project.path)); expectedVersionInPackageJson = `link:${relativePathToProject}`; } @@ -168,7 +169,7 @@ export class Project { * instead of everything located in the project directory. */ public getIntermediateBuildDirectory() { - return Path.resolve(this.path, this.getBuildConfig().intermediateBuildDirectory || '.'); + return resolve(this.path, this.getBuildConfig().intermediateBuildDirectory || '.'); } public getCleanConfig(): CleanConfig { @@ -196,14 +197,14 @@ export class Project { if (typeof raw === 'string') { return { - [this.name]: Path.resolve(this.path, raw), + [this.name]: resolve(this.path, raw), }; } if (typeof raw === 'object') { const binsConfig: { [k: string]: string } = {}; for (const binName of Object.keys(raw)) { - binsConfig[binName] = Path.resolve(this.path, raw[binName]); + binsConfig[binName] = resolve(this.path, raw[binName]); } return binsConfig; } @@ -261,6 +262,49 @@ export class Project { await this.removeExtraneousNodeModules(); } + /** + * Install a specific version of a dependency and update the package.json. + * When a range is not specified, ^ is used. The range is then + * placed in the package.json with intentionally no validation. + */ + public async installDependencyVersion( + depName: string, + version: string, + dev: boolean = false, + range?: string + ) { + log.info(`[${this.name}] running yarn to install ${depName}@${version}`); + + log.write(''); + + const rangeToUse = range || `^${version}`; + + const extraArgs = [`${depName}@${version}`]; + if (dev) extraArgs.push('--dev'); + + if (this.isWorkspaceProject) { + await installInDir(this.path); + } else { + await installInDir(this.path, extraArgs, true); + } + + await patchFile( + this.packageJsonLocation, + `"${depName}": "${version}"`, + `"${depName}": "${rangeToUse}"` + ); + // The lock-file of workspace packages are symlinked to the root project's and editing the one in the project suffices + await patchFile( + resolve(this.path, 'yarn.lock'), + `${depName}@${version}`, + `${depName}@${rangeToUse}` + ); + + log.write(''); + + await this.removeExtraneousNodeModules(); + } + /** * Yarn workspaces symlinks workspace projects to the root node_modules, even * when there is no depenency on the project. This results in unnecicary, and @@ -283,13 +327,13 @@ export class Project { unusedWorkspaces.forEach((name) => { const { dependencies, devDependencies } = this.json; - const nodeModulesPath = Path.resolve(this.nodeModulesLocation, name); + const nodeModulesPath = resolve(this.nodeModulesLocation, name); const isDependency = dependencies && dependencies.hasOwnProperty(name); const isDevDependency = devDependencies && devDependencies.hasOwnProperty(name); - if (!isDependency && !isDevDependency && fs.existsSync(nodeModulesPath)) { + if (!isDependency && !isDevDependency && existsSync(nodeModulesPath)) { log.debug(`No dependency on ${name}, removing link in node_modules`); - fs.unlinkSync(nodeModulesPath); + unlinkSync(nodeModulesPath); } }); } diff --git a/packages/osd-pm/src/utils/scripts.ts b/packages/osd-pm/src/utils/scripts.ts index cbb49875c021..7011c09fb585 100644 --- a/packages/osd-pm/src/utils/scripts.ts +++ b/packages/osd-pm/src/utils/scripts.ts @@ -28,6 +28,8 @@ * under the License. */ +import { createReadStream, createWriteStream, unlinkSync, renameSync } from 'fs'; +import { createInterface } from 'readline'; import { spawn, spawnStreaming } from './child_process'; import { Project } from './project'; @@ -45,8 +47,8 @@ interface WorkspacesInfo { /** * Install all dependencies in the given directory */ -export async function installInDir(directory: string, extraArgs: string[] = []) { - const options = ['install', '--non-interactive', ...extraArgs]; +export async function installInDir(directory: string, extraArgs: string[] = [], useAdd = false) { + const options = [useAdd ? 'add' : 'install', '--non-interactive', ...extraArgs]; // We pass the mutex flag to ensure only one instance of yarn runs at any // given time (e.g. to avoid conflicts). @@ -55,6 +57,40 @@ export async function installInDir(directory: string, extraArgs: string[] = []) }); } +/** + * Patch a file by replacing a given string + */ +export function patchFile( + filePath: string, + searchValue: string, + replacement: string +): Promise { + return new Promise(async (resolve, reject) => { + const patchWriter = createWriteStream(`${filePath}.patched`, { + flags: 'w', + }); + const fileReader = createInterface({ + input: createReadStream(filePath), + crlfDelay: Infinity, + }); + for await (const line of fileReader) { + if (line.includes(searchValue)) { + patchWriter.write(line.replace(searchValue, replacement) + '\n', 'utf8'); + } else { + patchWriter.write(line + '\n', 'utf8'); + } + } + + patchWriter.on('finish', () => resolve()); + patchWriter.on('error', reject); + + fileReader.close(); + patchWriter.end(); + unlinkSync(filePath); + renameSync(`${filePath}.patched`, filePath); + }); +} + /** * Run script in the given directory */ diff --git a/packages/osd-pm/src/utils/validate_dependencies.ts b/packages/osd-pm/src/utils/validate_dependencies.ts index 2264681b986c..1496d93820d1 100644 --- a/packages/osd-pm/src/utils/validate_dependencies.ts +++ b/packages/osd-pm/src/utils/validate_dependencies.ts @@ -29,9 +29,12 @@ */ // @ts-expect-error published types are useless -import { stringify as stringifyLockfile } from '@yarnpkg/lockfile'; +import { stringify as stringifyLockfile, parse as parseLockFile } from '@yarnpkg/lockfile'; import dedent from 'dedent'; import chalk from 'chalk'; +import path from 'path'; +import { readFileSync } from 'fs'; +import { satisfies, rcompare } from 'semver'; import { writeFile } from './fs'; import { OpenSearchDashboards } from '../utils/opensearch_dashboards'; @@ -40,8 +43,39 @@ import { log } from './log'; import { Project } from './project'; import { ITree, treeToString } from './projects_tree'; -export async function validateDependencies(osd: OpenSearchDashboards, yarnLock: YarnLock) { - // look through all of the packages in the yarn.lock file to see if +enum SingleVersionResolution { + STRICT = 'strict', + LOOSE = 'loose', + BRUTE_FORCE = 'brute-force', + IGNORE = 'ignore', +} + +export async function validateDependencies( + osd: OpenSearchDashboards, + yarnLock: YarnLock, + /* `singleVersionResolution` controls how violations of single-version-dependencies is applied. + * STRICT (default): throw an error and exit + * LOOSE: identify and install a single version that satisfies all ranges + * BRUTE_FORCE: identify and install the newest version + * IGNORE: show all errors without exiting + * + * `LOOSE`: + * Reconciles the various versions installed as a result of having multiple ranges for a dependency, by + * choosing one that satisfies all said ranges. Even though installing the chosen version updates the + * lock-files, no package.json changes would be needed. + * + * `BRUTE_FORCE`: + * With no care for reconciliation, the newest of the various versions installed is chosen, irrespective of + * whether it satisfies any of the ranges. Installing the chosen version updates the lock-files and a range + * in the form of `^` is applied to all `package.json` files that declared the dependency. + * + * `IGNORE`: + * Behaves just like `strict` by showing errors when different ranges of a package are marked as + * dependencies, but it does not terminate the script. + */ + singleVersionResolution: SingleVersionResolution = SingleVersionResolution.STRICT +) { + // look through all the packages in the yarn.lock file to see if // we have accidentally installed multiple lodash v4 versions const lodash4Versions = new Set(); const lodash4Reqs = new Set(); @@ -109,11 +143,17 @@ export async function validateDependencies(osd: OpenSearchDashboards, yarnLock: process.exit(1); } - // TODO: remove this once we move into a single package.json + let hasIssues = false; + // look through all the package.json files to find packages which have mismatched version ranges const depRanges = new Map>(); for (const project of osd.getAllProjects().values()) { - for (const [dep, range] of Object.entries(project.allDependencies)) { + for (const [dep, range] of Object.entries( + // Don't be bothered with validating dev-deps when validating single-version loosely + singleVersionResolution === SingleVersionResolution.LOOSE + ? project.productionDependencies + : project.allDependencies + )) { const existingDep = depRanges.get(dep); if (!existingDep) { depRanges.set(dep, [ @@ -138,21 +178,166 @@ export async function validateDependencies(osd: OpenSearchDashboards, yarnLock: } } - const duplicateRanges = Array.from(depRanges.entries()) - .filter(([, ranges]) => ranges.length > 1) - .reduce( - (acc: string[], [dep, ranges]) => [ - ...acc, - dep, - ...ranges.map( - ({ range, projects }) => ` ${range} => ${projects.map((p) => p.name).join(', ')}` - ), - ], - [] - ) - .join('\n '); - - if (duplicateRanges) { + const cachedManifests = new Map(); + const violatingSingleVersionDepRanges = new Map< + string, + Array<{ range: string; projects: Project[] }> + >(); + for (const [depName, ranges] of depRanges) { + // No violation if just a single range of a dependency is used + if (ranges.length === 1) continue; + + const installedVersions = new Set(); + const installedDepVersionsCache = new Map(); + const desiredRanges = new Map(); + + depLoop: for (const { range, projects } of ranges) { + for (const project of projects) { + if (!cachedManifests.has(project.path)) + cachedManifests.set( + project.path, + // If there are errors reading or parsing the lockfiles, don't catch and let them fall through + parseLockFile(readFileSync(path.join(project.path, 'yarn.lock'), 'utf-8')) + ); + const { object: deps } = cachedManifests.get(project.path); + if (deps?.[`${depName}@${range}`]?.version) { + installedVersions.add(deps[`${depName}@${range}`].version); + installedDepVersionsCache.set( + `${project.name}#${depName}`, + deps[`${depName}@${range}`].version + ); + } else { + log.warning(`Failed to find the installed version for ${depName}@${range}`); + // If we cannot read any one of the installed versions of a depName, there is no point in continuing with it + installedVersions.clear(); + desiredRanges.clear(); + break depLoop; + } + } + + desiredRanges.set(range, projects); + } + + if (installedVersions.size === 0) { + // More than one range is used but couldn't get all the installed versions: call out violation + violatingSingleVersionDepRanges.set(depName, ranges); + } else if ( + singleVersionResolution === SingleVersionResolution.LOOSE && + installedVersions.size === 1 + ) { + hasIssues = true; + + /* When validating single-version loosely, ignore multiple ranges when they result in the installation of + * a single version. + */ + log.info( + `Ignored single version requirement for ${depName} as all installations are using v${ + installedVersions.values().next().value + }.` + ); + } else { + const sortedInstalledVersion = Array.from(installedVersions).sort(rcompare); + const rangePatterns = Array.from(desiredRanges.keys()); + + if (singleVersionResolution === SingleVersionResolution.BRUTE_FORCE) { + hasIssues = true; + + const suitableVersion = sortedInstalledVersion[0]; + const suitableRange = `^${suitableVersion}`; + + // Install the version on all projects that have this dep; use the suitable range. + for (const { projects } of ranges) { + for (const project of projects) { + await project.installDependencyVersion( + depName, + suitableVersion, + depName in project.devDependencies, + suitableRange + ); + } + } + + const conflictingRanges = ranges + .map(({ range, projects }) => `${range} => ${projects.map((p) => p.name).join(', ')}`) + .join('\n '); + log.warning(dedent` + + [single_version_dependencies] Multiple version ranges for package "${depName}" + were found across different package.json files. A version, v${suitableVersion}, was identified as the most recent + already installed replacement. All package.json files have been updated to indicate a dependency on \`${depName}@${suitableRange}\`. + + The conflicting version ranges are: + ${conflictingRanges} + `); + } else if (singleVersionResolution === SingleVersionResolution.LOOSE) { + let isCommonGroundFound = false; + for (const installedVersion of sortedInstalledVersion) { + if (rangePatterns.every((range) => satisfies(installedVersion, range))) { + isCommonGroundFound = true; + + // Install the version on all projects that have this dep; keep the original range. + for (const { range, projects } of ranges) { + for (const project of projects) { + // Don't bother updating anything if the desired version is already installed + if ( + installedDepVersionsCache.get(`${project.name}#${depName}`) === installedVersion + ) + continue; + + await project.installDependencyVersion( + depName, + installedVersion, + depName in project.devDependencies, + // When validating single-version loosely, when a version change is needed, the range shouldn't change + range + ); + } + } + + hasIssues = true; + + const conflictingRanges = ranges + .map(({ range, projects }) => `${range} => ${projects.map((p) => p.name).join(', ')}`) + .join('\n '); + log.warning(dedent` + + [single_version_dependencies] Multiple version ranges for package "${depName}" + were found across different package.json files. A suitable version, v${installedVersion}, was + identified and installed. + + The conflicting version ranges are: + ${conflictingRanges} + `); + + // A usable version was identified so no need to check the lower versions + break; + } + } + if (!isCommonGroundFound) { + // When validating single-version loosely and no installed version satisfies all ranges, call out violation + violatingSingleVersionDepRanges.set(depName, ranges); + } + } else { + // When validating single-version, not loosly or with brute-force, call out violation + violatingSingleVersionDepRanges.set(depName, ranges); + } + } + } + + if (violatingSingleVersionDepRanges.size > 0) { + const duplicateRanges = Array.from(violatingSingleVersionDepRanges.entries()) + .reduce( + (acc: string[], [dep, ranges]) => [ + ...acc, + dep, + ...ranges.map( + ({ range, projects }) => ` ${range} => ${projects.map((p) => p.name).join(', ')}` + ), + ], + [] + ) + .join('\n '); + log.error(dedent` [single_version_dependencies] Multiple version ranges for the same dependency @@ -167,10 +352,12 @@ export async function validateDependencies(osd: OpenSearchDashboards, yarnLock: ${duplicateRanges} `); - process.exit(1); + if (singleVersionResolution !== SingleVersionResolution.IGNORE) { + process.exit(1); + } } - // look for packages that have the the `opensearchDashboards.devOnly` flag in their package.json + // look for packages that have the `opensearchDashboards.devOnly` flag in their package.json // and make sure they aren't included in the production dependencies of OpenSearch Dashboards const devOnlyProjectsInProduction = getDevOnlyProductionDepsTree(osd, 'opensearch-dashboards'); if (devOnlyProjectsInProduction) { @@ -187,7 +374,9 @@ export async function validateDependencies(osd: OpenSearchDashboards, yarnLock: process.exit(1); } - log.success('yarn.lock analysis completed without any issues'); + log.success( + hasIssues ? 'yarn.lock analysis completed' : 'yarn.lock analysis completed without any issues' + ); } function getDevOnlyProductionDepsTree(osd: OpenSearchDashboards, projectName: string) {