Skip to content

Commit

Permalink
feat(run): Add engines check before executing scripts. (#7021)
Browse files Browse the repository at this point in the history
Closes #7013

**Summary**

A more elaborate description is available in #7013. In short, ensuring scripts are ran in the expected environment can deter hard to diagnose bugs.

**Test plan**

Given a `node` engine requirement that doesn’t match the current environment:

```
$ cat package.json | grep -i1 '"node"'
  "engines": {
    "node": "^10.13.0"
  },

$ nvm use 8
Now using node v8.12.0 (npm v6.4.1)
```

A script invocation will fail as follows:

```
$ node ~/Code/JavaScript/yarn/lib/cli/index.js run relay
yarn run v1.15.0-0
error @artsy/reaction@12.1.10: The engine "node" is incompatible with this module. Expected version "^10.13.0". Got "8.12.0"
error Commands cannot run with an incompatible environment.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```

If need be, this can be overridden with the `--ignore-engines` flag:

```
$ node ~/Code/JavaScript/yarn/lib/cli/index.js run --ignore-engines relay
yarn run v1.15.0-0
$ relay-compiler --src ./src --schema data/schema.graphql --language typescript --artifactDirectory ./src/__generated__ --exclude '**/node_modules/**,**/__mocks__/**,**/__generated__/**'
✨  Done in 2.22s.
```

Or, of course, making the environment match the requirements:

```
$ nvm use 10.13
Now using node v10.13.0 (npm v6.4.1)

$ node ~/Code/JavaScript/yarn/lib/cli/index.js run relay
yarn run v1.15.0-0
$ relay-compiler --src ./src --schema data/schema.graphql --language typescript --artifactDirectory ./src/__generated__ --exclude '**/node_modules/**,**/__mocks__/**,**/__generated__/**'
✨  Done in 1.91s.
```
  • Loading branch information
alloy authored and cpojer committed Mar 19, 2019
1 parent bba4dce commit 697a254
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -90,6 +90,10 @@ The 1.15.1 doesn't exist due to a release hiccup.

[#7093](https://github.com/yarnpkg/yarn/pull/7093) - [**David Refoua**](https://github.com/DRSDavidSoft)

- Run the engines check before executing `run` scripts.

[#7013](https://github.com/yarnpkg/yarn/issues/7013) - [**Eloy Durán**](https://github.com/alloy)

## 1.14.0

- Improves PnP compatibility with Node 6
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/install.js
Expand Up @@ -745,7 +745,7 @@ export class Install {

async checkCompatibility(): Promise<void> {
const {manifest} = await this.fetchRequestFromCwd();
await compatibility.checkOne({_reference: {}, ...manifest}, this.config, this.flags.ignoreEngines);
await compatibility.checkOne(manifest, this.config, this.flags.ignoreEngines);
}

async persistChanges(): Promise<void> {
Expand Down
8 changes: 8 additions & 0 deletions src/cli/commands/run.js
Expand Up @@ -5,6 +5,7 @@ import type Config from '../../config.js';
import {execCommand, makeEnv} from '../../util/execute-lifecycle-script.js';
import {dynamicRequire} from '../../util/dynamic-require.js';
import {MessageError} from '../../errors.js';
import {checkOne as checkCompatibility} from '../../package-compatibility.js';
import * as fs from '../../util/fs.js';
import * as constants from '../../constants.js';

Expand Down Expand Up @@ -117,6 +118,13 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg
}

if (cmds.length) {
const ignoreEngines = !!(flags.ignoreEngines || config.getOption('ignore-engines'));
try {
await checkCompatibility(pkg, config, ignoreEngines);
} catch (err) {
throw err instanceof MessageError ? new MessageError(reporter.lang('cannotRunWithIncompatibleEnv')) : err;
}

// Disable wrapper in executed commands
process.env.YARN_WRAP_OUTPUT = 'false';
for (const [stage, cmd] of cmds) {
Expand Down
4 changes: 1 addition & 3 deletions src/package-compatibility.js
Expand Up @@ -8,7 +8,6 @@ import {entries} from './util/misc.js';
import {version as yarnVersion} from './util/yarn-version.js';
import {satisfiesWithPrereleases} from './util/semver.js';

const invariant = require('invariant');
const semver = require('semver');

const VERSIONS = Object.assign({}, process.versions, {
Expand Down Expand Up @@ -111,9 +110,8 @@ export function checkOne(info: Manifest, config: Config, ignoreEngines: boolean)

const pushError = msg => {
const ref = info._reference;
invariant(ref, 'expected package reference');

if (ref.optional) {
if (ref && ref.optional) {
ref.ignore = true;
ref.incompatible = true;

Expand Down
3 changes: 2 additions & 1 deletion src/reporters/lang/en.js
Expand Up @@ -229,11 +229,12 @@ const messages = {
nodeGypAutoInstallFailed:
'Failed to auto-install node-gyp. Please run "yarn global add node-gyp" manually. Error: $0',

foundIncompatible: 'Found incompatible module',
foundIncompatible: 'Found incompatible module.',
incompatibleEngine: 'The engine $0 is incompatible with this module. Expected version $1. Got $2',
incompatibleCPU: 'The CPU architecture $0 is incompatible with this module.',
incompatibleOS: 'The platform $0 is incompatible with this module.',
invalidEngine: 'The engine $0 appears to be invalid.',
cannotRunWithIncompatibleEnv: 'Commands cannot run with an incompatible environment.',

optionalCompatibilityExcluded:
'$0 is an optional dependency and failed compatibility check. Excluding it from installation.',
Expand Down

0 comments on commit 697a254

Please sign in to comment.