Skip to content

Commit

Permalink
Add --immutable arg
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisdothtml committed Jan 10, 2025
1 parent cf649c7 commit f7d526f
Show file tree
Hide file tree
Showing 19 changed files with 296 additions and 47 deletions.
2 changes: 1 addition & 1 deletion bin/cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ async function runMaster() {
await install({
root,
cwd: `${root}/${data[0].dir}`,
frozenLockfile: true,
immutable: true,
conservative: true,
});

Expand Down
8 changes: 7 additions & 1 deletion commands/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,13 @@ const add /*: Add */ = async ({root, cwd, args, dev = false}) => {
dirs: projects.map(dir => `${root}/${dir}`),
target: resolve(root, cwd),
});
await generateBazelBuildRules({root, deps, projects, dependencySyncRule});
await generateBazelBuildRules({
root,
deps,
projects,
dependencySyncRule,
immutable: false,
});
}
};

Expand Down
2 changes: 1 addition & 1 deletion commands/ci.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type CiArgs = {
export type Ci = (CiArgs) => Promise<void>
*/
const ci /*: Ci */ = async ({root, cwd}) => {
await install({root, cwd, frozenLockfile: true, conservative: true});
await install({root, cwd, immutable: true, conservative: true});
};

module.exports = {ci};
3 changes: 2 additions & 1 deletion commands/focus.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,13 @@ const focus /*: Focus */ = async ({
await validateVersionPolicy({dirs: deps.map(dep => dep.dir), versionPolicy});

if (workspace === 'sandbox') {
await generateBazelignore({root});
await generateBazelignore({root, immutable: false});
await generateBazelBuildRules({
root,
deps,
projects,
dependencySyncRule,
immutable: false,
});
}

Expand Down
50 changes: 38 additions & 12 deletions commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const {node, yarn} = require('../utils/binary-paths.js');
export type InstallArgs = {
root: string,
cwd: string,
frozenLockfile?: boolean,
immutable?: boolean,
conservative?: boolean,
skipPreinstall?: boolean,
skipPostinstall?: boolean,
Expand All @@ -33,7 +33,7 @@ export type Install = (InstallArgs) => Promise<void>
const install /*: Install */ = async ({
root,
cwd,
frozenLockfile = false,
immutable = false,
conservative = true,
skipPreinstall = false,
skipPostinstall = false,
Expand Down Expand Up @@ -71,14 +71,27 @@ const install /*: Install */ = async ({
validateDeps({deps});
await validateVersionPolicy({dirs: deps.map(dep => dep.dir), versionPolicy});

if (workspace === 'sandbox' && frozenLockfile === false) {
await generateBazelignore({root});
await generateBazelBuildRules({
root,
deps: all,
projects,
dependencySyncRule,
});
if (workspace === 'sandbox') {
const changedGeneratedFiles = [
...(await generateBazelignore({
root,
immutable,
})),
...(await generateBazelBuildRules({
root,
deps: all,
projects,
dependencySyncRule,
immutable,
})),
];

if (immutable && changedGeneratedFiles.length > 0) {
throw new ImmutableInstallError(
`Generated files would have changed, but 'immutable' arg was passed`,
changedGeneratedFiles
);
}
}

if (hooks.bool_shouldinstall) {
Expand All @@ -97,7 +110,7 @@ const install /*: Install */ = async ({
const env = process.env;
const path = dirname(node) + ':' + String(process.env.PATH);
const spawnArgs = [yarn, 'install'];
if (frozenLockfile) {
if (immutable) {
spawnArgs.push('--immutable');
}

Expand Down Expand Up @@ -131,6 +144,19 @@ const install /*: Install */ = async ({
}
};

/**
* An error that's thrown when the `immutable` flag is
* `true` and generated files would have changed.
*/
class ImmutableInstallError extends Error {
/*:: changedFiles: Array<string>; */

constructor(message /*: string */, changedFiles /*: Array<string> */) {
super(message);
this.changedFiles = changedFiles;
}
}

const validateRegistration = ({root, cwd, projects}) => {
if (!projects.find(dir => resolve(`${root}/${dir}`) === cwd)) {
const registrationError = `Your cwd ${cwd} is not listed in manifest.json or package.json. If you are at the wrong directory, cd into your desired directory or use the --cwd flag. If you are in the desired directory, make sure it is listed in the projects field in manifest.json or workspaces field in package.json`;
Expand Down Expand Up @@ -173,4 +199,4 @@ const validateVersionPolicy = async ({dirs, versionPolicy}) => {
if (!result.valid) throw new Error(getErrorMessage(result, false));
};

module.exports = {install};
module.exports = {install, ImmutableInstallError};
8 changes: 7 additions & 1 deletion commands/remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ const remove /*: Remove */ = async ({root, cwd, args}) => {
dirs: projects.map(dir => `${root}/${dir}`),
target: resolve(root, cwd),
});
await generateBazelBuildRules({root, deps, projects, dependencySyncRule});
await generateBazelBuildRules({
root,
deps,
projects,
dependencySyncRule,
immutable: false,
});
}
};

Expand Down
74 changes: 60 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// @flow
const {getRootDir} = require('./utils/get-root-dir.js');
const {parse, normalize} = require('./utils/parse-argv.js');
const {cli} = require('./utils/cli.js');
const {cli, CliError} = require('./utils/cli.js');
const {version} = require('./commands/version.js');
const {init} = require('./commands/init.js');
const {scaffold} = require('./commands/scaffold.js');
const {install} = require('./commands/install.js');
const {install, ImmutableInstallError} = require('./commands/install.js');
const {ci} = require('./commands/ci.js');
const {focus} = require('./commands/focus.js');
const {add} = require('./commands/add.js');
Expand Down Expand Up @@ -86,26 +86,46 @@ const runCLI /*: RunCLI */ = async argv => {
--skipPreinstall Skip the preinstall hook
--skipPostinstall Skip the postinstall hook
--mode If set to skip-build, skips build scripts. If set to update-lockfile, skips link step
--immutable Fail if generated files need to be modified
--verbose`,
async ({cwd, skipPreinstall, skipPostinstall, mode, verbose}) =>
install({
root: await rootOf(args),
cwd,
skipPreinstall: Boolean(skipPreinstall),
skipPostinstall: Boolean(skipPostinstall),
mode,
verbose: Boolean(verbose),
}),
async ({
cwd,
skipPreinstall,
skipPostinstall,
mode,
immutable,
verbose,
}) => {
try {
await install({
root: await rootOf(args),
cwd,
skipPreinstall: Boolean(skipPreinstall),
skipPostinstall: Boolean(skipPostinstall),
mode,
immutable: Boolean(immutable),
verbose: Boolean(verbose),
});
} catch (error) {
handleInstallError(error);
}
},
],
ci: [
`Install all dependencies for all project without modifying source files
`Install all dependencies for all projects, failing if any generated files need to be modified
--cwd [cwd] Project directory to use`,
async ({cwd}) => ci({root: await rootOf(args), cwd}),
async ({cwd}) => {
try {
await ci({root: await rootOf(args), cwd});
} catch (error) {
handleInstallError(error);
}
},
],
focus: [
`Install all dependencies for one or more projects without installing the rest
--cwd [cwd] Project directory to use
--all Install all dependencies, like regular yarn install
--production Install only production dependencies, not devDependencies
Expand Down Expand Up @@ -366,6 +386,32 @@ const runCLI /*: RunCLI */ = async argv => {
);
};

const ansiRed = '\x1b[91m';
const ansiReset = '\x1b[0m';
/**
* Checks whether the provided error is a `ImmutableInstallError`,
* and if it is, throws a `CliError` with a formatted message.
*/
function handleInstallError(error /*: Error | ImmutableInstallError */) {
if (error instanceof ImmutableInstallError) {
const shouldUseColors = process.stdout.isTTY || process.env.FORCE_COLOR;
const errorMessage =
(shouldUseColors ? ansiRed : '') +
'ERROR: ' +
error.message +
'\n' +
error.changedFiles
.sort((a, b) => a.localeCompare(b))
.map(l => ' - ' + l)
.join('\n') +
(shouldUseColors ? ansiReset : '');

throw new CliError(errorMessage, 1);
} else {
throw error;
}
}

async function rootOf(args) {
return getRootDir({dir: args.cwd});
}
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/immutable-install/a/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "a",
"version": "0.0.0"
}
9 changes: 9 additions & 0 deletions tests/fixtures/immutable-install/b/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package(default_visibility = ["//visibility:public"])
load("@jazelle//:build-rules.bzl", "web_library")

web_library(
name = "b",
deps = [
],
dist = ["dist"],
)
7 changes: 7 additions & 0 deletions tests/fixtures/immutable-install/b/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "b",
"version": "0.0.0",
"dependencies": {
"a": "0.0.0"
}
}
3 changes: 3 additions & 0 deletions tests/fixtures/immutable-install/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"workspace": "sandbox"
}
4 changes: 4 additions & 0 deletions tests/fixtures/immutable-install/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"private": true,
"workspaces": ["a", "b"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("@jazelle//:build-rules.bzl", "web_library")

package(default_visibility = ["//visibility:public"])

web_library(
name = "node_modules",
srcs = glob(["**/*"]),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @flow
module.exports.template = ({name, path, label, dependencies}) => `
#
# name: ${name}
# path: ${path}
# label: ${label}
# dependencies: ${dependencies.join('|')}
#`;
Empty file.
Loading

0 comments on commit f7d526f

Please sign in to comment.