Skip to content

Commit a7d9f86

Browse files
committed
src: add --run-from flag
Closes nodejs#57489 Co-authored-by: Mert Can Altin <[email protected]> Co-authored-by: Yagiz Nizipli <[email protected]> Signed-off-by: flakey5 <[email protected]>
1 parent 4a7d501 commit a7d9f86

File tree

5 files changed

+88
-1
lines changed

5 files changed

+88
-1
lines changed

doc/api/cli.md

+19
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,25 @@ The following environment variables are set when running a script with `--run`:
22942294
* `NODE_RUN_PACKAGE_JSON_PATH`: The path to the `package.json` that is being
22952295
processed.
22962296

2297+
### `--run-from=<path>`
2298+
2299+
<!--
2300+
added: REPLACEME
2301+
-->
2302+
2303+
> Stability 1.0 - Early development
2304+
2305+
Run a `package.json` script from a specified path to a `package.json` file or
2306+
path to the containing folder of a `package.json` file.
2307+
2308+
The script is ran from the directory of the `package.json` file.
2309+
2310+
```bash
2311+
node --run-from=/app/package.json --run test
2312+
# Or
2313+
node --run-from=/app/ --run test
2314+
```
2315+
22972316
### `--secure-heap-min=n`
22982317

22992318
<!-- YAML

src/node_options.cc

+3
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,9 @@ PerProcessOptionsParser::PerProcessOptionsParser(
12161216
AddOption("--run",
12171217
"Run a script specified in package.json",
12181218
&PerProcessOptions::run);
1219+
AddOption("--run-from",
1220+
"Run a package.json script from a specific directory",
1221+
&PerProcessOptions::run_from);
12191222
AddOption(
12201223
"--disable-wasm-trap-handler",
12211224
"Disable trap-handler-based WebAssembly bound checks. V8 will insert "

src/node_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ class PerProcessOptions : public Options {
327327
bool print_version = false;
328328
std::string experimental_sea_config;
329329
std::string run;
330+
std::string run_from;
330331

331332
#ifdef NODE_HAVE_I18N_SUPPORT
332333
std::string icu_data_dir;

src/node_task_runner.cc

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "node_task_runner.h"
22
#include "util-inl.h"
33

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

67
namespace node::task_runner {
@@ -252,7 +253,25 @@ FindPackageJson(const std::filesystem::path& cwd) {
252253
void RunTask(const std::shared_ptr<InitializationResultImpl>& result,
253254
std::string_view command_id,
254255
const std::vector<std::string_view>& positional_args) {
255-
auto cwd = std::filesystem::current_path();
256+
auto run_from = per_process::cli_options->run_from;
257+
std::filesystem::path cwd;
258+
259+
if (run_from.empty()) {
260+
cwd = std::filesystem::current_path();
261+
} else {
262+
cwd = std::filesystem::path(run_from);
263+
264+
if (is_regular_file(cwd)) {
265+
// Given a package.json
266+
cwd = std::filesystem::absolute(cwd.parent_path());
267+
} else if (!is_directory(cwd)) {
268+
// Given a directory that should have a package.json
269+
fprintf(stderr, "Error: %s is not a directory\n", cwd.c_str());
270+
result->exit_code_ = ExitCode::kGenericUserError;
271+
return;
272+
}
273+
}
274+
256275
auto package_json = FindPackageJson(cwd);
257276

258277
if (!package_json.has_value()) {

test/parallel/test-node-run.js

+45
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,49 @@ describe('node --run [command]', () => {
222222
assert.strictEqual(child.stdout, '');
223223
assert.strictEqual(child.code, 1);
224224
});
225+
226+
it('runs script in a custom working directory using --run-from', async () => {
227+
const workingDir = fixtures.path('run-script');
228+
229+
const child = await common.spawnPromisified(
230+
process.execPath,
231+
[ '--run-from', workingDir, '--run', `pwd${envSuffix}` ],
232+
233+
{ env: fixtures.path('run-script/sub-directory') }
234+
);
235+
236+
assert.strictEqual(child.stdout.trim(), workingDir);
237+
assert.strictEqual(child.stderr, '');
238+
assert.strictEqual(child.code, 0);
239+
});
240+
241+
it('runs script in a custom working directory using --run-from is given a package.json', async () => {
242+
const packageJson = fixtures.path('run-script/package.json');
243+
const workingDir = fixtures.path('run-script');
244+
245+
const child = await common.spawnPromisified(
246+
process.execPath,
247+
[ '--run-from', packageJson, '--run', `pwd${envSuffix}` ],
248+
249+
{ env: fixtures.path('run-script/sub-directory') }
250+
);
251+
252+
assert.strictEqual(child.stdout.trim(), workingDir);
253+
assert.strictEqual(child.stderr, '');
254+
assert.strictEqual(child.code, 0);
255+
})
256+
257+
it('--run-from should be no-op when used without --run', async () => {
258+
const packageJson = fixtures.path('run-script/package.json');
259+
260+
const child = await common.spawnPromisified(
261+
process.execPath,
262+
[ '--run-from', packageJson, '--print', 'process.cwd()' ],
263+
{ cwd: process.cwd() }
264+
);
265+
266+
assert.strictEqual(child.stdout.trim(), process.cwd());
267+
assert.strictEqual(child.stderr, '');
268+
assert.strictEqual(child.code, 0);
269+
})
225270
});

0 commit comments

Comments
 (0)