Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: add --run-from flag #57592

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -2294,6 +2294,25 @@ The following environment variables are set when running a script with `--run`:
* `NODE_RUN_PACKAGE_JSON_PATH`: The path to the `package.json` that is being
processed.

### `--run-from=<path>`

<!--
added: REPLACEME
-->

> Stability 1.0 - Early development

Run a `package.json` script from a specified path to a `package.json` file or
path to the containing folder of a `package.json` file.

The script is ran from the directory of the `package.json` file.

```bash
node --run-from=/app/package.json --run test
# Or
node --run-from=/app/ --run test
```

### `--secure-heap-min=n`

<!-- YAML
Expand Down
3 changes: 3 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,9 @@ PerProcessOptionsParser::PerProcessOptionsParser(
AddOption("--run",
"Run a script specified in package.json",
&PerProcessOptions::run);
AddOption("--run-from",
"Run a package.json script from a specific directory",
&PerProcessOptions::run_from);
AddOption(
"--disable-wasm-trap-handler",
"Disable trap-handler-based WebAssembly bound checks. V8 will insert "
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ class PerProcessOptions : public Options {
bool print_version = false;
std::string experimental_sea_config;
std::string run;
std::string run_from;

#ifdef NODE_HAVE_I18N_SUPPORT
std::string icu_data_dir;
Expand Down
21 changes: 20 additions & 1 deletion src/node_task_runner.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "node_task_runner.h"
#include "util-inl.h"

#include <filesystem>
#include <regex> // NOLINT(build/c++11)

namespace node::task_runner {
Expand Down Expand Up @@ -252,7 +253,25 @@ FindPackageJson(const std::filesystem::path& cwd) {
void RunTask(const std::shared_ptr<InitializationResultImpl>& result,
std::string_view command_id,
const std::vector<std::string_view>& positional_args) {
auto cwd = std::filesystem::current_path();
auto run_from = per_process::cli_options->run_from;
std::filesystem::path cwd;

if (run_from.empty()) {
cwd = std::filesystem::current_path();
} else {
cwd = std::filesystem::absolute(std::filesystem::path(run_from));

if (is_regular_file(cwd)) {
// Given a package.json
cwd = cwd.parent_path();
} else if (!is_directory(cwd)) {
// Given a directory that should have a package.json
fprintf(stderr, "Error: %s is not a directory\n", cwd.c_str());
result->exit_code_ = ExitCode::kGenericUserError;
return;
}
}

auto package_json = FindPackageJson(cwd);

if (!package_json.has_value()) {
Expand Down
45 changes: 45 additions & 0 deletions test/parallel/test-node-run.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,49 @@ describe('node --run [command]', () => {
assert.strictEqual(child.stdout, '');
assert.strictEqual(child.code, 1);
});

it('runs script in a custom working directory using --run-from', async () => {
const workingDir = fixtures.path('run-script');

const child = await common.spawnPromisified(
process.execPath,
[ '--run-from', workingDir, '--run', `pwd${envSuffix}` ],

{ env: fixtures.path('run-script/sub-directory') }
);

assert.strictEqual(child.stdout.trim(), workingDir);
assert.strictEqual(child.stderr, '');
assert.strictEqual(child.code, 0);
});

it('runs script in a custom working directory using --run-from is given a package.json', async () => {
const packageJson = fixtures.path('run-script/package.json');
const workingDir = fixtures.path('run-script');

const child = await common.spawnPromisified(
process.execPath,
[ '--run-from', packageJson, '--run', `pwd${envSuffix}` ],

{ env: fixtures.path('run-script/sub-directory') }
);

assert.strictEqual(child.stdout.trim(), workingDir);
assert.strictEqual(child.stderr, '');
assert.strictEqual(child.code, 0);
});

it('--run-from should be no-op when used without --run', async () => {
const packageJson = fixtures.path('run-script/package.json');

const child = await common.spawnPromisified(
process.execPath,
[ '--run-from', packageJson, '--print', 'process.cwd()' ],
{ cwd: process.cwd() }
);

assert.strictEqual(child.stdout.trim(), process.cwd());
assert.strictEqual(child.stderr, '');
assert.strictEqual(child.code, 0);
});
});
Loading