@yarnpkg/plugin-essentials 4.0.0-rc.9 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/add.d.ts +1 -1
- package/lib/commands/add.js +34 -25
- package/lib/commands/bin.d.ts +1 -1
- package/lib/commands/bin.js +1 -1
- package/lib/commands/cache/clean.d.ts +1 -1
- package/lib/commands/cache/clean.js +1 -1
- package/lib/commands/config/get.d.ts +2 -1
- package/lib/commands/config/get.js +4 -1
- package/lib/commands/config/set.d.ts +1 -1
- package/lib/commands/config/set.js +1 -1
- package/lib/commands/config/unset.d.ts +1 -1
- package/lib/commands/config/unset.js +1 -1
- package/lib/commands/config.d.ts +5 -3
- package/lib/commands/config.js +96 -39
- package/lib/commands/dedupe.d.ts +1 -1
- package/lib/commands/dedupe.js +7 -8
- package/lib/commands/entries/clipanion.js +1 -1
- package/lib/commands/entries/help.js +1 -1
- package/lib/commands/entries/version.js +1 -1
- package/lib/commands/exec.js +1 -1
- package/lib/commands/explain/peerRequirements.d.ts +3 -3
- package/lib/commands/explain/peerRequirements.js +75 -106
- package/lib/commands/explain.js +1 -1
- package/lib/commands/info.js +10 -18
- package/lib/commands/install.d.ts +1 -1
- package/lib/commands/install.js +245 -205
- package/lib/commands/link.d.ts +2 -2
- package/lib/commands/link.js +36 -32
- package/lib/commands/node.js +1 -1
- package/lib/commands/plugin/check.d.ts +8 -0
- package/lib/commands/plugin/check.js +61 -0
- package/lib/commands/plugin/import/sources.d.ts +3 -3
- package/lib/commands/plugin/import/sources.js +5 -5
- package/lib/commands/plugin/import.d.ts +5 -4
- package/lib/commands/plugin/import.js +15 -28
- package/lib/commands/plugin/list.d.ts +2 -2
- package/lib/commands/plugin/list.js +5 -6
- package/lib/commands/plugin/remove.d.ts +1 -1
- package/lib/commands/plugin/remove.js +14 -13
- package/lib/commands/plugin/runtime.d.ts +2 -2
- package/lib/commands/plugin/runtime.js +4 -4
- package/lib/commands/rebuild.d.ts +2 -2
- package/lib/commands/rebuild.js +10 -10
- package/lib/commands/remove.d.ts +1 -1
- package/lib/commands/remove.js +7 -8
- package/lib/commands/run.js +1 -1
- package/lib/commands/runIndex.d.ts +2 -2
- package/lib/commands/runIndex.js +3 -3
- package/lib/commands/set/resolution.d.ts +1 -1
- package/lib/commands/set/resolution.js +4 -6
- package/lib/commands/set/version/sources.d.ts +3 -2
- package/lib/commands/set/version/sources.js +21 -12
- package/lib/commands/set/version.d.ts +2 -3
- package/lib/commands/set/version.js +20 -16
- package/lib/commands/unlink.d.ts +1 -1
- package/lib/commands/unlink.js +7 -8
- package/lib/commands/up.d.ts +3 -3
- package/lib/commands/up.js +19 -17
- package/lib/commands/why.js +5 -13
- package/lib/commands/workspace.js +2 -5
- package/lib/commands/workspaces/list.d.ts +2 -1
- package/lib/commands/workspaces/list.js +8 -1
- package/lib/dedupeUtils.d.ts +3 -3
- package/lib/dedupeUtils.js +3 -5
- package/lib/index.d.ts +76 -1
- package/lib/index.js +40 -1
- package/lib/suggestUtils.d.ts +4 -4
- package/lib/suggestUtils.js +14 -12
- package/package.json +22 -17
package/lib/commands/install.js
CHANGED
|
@@ -7,7 +7,21 @@ const fslib_1 = require("@yarnpkg/fslib");
|
|
|
7
7
|
const parsers_1 = require("@yarnpkg/parsers");
|
|
8
8
|
const ci_info_1 = tslib_1.__importDefault(require("ci-info"));
|
|
9
9
|
const clipanion_1 = require("clipanion");
|
|
10
|
+
const semver_1 = tslib_1.__importDefault(require("semver"));
|
|
10
11
|
const t = tslib_1.__importStar(require("typanion"));
|
|
12
|
+
const LOCKFILE_MIGRATION_RULES = [{
|
|
13
|
+
selector: v => v === -1,
|
|
14
|
+
name: `nodeLinker`,
|
|
15
|
+
value: `node-modules`,
|
|
16
|
+
}, {
|
|
17
|
+
selector: v => v !== -1 && v < 8,
|
|
18
|
+
name: `enableGlobalCache`,
|
|
19
|
+
value: false,
|
|
20
|
+
}, {
|
|
21
|
+
selector: v => v !== -1 && v < 8,
|
|
22
|
+
name: `compressionLevel`,
|
|
23
|
+
value: `mixed`,
|
|
24
|
+
}];
|
|
11
25
|
// eslint-disable-next-line arca/no-default-export
|
|
12
26
|
class YarnCommand extends cli_1.BaseCommand {
|
|
13
27
|
constructor() {
|
|
@@ -49,7 +63,6 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
49
63
|
this.networkTimeout = clipanion_1.Option.String(`--network-timeout`, { hidden: true });
|
|
50
64
|
}
|
|
51
65
|
async execute() {
|
|
52
|
-
var _a, _b, _c;
|
|
53
66
|
const configuration = await core_1.Configuration.find(this.context.cwd, this.context.plugins);
|
|
54
67
|
if (typeof this.inlineBuilds !== `undefined`)
|
|
55
68
|
configuration.useWithSource(`<cli>`, { enableInlineBuilds: this.inlineBuilds }, configuration.startingCwd, { overwrite: true });
|
|
@@ -57,113 +70,72 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
57
70
|
// in process of deploying Google Cloud Functions and
|
|
58
71
|
// Google App Engine
|
|
59
72
|
const isGCP = !!process.env.FUNCTION_TARGET || !!process.env.GOOGLE_RUNTIME;
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
});
|
|
73
|
-
if (deprecationReport.hasErrors()) {
|
|
74
|
-
return deprecationReport.exitCode();
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
// The ignoreEngines flag isn't implemented at the moment. I'm still
|
|
81
|
-
// considering how it should work in the context of plugins - would it
|
|
82
|
-
// make sense to allow them (or direct dependencies) to define new
|
|
83
|
-
// "engine check"? Since it has implications regarding the architecture,
|
|
84
|
-
// I prefer to postpone the decision to later. Also it wouldn't be a flag,
|
|
85
|
-
// it would definitely be a configuration setting.
|
|
86
|
-
if (typeof this.ignoreEngines !== `undefined`) {
|
|
87
|
-
const exitCode = await reportDeprecation(`The --ignore-engines option is deprecated; engine checking isn't a core feature anymore`, {
|
|
73
|
+
const deprecationExitCode = await (0, core_1.reportOptionDeprecations)({
|
|
74
|
+
configuration,
|
|
75
|
+
stdout: this.context.stdout,
|
|
76
|
+
}, [{
|
|
77
|
+
// The ignoreEngines flag isn't implemented at the moment. I'm still
|
|
78
|
+
// considering how it should work in the context of plugins - would it
|
|
79
|
+
// make sense to allow them (or direct dependencies) to define new
|
|
80
|
+
// "engine check"? Since it has implications regarding the architecture,
|
|
81
|
+
// I prefer to postpone the decision to later. Also it wouldn't be a flag,
|
|
82
|
+
// it would definitely be a configuration setting.
|
|
83
|
+
option: this.ignoreEngines,
|
|
84
|
+
message: `The --ignore-engines option is deprecated; engine checking isn't a core feature anymore`,
|
|
88
85
|
error: !ci_info_1.default.VERCEL,
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// The preferOffline flag doesn't make much sense with our architecture.
|
|
108
|
-
// It would require the fetchers to also act as resolvers, which is
|
|
109
|
-
// doable but quirky. Since a similar behavior is available via the
|
|
110
|
-
// --cached flag in yarn add, I prefer to move it outside of the core and
|
|
111
|
-
// let someone implement this "resolver-that-reads-the-cache" logic.
|
|
112
|
-
if (typeof this.preferOffline !== `undefined`) {
|
|
113
|
-
const exitCode = await reportDeprecation(`The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead`, {
|
|
86
|
+
}, {
|
|
87
|
+
// The registry flag isn't supported anymore because it makes little sense
|
|
88
|
+
// to use a registry for a single install. You instead want to configure it
|
|
89
|
+
// for all installs inside a project, so through the .yarnrc.yml file. Note
|
|
90
|
+
// that if absolutely necessary, the old behavior can be emulated by adding
|
|
91
|
+
// the YARN_NPM_REGISTRY_SERVER variable to the environment.
|
|
92
|
+
option: this.registry,
|
|
93
|
+
message: `The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file`,
|
|
94
|
+
}, {
|
|
95
|
+
// The preferOffline flag doesn't make much sense with our architecture.
|
|
96
|
+
// It would require the fetchers to also act as resolvers, which is
|
|
97
|
+
// doable but quirky. Since a similar behavior is available via the
|
|
98
|
+
// --cached flag in yarn add, I prefer to move it outside of the core and
|
|
99
|
+
// let someone implement this "resolver-that-reads-the-cache" logic.
|
|
100
|
+
option: this.preferOffline,
|
|
101
|
+
message: `The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead`,
|
|
114
102
|
error: !ci_info_1.default.VERCEL,
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// Instead, we expect users to use it with `yarn workspaces focus` (which can
|
|
123
|
-
// be used even outside of monorepos).
|
|
124
|
-
if (typeof this.production !== `undefined`) {
|
|
125
|
-
const exitCode = await reportDeprecation(`The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead`, {
|
|
103
|
+
}, {
|
|
104
|
+
// Since the production flag would yield a different lockfile than the
|
|
105
|
+
// regular installs, it's not part of the regular `install` command anymore.
|
|
106
|
+
// Instead, we expect users to use it with `yarn workspaces focus` (which can
|
|
107
|
+
// be used even outside of monorepos).
|
|
108
|
+
option: this.production,
|
|
109
|
+
message: `The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead`,
|
|
126
110
|
error: true,
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// Yarn 2 isn't interactive during installs anyway, so there's no real point
|
|
133
|
-
// to this flag at the moment.
|
|
134
|
-
if (typeof this.nonInteractive !== `undefined`) {
|
|
135
|
-
const exitCode = await reportDeprecation(`The --non-interactive option is deprecated`, {
|
|
111
|
+
}, {
|
|
112
|
+
// Yarn 2+ isn't interactive during installs anyway, so there's no real point
|
|
113
|
+
// to this flag at the moment.
|
|
114
|
+
option: this.nonInteractive,
|
|
115
|
+
message: `The --non-interactive option is deprecated`,
|
|
136
116
|
error: !isGCP,
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// We also want to prevent them from using --cache-folder
|
|
152
|
-
// Note: it's been deprecated because the cache folder should be set from
|
|
153
|
-
// the settings. Otherwise there would be a very high chance that multiple
|
|
154
|
-
// Yarn commands would use different caches, causing unexpected behaviors.
|
|
155
|
-
if (typeof this.cacheFolder !== `undefined`) {
|
|
156
|
-
const exitCode = await reportDeprecation(`The cache-folder option has been deprecated; use rc settings instead`, {
|
|
117
|
+
}, {
|
|
118
|
+
// We want to prevent people from using --frozen-lockfile
|
|
119
|
+
// Note: it's been deprecated because we're now locking more than just the
|
|
120
|
+
// lockfile - for example the PnP artifacts will also be locked.
|
|
121
|
+
option: this.frozenLockfile,
|
|
122
|
+
message: `The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead`,
|
|
123
|
+
callback: () => this.immutable = this.frozenLockfile,
|
|
124
|
+
}, {
|
|
125
|
+
// We also want to prevent them from using --cache-folder
|
|
126
|
+
// Note: it's been deprecated because the cache folder should be set from
|
|
127
|
+
// the settings. Otherwise there would be a very high chance that multiple
|
|
128
|
+
// Yarn commands would use different caches, causing unexpected behaviors.
|
|
129
|
+
option: this.cacheFolder,
|
|
130
|
+
message: `The cache-folder option has been deprecated; use rc settings instead`,
|
|
157
131
|
error: !ci_info_1.default.NETLIFY,
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
}
|
|
132
|
+
}]);
|
|
133
|
+
if (deprecationExitCode !== null)
|
|
134
|
+
return deprecationExitCode;
|
|
163
135
|
const updateMode = this.mode === core_1.InstallMode.UpdateLockfile;
|
|
164
136
|
if (updateMode && (this.immutable || this.immutableCache))
|
|
165
137
|
throw new clipanion_1.UsageError(`${core_1.formatUtils.pretty(configuration, `--immutable`, core_1.formatUtils.Type.CODE)} and ${core_1.formatUtils.pretty(configuration, `--immutable-cache`, core_1.formatUtils.Type.CODE)} cannot be used with ${core_1.formatUtils.pretty(configuration, `--mode=update-lockfile`, core_1.formatUtils.Type.CODE)}`);
|
|
166
|
-
const immutable = (
|
|
138
|
+
const immutable = (this.immutable ?? configuration.get(`enableImmutableInstalls`)) && !updateMode;
|
|
167
139
|
const immutableCache = this.immutableCache && !updateMode;
|
|
168
140
|
if (configuration.projectCwd !== null) {
|
|
169
141
|
const fixReport = await core_1.StreamReport.start({
|
|
@@ -172,8 +144,16 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
172
144
|
stdout: this.context.stdout,
|
|
173
145
|
includeFooter: false,
|
|
174
146
|
}, async (report) => {
|
|
147
|
+
let changed = false;
|
|
148
|
+
if (await autofixLegacyPlugins(configuration, immutable)) {
|
|
149
|
+
report.reportInfo(core_1.MessageName.AUTOMERGE_SUCCESS, `Automatically removed core plugins that are now builtins 👍`);
|
|
150
|
+
changed = true;
|
|
151
|
+
}
|
|
175
152
|
if (await autofixMergeConflicts(configuration, immutable)) {
|
|
176
153
|
report.reportInfo(core_1.MessageName.AUTOMERGE_SUCCESS, `Automatically fixed merge conflicts 👍`);
|
|
154
|
+
changed = true;
|
|
155
|
+
}
|
|
156
|
+
if (changed) {
|
|
177
157
|
report.reportSeparator();
|
|
178
158
|
}
|
|
179
159
|
});
|
|
@@ -181,34 +161,6 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
181
161
|
return fixReport.exitCode();
|
|
182
162
|
}
|
|
183
163
|
}
|
|
184
|
-
if (configuration.projectCwd !== null && typeof configuration.sources.get(`nodeLinker`) === `undefined`) {
|
|
185
|
-
const projectCwd = configuration.projectCwd;
|
|
186
|
-
let content;
|
|
187
|
-
try {
|
|
188
|
-
content = await fslib_1.xfs.readFilePromise(fslib_1.ppath.join(projectCwd, fslib_1.Filename.lockfile), `utf8`);
|
|
189
|
-
}
|
|
190
|
-
catch { }
|
|
191
|
-
// If migrating from a v1 install, we automatically enable the node-modules linker,
|
|
192
|
-
// since that's likely what the author intended to do.
|
|
193
|
-
if (content === null || content === void 0 ? void 0 : content.includes(`yarn lockfile v1`)) {
|
|
194
|
-
const nmReport = await core_1.StreamReport.start({
|
|
195
|
-
configuration,
|
|
196
|
-
json: this.json,
|
|
197
|
-
stdout: this.context.stdout,
|
|
198
|
-
includeFooter: false,
|
|
199
|
-
}, async (report) => {
|
|
200
|
-
report.reportInfo(core_1.MessageName.AUTO_NM_SUCCESS, `Migrating from Yarn 1; automatically enabling the compatibility node-modules linker 👍`);
|
|
201
|
-
report.reportSeparator();
|
|
202
|
-
configuration.use(`<compat>`, { nodeLinker: `node-modules` }, projectCwd, { overwrite: true });
|
|
203
|
-
await core_1.Configuration.updateConfiguration(projectCwd, {
|
|
204
|
-
nodeLinker: `node-modules`,
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
if (nmReport.hasErrors()) {
|
|
208
|
-
return nmReport.exitCode();
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
164
|
if (configuration.projectCwd !== null) {
|
|
213
165
|
const telemetryReport = await core_1.StreamReport.start({
|
|
214
166
|
configuration,
|
|
@@ -216,18 +168,72 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
216
168
|
stdout: this.context.stdout,
|
|
217
169
|
includeFooter: false,
|
|
218
170
|
}, async (report) => {
|
|
219
|
-
|
|
220
|
-
|
|
171
|
+
if (core_1.Configuration.telemetry?.isNew) {
|
|
172
|
+
core_1.Configuration.telemetry.commitTips();
|
|
221
173
|
report.reportInfo(core_1.MessageName.TELEMETRY_NOTICE, `Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry`);
|
|
222
174
|
report.reportInfo(core_1.MessageName.TELEMETRY_NOTICE, `Run ${core_1.formatUtils.pretty(configuration, `yarn config set --home enableTelemetry 0`, core_1.formatUtils.Type.CODE)} to disable`);
|
|
223
175
|
report.reportSeparator();
|
|
224
176
|
}
|
|
177
|
+
else if (core_1.Configuration.telemetry?.shouldShowTips) {
|
|
178
|
+
const data = await core_1.httpUtils.get(`https://repo.yarnpkg.com/tags`, { configuration, jsonResponse: true }).catch(() => null);
|
|
179
|
+
if (data !== null) {
|
|
180
|
+
let newVersion = null;
|
|
181
|
+
if (core_1.YarnVersion !== null) {
|
|
182
|
+
const isRcBinary = semver_1.default.prerelease(core_1.YarnVersion);
|
|
183
|
+
const releaseType = isRcBinary ? `canary` : `stable`;
|
|
184
|
+
const candidate = data.latest[releaseType];
|
|
185
|
+
if (semver_1.default.gt(candidate, core_1.YarnVersion)) {
|
|
186
|
+
newVersion = [releaseType, candidate];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (newVersion) {
|
|
190
|
+
core_1.Configuration.telemetry.commitTips();
|
|
191
|
+
report.reportInfo(core_1.MessageName.VERSION_NOTICE, `${core_1.formatUtils.applyStyle(configuration, `A new ${newVersion[0]} version of Yarn is available:`, core_1.formatUtils.Style.BOLD)} ${core_1.structUtils.prettyReference(configuration, newVersion[1])}!`);
|
|
192
|
+
report.reportInfo(core_1.MessageName.VERSION_NOTICE, `Upgrade now by running ${core_1.formatUtils.pretty(configuration, `yarn set version ${newVersion[1]}`, core_1.formatUtils.Type.CODE)}`);
|
|
193
|
+
report.reportSeparator();
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
const tip = core_1.Configuration.telemetry.selectTip(data.tips);
|
|
197
|
+
if (tip) {
|
|
198
|
+
report.reportInfo(core_1.MessageName.TIPS_NOTICE, core_1.formatUtils.pretty(configuration, tip.message, core_1.formatUtils.Type.MARKDOWN_INLINE));
|
|
199
|
+
if (tip.url)
|
|
200
|
+
report.reportInfo(core_1.MessageName.TIPS_NOTICE, `Learn more at ${tip.url}`);
|
|
201
|
+
report.reportSeparator();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
225
206
|
});
|
|
226
207
|
if (telemetryReport.hasErrors()) {
|
|
227
208
|
return telemetryReport.exitCode();
|
|
228
209
|
}
|
|
229
210
|
}
|
|
230
211
|
const { project, workspace } = await core_1.Project.find(configuration, this.context.cwd);
|
|
212
|
+
const lockfileLastVersion = project.lockfileLastVersion;
|
|
213
|
+
if (lockfileLastVersion !== null) {
|
|
214
|
+
const compatReport = await core_1.StreamReport.start({
|
|
215
|
+
configuration,
|
|
216
|
+
json: this.json,
|
|
217
|
+
stdout: this.context.stdout,
|
|
218
|
+
includeFooter: false,
|
|
219
|
+
}, async (report) => {
|
|
220
|
+
const newSettings = {};
|
|
221
|
+
for (const rule of LOCKFILE_MIGRATION_RULES) {
|
|
222
|
+
if (rule.selector(lockfileLastVersion) && typeof configuration.sources.get(rule.name) === `undefined`) {
|
|
223
|
+
configuration.use(`<compat>`, { [rule.name]: rule.value }, project.cwd, { overwrite: true });
|
|
224
|
+
newSettings[rule.name] = rule.value;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (Object.keys(newSettings).length > 0) {
|
|
228
|
+
await core_1.Configuration.updateConfiguration(project.cwd, newSettings);
|
|
229
|
+
report.reportInfo(core_1.MessageName.MIGRATION_SUCCESS, `Migrated your project to the latest Yarn version 🚀`);
|
|
230
|
+
report.reportSeparator();
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
if (compatReport.hasErrors()) {
|
|
234
|
+
return compatReport.exitCode();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
231
237
|
const cache = await core_1.Cache.find(configuration, { immutable: immutableCache, check: this.checkCache });
|
|
232
238
|
if (!workspace)
|
|
233
239
|
throw new cli_1.WorkspaceRequiredError(project.cwd, this.context.cwd);
|
|
@@ -235,9 +241,9 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
235
241
|
restoreResolutions: false,
|
|
236
242
|
});
|
|
237
243
|
const enableHardenedMode = configuration.get(`enableHardenedMode`);
|
|
238
|
-
if (
|
|
244
|
+
if (this.refreshLockfile ?? enableHardenedMode)
|
|
239
245
|
project.lockfileNeedsRefresh = true;
|
|
240
|
-
const checkResolutions =
|
|
246
|
+
const checkResolutions = this.checkResolutions ?? enableHardenedMode;
|
|
241
247
|
// Important: Because other commands also need to run installs, if you
|
|
242
248
|
// get in a situation where you need to change this file in order to
|
|
243
249
|
// customize the install it's very likely you're doing something wrong.
|
|
@@ -245,18 +251,17 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
245
251
|
// install logic should be implemented elsewhere (probably in either of
|
|
246
252
|
// the Configuration and Install classes). Feel free to open an issue
|
|
247
253
|
// in order to ask for design feedback before writing features.
|
|
248
|
-
|
|
249
|
-
configuration,
|
|
254
|
+
return await project.installWithNewReport({
|
|
250
255
|
json: this.json,
|
|
251
256
|
stdout: this.context.stdout,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
257
|
+
}, {
|
|
258
|
+
cache,
|
|
259
|
+
immutable,
|
|
260
|
+
checkResolutions,
|
|
261
|
+
mode: this.mode,
|
|
255
262
|
});
|
|
256
|
-
return report.exitCode();
|
|
257
263
|
}
|
|
258
264
|
}
|
|
259
|
-
exports.default = YarnCommand;
|
|
260
265
|
YarnCommand.paths = [
|
|
261
266
|
[`install`],
|
|
262
267
|
clipanion_1.Command.Default,
|
|
@@ -288,7 +293,7 @@ YarnCommand.usage = clipanion_1.Command.Usage({
|
|
|
288
293
|
|
|
289
294
|
If the \`--mode=<mode>\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:
|
|
290
295
|
|
|
291
|
-
- \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the
|
|
296
|
+
- \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.
|
|
292
297
|
|
|
293
298
|
- \`update-lockfile\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.
|
|
294
299
|
`,
|
|
@@ -303,14 +308,12 @@ YarnCommand.usage = clipanion_1.Command.Usage({
|
|
|
303
308
|
`$0 install --immutable --immutable-cache --check-cache`,
|
|
304
309
|
]],
|
|
305
310
|
});
|
|
306
|
-
|
|
307
|
-
const MERGE_CONFLICT_END = `>>>>>>>`;
|
|
308
|
-
const MERGE_CONFLICT_SEP = `=======`;
|
|
311
|
+
exports.default = YarnCommand;
|
|
309
312
|
const MERGE_CONFLICT_START = `<<<<<<<`;
|
|
310
313
|
async function autofixMergeConflicts(configuration, immutable) {
|
|
311
314
|
if (!configuration.projectCwd)
|
|
312
315
|
return false;
|
|
313
|
-
const lockfilePath = fslib_1.ppath.join(configuration.projectCwd,
|
|
316
|
+
const lockfilePath = fslib_1.ppath.join(configuration.projectCwd, fslib_1.Filename.lockfile);
|
|
314
317
|
if (!await fslib_1.xfs.existsPromise(lockfilePath))
|
|
315
318
|
return false;
|
|
316
319
|
const file = await fslib_1.xfs.readFilePromise(lockfilePath, `utf8`);
|
|
@@ -318,22 +321,74 @@ async function autofixMergeConflicts(configuration, immutable) {
|
|
|
318
321
|
return false;
|
|
319
322
|
if (immutable)
|
|
320
323
|
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_IMMUTABLE, `Cannot autofix a lockfile when running an immutable install`);
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
let commits = await core_1.execUtils.execvp(`git`, [`rev-parse`, `MERGE_HEAD`, `HEAD`], {
|
|
325
|
+
cwd: configuration.projectCwd,
|
|
326
|
+
});
|
|
327
|
+
if (commits.code !== 0) {
|
|
328
|
+
commits = await core_1.execUtils.execvp(`git`, [`rev-parse`, `REBASE_HEAD`, `HEAD`], {
|
|
329
|
+
cwd: configuration.projectCwd,
|
|
330
|
+
});
|
|
327
331
|
}
|
|
328
|
-
|
|
329
|
-
|
|
332
|
+
if (commits.code !== 0) {
|
|
333
|
+
commits = await core_1.execUtils.execvp(`git`, [`rev-parse`, `CHERRY_PICK_HEAD`, `HEAD`], {
|
|
334
|
+
cwd: configuration.projectCwd,
|
|
335
|
+
});
|
|
330
336
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
337
|
+
if (commits.code !== 0)
|
|
338
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_GIT_ERROR, `Git returned an error when trying to find the commits pertaining to the conflict`);
|
|
339
|
+
let variants = await Promise.all(commits.stdout.trim().split(/\n/).map(async (hash) => {
|
|
340
|
+
const content = await core_1.execUtils.execvp(`git`, [`show`, `${hash}:./${fslib_1.Filename.lockfile}`], {
|
|
341
|
+
cwd: configuration.projectCwd,
|
|
342
|
+
});
|
|
343
|
+
if (content.code !== 0)
|
|
344
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_GIT_ERROR, `Git returned an error when trying to access the lockfile content in ${hash}`);
|
|
345
|
+
try {
|
|
346
|
+
return (0, parsers_1.parseSyml)(content.stdout);
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_FAILED_TO_PARSE, `A variant of the conflicting lockfile failed to parse`);
|
|
350
|
+
}
|
|
351
|
+
}));
|
|
335
352
|
// Old-style lockfiles should be filtered out (for example when switching
|
|
336
|
-
// from a Yarn 2 branch to a Yarn 1 branch).
|
|
353
|
+
// from a Yarn 2 branch to a Yarn 1 branch).
|
|
354
|
+
variants = variants.filter(variant => {
|
|
355
|
+
return !!variant.__metadata;
|
|
356
|
+
});
|
|
357
|
+
for (const variant of variants) {
|
|
358
|
+
// Pre-lockfile v7, the entries weren't normalized (ie we had "foo@x.y.z"
|
|
359
|
+
// in the lockfile rather than "foo@npm:x.y.z")
|
|
360
|
+
if (variant.__metadata.version < 7) {
|
|
361
|
+
for (const key of Object.keys(variant)) {
|
|
362
|
+
if (key === `__metadata`)
|
|
363
|
+
continue;
|
|
364
|
+
const descriptor = core_1.structUtils.parseDescriptor(key, true);
|
|
365
|
+
const normalizedDescriptor = configuration.normalizeDependency(descriptor);
|
|
366
|
+
const newKey = core_1.structUtils.stringifyDescriptor(normalizedDescriptor);
|
|
367
|
+
if (newKey !== key) {
|
|
368
|
+
variant[newKey] = variant[key];
|
|
369
|
+
delete variant[key];
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// We encode the cacheKeys inside the checksums so that the reconciliation
|
|
374
|
+
// can merge the data together
|
|
375
|
+
for (const key of Object.keys(variant)) {
|
|
376
|
+
if (key === `__metadata`)
|
|
377
|
+
continue;
|
|
378
|
+
const checksum = variant[key].checksum;
|
|
379
|
+
if (typeof checksum === `string` && checksum.includes(`/`))
|
|
380
|
+
continue;
|
|
381
|
+
variant[key].checksum = `${variant.__metadata.cacheKey}/${checksum}`;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
const merged = Object.assign({}, ...variants);
|
|
385
|
+
// We must keep the lockfile version as small as necessary to force Yarn to
|
|
386
|
+
// refresh the merged-in lockfile metadata that may be missing.
|
|
387
|
+
merged.__metadata.version = `${Math.min(...variants.map(variant => {
|
|
388
|
+
return parseInt(variant.__metadata.version ?? 0);
|
|
389
|
+
}))}`;
|
|
390
|
+
// It shouldn't matter, since the cacheKey have been embed within the checksums
|
|
391
|
+
merged.__metadata.cacheKey = `merged`;
|
|
337
392
|
// parse as valid YAML except that the objects become strings. We can use
|
|
338
393
|
// that to detect them. Damn, it's really ugly though.
|
|
339
394
|
for (const [key, value] of Object.entries(merged))
|
|
@@ -344,52 +399,37 @@ async function autofixMergeConflicts(configuration, immutable) {
|
|
|
344
399
|
});
|
|
345
400
|
return true;
|
|
346
401
|
}
|
|
347
|
-
function
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
variants[1].push(conflictLine);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
variants[0].push(line);
|
|
388
|
-
variants[1].push(line);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
return [
|
|
392
|
-
variants[0].join(`\n`),
|
|
393
|
-
variants[1].join(`\n`),
|
|
394
|
-
];
|
|
402
|
+
async function autofixLegacyPlugins(configuration, immutable) {
|
|
403
|
+
if (!configuration.projectCwd)
|
|
404
|
+
return false;
|
|
405
|
+
const legacyPlugins = [];
|
|
406
|
+
const yarnPluginDir = fslib_1.ppath.join(configuration.projectCwd, `.yarn/plugins/@yarnpkg`);
|
|
407
|
+
const changed = await core_1.Configuration.updateConfiguration(configuration.projectCwd, {
|
|
408
|
+
plugins: plugins => {
|
|
409
|
+
if (!Array.isArray(plugins))
|
|
410
|
+
return plugins;
|
|
411
|
+
const filteredPlugins = plugins.filter((plugin) => {
|
|
412
|
+
if (!plugin.path)
|
|
413
|
+
return true;
|
|
414
|
+
const resolvedPath = fslib_1.ppath.resolve(configuration.projectCwd, plugin.path);
|
|
415
|
+
const isLegacy = core_1.LEGACY_PLUGINS.has(plugin.spec) && fslib_1.ppath.contains(yarnPluginDir, resolvedPath);
|
|
416
|
+
if (isLegacy)
|
|
417
|
+
legacyPlugins.push(resolvedPath);
|
|
418
|
+
return !isLegacy;
|
|
419
|
+
});
|
|
420
|
+
if (filteredPlugins.length === 0)
|
|
421
|
+
return core_1.Configuration.deleteProperty;
|
|
422
|
+
if (filteredPlugins.length === plugins.length)
|
|
423
|
+
return plugins;
|
|
424
|
+
return filteredPlugins;
|
|
425
|
+
},
|
|
426
|
+
}, {
|
|
427
|
+
immutable,
|
|
428
|
+
});
|
|
429
|
+
if (!changed)
|
|
430
|
+
return false;
|
|
431
|
+
await Promise.all(legacyPlugins.map(async (pluginPath) => {
|
|
432
|
+
await fslib_1.xfs.removePromise(pluginPath);
|
|
433
|
+
}));
|
|
434
|
+
return true;
|
|
395
435
|
}
|
package/lib/commands/link.d.ts
CHANGED