Skip to content

Commit

Permalink
feat(builtin): yarn install use --frozen-lockfile as default
Browse files Browse the repository at this point in the history
To be more hermetic with the install of the dependencies use the frozen lockfile flag to install the exact version from the `yarn.lock` file.

To update a dependency use the vendored yarn binary with `bazel run @nodejs//:yarn upgrade <dep-name>`.

Fixes #941
  • Loading branch information
Lukas Holzer committed Dec 6, 2020
1 parent c344401 commit e61ede6
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 4 deletions.
5 changes: 4 additions & 1 deletion internal/bazel_integration_test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ package(default_visibility = ["//visibility:public"])
nodejs_binary(
name = "test_runner",
configuration_env_vars = ["BAZEL_INTEGRATION_TEST_DEBUG"],
data = ["@npm//tmp"],
data = [
"@npm//@yarnpkg/lockfile",
"@npm//tmp",
],
entry_point = ":test_runner.js",
templated_args = ["--node_options=--max-old-space-size=1024"],
)
Expand Down
32 changes: 31 additions & 1 deletion internal/bazel_integration_test/test_runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const spawnSync = require('child_process').spawnSync;
const fs = require('fs');
const path = require('path');
const tmp = require('tmp');
const lockfile = require('@yarnpkg/lockfile');

const DEBUG = !!process.env['BAZEL_INTEGRATION_TEST_DEBUG'];
const VERBOSE_LOGS = !!process.env['VERBOSE_LOGS'];
Expand Down Expand Up @@ -230,10 +231,13 @@ if (config.bazelrcAppend) {
logFileContents('WORKSPACE file with replacements:', workspaceContents);
}

// Handle package.json replacements
// Handle package.json and yarn.lock replacements
const packageJsonFile = path.posix.join(workspaceRoot, 'package.json');
const yarnLockFile = path.posix.join(workspaceRoot, 'yarn.lock');

if (isFile(packageJsonFile)) {
let packageJsonContents = fs.readFileSync(packageJsonFile, {encoding: 'utf-8'});
let yarnLockContents = isFile(yarnLockFile) ? fs.readFileSync(yarnLockFile, {encoding: 'utf-8'}) : null;

const npmPackageKeys = Object.keys(config.npmPackages);
if (npmPackageKeys.length) {
Expand All @@ -242,6 +246,29 @@ if (isFile(packageJsonFile)) {
const packagePath = copyNpmPackage(config.npmPackages[packageJsonKey]).replace(/\\/g, '/');
const regex = new RegExp(`\"${packageJsonKey}\"\\s*\:\\s*\"[^"]+`)
const replacement = `"${packageJsonKey}": "file:${packagePath}`;

if (yarnLockContents) {
const {object: json} = lockfile.parse(yarnLockContents)
const lockFileKey = Object.keys(json).find(key => key.startsWith(packageJsonKey))
const pkg = json[lockFileKey];

if (pkg.resolved) {
delete pkg.resolved
}
if (pkg.integrity) {
delete pkg.integrity
}
pkg.version = require(path.posix.join(packagePath, 'package.json')).version;

// delete old object and replace with the new key
delete json[lockFileKey];

const rel = path.posix.join(path.relative(workspaceRoot, '/'), '..', packagePath);
json[`${packageJsonKey}@file:${rel}`] = pkg

yarnLockContents = lockfile.stringify(json)
}

packageJsonContents = packageJsonContents.replace(regex, replacement);
if (!packageJsonContents.includes(packagePath)) {
console.error(`bazel_integration_test: package.json replacement for npm package ${
Expand All @@ -250,6 +277,9 @@ if (isFile(packageJsonFile)) {
}
}
fs.writeFileSync(packageJsonFile, packageJsonContents);
if (yarnLockContents) {
fs.writeFileSync(yarnLockFile, yarnLockContents);
}
}

const packageJsonReplacementKeys = Object.keys(config.packageJsonRepacements);
Expand Down
25 changes: 23 additions & 2 deletions internal/npm_install/npm_install.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ def _add_data_dependencies(repository_ctx):
for f in repository_ctx.attr.data:
to = []
if f.package:
to += [f.package]
to += [f.name]
to.append(f.package)
to.append(f.name)

# Make copies of the data files instead of symlinking
# as yarn under linux will have trouble using symlinked
Expand Down Expand Up @@ -328,6 +328,13 @@ def _yarn_install_impl(repository_ctx):
yarn = get_yarn_label(repository_ctx)

yarn_args = []

# Set frozen lockfile as default install to install the exact version from the yarn.lock
# file. To perform an yarn install use the vendord yarn binary with:
# `bazel run @nodejs//:yarn install` or `bazel run @nodejs//:yarn install -- -D <dep-name>`
if repository_ctx.attr.frozen_lockfile:
yarn_args.append("--frozen-lockfile")

if not repository_ctx.attr.use_global_yarn_cache:
yarn_args.extend(["--cache-folder", str(repository_ctx.path("_yarn_cache"))])
else:
Expand Down Expand Up @@ -429,6 +436,20 @@ yarn_install = repository_rule(
See yarn CLI docs https://yarnpkg.com/en/docs/cli/install for complete list of supported arguments.""",
default = [],
),
"frozen_lockfile": attr.bool(
default = True,
doc = """Use the `--frozen-lockfile` flag for yarn.
Don’t generate a `yarn.lock` lockfile and fail if an update is needed.
This flag enables an exact install of the version that is specified in the `yarn.lock`
file. This helps to have reproduceable builds across builds.
To update a dependency or install a new one run the `yarn install` command with the
vendored yarn binary. `bazel run @nodejs//:yarn install`. You can pass the options like
`bazel run @nodejs//:yarn install -- -D <dep-name>`.
""",
),
"use_global_yarn_cache": attr.bool(
default = True,
doc = """Use the global yarn cache on the system.
Expand Down

0 comments on commit e61ede6

Please sign in to comment.