From 04ae1a551726dd6e0047a942b459d18e1dcb1935 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Thu, 31 Oct 2024 22:19:19 -0700 Subject: [PATCH] fix(cli): set `npm_config_user_agent` when running npm packages or tasks (#26639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #25342. Still not sure on the exact user agent to set (should it include `node`?). After this PR, here's the state of running some `create-*` packages (just ones I could think of off the top of my head): | package | prints/runs/suggests deno install | notes | | ---------------- | ------------- | ------ | | `create-next-app` | ❌ | falls back to npm, needs a PR ([code](https://github.com/vercel/next.js/blob/c32e2802097c03fd9f95b1dae228d6e0257569c0/packages/create-next-app/helpers/get-pkg-manager.ts#L3)) | `sv create` | ❌ | uses `package-manager-detector`, needs a PR ([code](https://github.com/antfu-collective/package-manager-detector/tree/main)) | `create-qwik` | ✅ | runs `deno install` but suggests `deno start` which doesn't work (should be `deno task start` or `deno run start`) | `create-astro` | ✅ | runs `deno install` but suggests `npm run dev` later in output, probably needs a PR | `nuxi init` | ❌ | deno not an option in dialog, needs a PR ([code](https://github.com/nuxt/cli/blob/f04e2e894446f597da9d971b7eb03191d5a0da7e/src/commands/init.ts#L96-L102)) | `create-react-app` | ❌ | uses npm | `ng new` (`@angular/cli`) | ❌ | uses npm | `create-vite` | ✅ | suggests working deno commands 🎉 | `create-solid` | ❌ | suggests npm commands, needs PR It's possible that fixing `package-manager-detector` or other packages might make some of these just work, but haven't looked too carefully at each --- cli/npm/mod.rs | 12 +++++ cli/task_runner.rs | 10 +++- cli/tools/run/mod.rs | 18 ++++++++ .../print-npm-user-agent/1.0.0/index.js | 2 + .../print-npm-user-agent/1.0.0/package.json | 10 ++++ .../npm/user_agent_env_var/__test__.jsonc | 46 +++++++++++++++++++ .../npm/user_agent_env_var/bin_command.out | 2 + tests/specs/npm/user_agent_env_var/deno.jsonc | 3 ++ tests/specs/npm/user_agent_env_var/main.ts | 1 + .../specs/npm/user_agent_env_var/package.json | 8 ++++ .../npm/user_agent_env_var/postinstall.out | 10 ++++ tests/specs/npm/user_agent_env_var/run.out | 1 + tests/specs/npm/user_agent_env_var/test.mjs | 1 + 13 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 tests/registry/npm/@denotest/print-npm-user-agent/1.0.0/index.js create mode 100644 tests/registry/npm/@denotest/print-npm-user-agent/1.0.0/package.json create mode 100644 tests/specs/npm/user_agent_env_var/__test__.jsonc create mode 100644 tests/specs/npm/user_agent_env_var/bin_command.out create mode 100644 tests/specs/npm/user_agent_env_var/deno.jsonc create mode 100644 tests/specs/npm/user_agent_env_var/main.ts create mode 100644 tests/specs/npm/user_agent_env_var/package.json create mode 100644 tests/specs/npm/user_agent_env_var/postinstall.out create mode 100644 tests/specs/npm/user_agent_env_var/run.out create mode 100644 tests/specs/npm/user_agent_env_var/test.mjs diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index f48f7a7405..3971b1a0b3 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -189,3 +189,15 @@ impl NpmFetchResolver { info } } + +pub const NPM_CONFIG_USER_AGENT_ENV_VAR: &str = "npm_config_user_agent"; + +pub fn get_npm_config_user_agent() -> String { + format!( + "deno/{} npm/? deno/{} {} {}", + env!("CARGO_PKG_VERSION"), + env!("CARGO_PKG_VERSION"), + std::env::consts::OS, + std::env::consts::ARCH + ) +} diff --git a/cli/task_runner.rs b/cli/task_runner.rs index 418043b23f..43840e868d 100644 --- a/cli/task_runner.rs +++ b/cli/task_runner.rs @@ -155,6 +155,12 @@ fn prepare_env_vars( initial_cwd.to_string_lossy().to_string(), ); } + if !env_vars.contains_key(crate::npm::NPM_CONFIG_USER_AGENT_ENV_VAR) { + env_vars.insert( + crate::npm::NPM_CONFIG_USER_AGENT_ENV_VAR.into(), + crate::npm::get_npm_config_user_agent(), + ); + } if let Some(node_modules_dir) = node_modules_dir { prepend_to_path( &mut env_vars, @@ -204,7 +210,7 @@ impl ShellCommand for NpmCommand { mut context: ShellCommandContext, ) -> LocalBoxFuture<'static, ExecuteResult> { if context.args.first().map(|s| s.as_str()) == Some("run") - && context.args.len() > 2 + && context.args.len() >= 2 // for now, don't run any npm scripts that have a flag because // we don't handle stuff like `--workspaces` properly && !context.args.iter().any(|s| s.starts_with('-')) @@ -267,10 +273,12 @@ impl ShellCommand for NodeCommand { ) .execute(context); } + args.extend(["run", "-A"].into_iter().map(|s| s.to_string())); args.extend(context.args.iter().cloned()); let mut state = context.state; + state.apply_env_var(USE_PKG_JSON_HIDDEN_ENV_VAR_NAME, "1"); ExecutableCommand::new("deno".to_string(), std::env::current_exe().unwrap()) .execute(ShellCommandContext { diff --git a/cli/tools/run/mod.rs b/cli/tools/run/mod.rs index 152e2650bd..bebb3f5881 100644 --- a/cli/tools/run/mod.rs +++ b/cli/tools/run/mod.rs @@ -30,6 +30,16 @@ To grant permissions, set them before the script argument. For example: } } +fn set_npm_user_agent() { + static ONCE: std::sync::Once = std::sync::Once::new(); + ONCE.call_once(|| { + std::env::set_var( + crate::npm::NPM_CONFIG_USER_AGENT_ENV_VAR, + crate::npm::get_npm_config_user_agent(), + ); + }); +} + pub async fn run_script( mode: WorkerExecutionMode, flags: Arc, @@ -58,6 +68,10 @@ pub async fn run_script( let main_module = cli_options.resolve_main_module()?; + if main_module.scheme() == "npm" { + set_npm_user_agent(); + } + maybe_npm_install(&factory).await?; let worker_factory = factory.create_cli_main_worker_factory().await?; @@ -119,6 +133,10 @@ async fn run_with_watch( let cli_options = factory.cli_options()?; let main_module = cli_options.resolve_main_module()?; + if main_module.scheme() == "npm" { + set_npm_user_agent(); + } + maybe_npm_install(&factory).await?; let _ = watcher_communicator.watch_paths(cli_options.watch_paths()); diff --git a/tests/registry/npm/@denotest/print-npm-user-agent/1.0.0/index.js b/tests/registry/npm/@denotest/print-npm-user-agent/1.0.0/index.js new file mode 100644 index 0000000000..b835b8e25e --- /dev/null +++ b/tests/registry/npm/@denotest/print-npm-user-agent/1.0.0/index.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log(`npm_config_user_agent: ${process.env["npm_config_user_agent"]}`); \ No newline at end of file diff --git a/tests/registry/npm/@denotest/print-npm-user-agent/1.0.0/package.json b/tests/registry/npm/@denotest/print-npm-user-agent/1.0.0/package.json new file mode 100644 index 0000000000..9071173467 --- /dev/null +++ b/tests/registry/npm/@denotest/print-npm-user-agent/1.0.0/package.json @@ -0,0 +1,10 @@ +{ + "name": "@denotest/print-npm-user-agent", + "version": "1.0.0", + "bin": { + "print-npm-user-agent": "index.js" + }, + "scripts": { + "postinstall": "echo postinstall && node index.js && exit 1" + } +} \ No newline at end of file diff --git a/tests/specs/npm/user_agent_env_var/__test__.jsonc b/tests/specs/npm/user_agent_env_var/__test__.jsonc new file mode 100644 index 0000000000..a2af970a0e --- /dev/null +++ b/tests/specs/npm/user_agent_env_var/__test__.jsonc @@ -0,0 +1,46 @@ +{ + "tempDir": true, + "tests": { + "set_for_npm_package": { + "steps": [ + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "run -A npm:@denotest/print-npm-user-agent", + "output": "run.out" + } + ] + }, + "unset_for_local_file": { + "steps": [ + { + "args": "run -A main.ts", + "output": "Download [WILDCARD]\nnpm_config_user_agent: undefined\n" + } + ] + }, + "set_for_tasks": { + "steps": [ + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "task run-via-bin", + "output": "bin_command.out" + } + ] + }, + "set_for_lifecycle_scripts": { + "steps": [ + { + "args": "install --allow-scripts", + "output": "postinstall.out", + "exitCode": 1 + } + ] + } + } +} diff --git a/tests/specs/npm/user_agent_env_var/bin_command.out b/tests/specs/npm/user_agent_env_var/bin_command.out new file mode 100644 index 0000000000..c8e9413038 --- /dev/null +++ b/tests/specs/npm/user_agent_env_var/bin_command.out @@ -0,0 +1,2 @@ +Task run-via-bin print-npm-user-agent +npm_config_user_agent: deno/[WILDCARD] npm/? deno/[WILDCARD] [WILDCARD] [WILDCARD] diff --git a/tests/specs/npm/user_agent_env_var/deno.jsonc b/tests/specs/npm/user_agent_env_var/deno.jsonc new file mode 100644 index 0000000000..fbd70ec480 --- /dev/null +++ b/tests/specs/npm/user_agent_env_var/deno.jsonc @@ -0,0 +1,3 @@ +{ + "nodeModulesDir": "auto" +} diff --git a/tests/specs/npm/user_agent_env_var/main.ts b/tests/specs/npm/user_agent_env_var/main.ts new file mode 100644 index 0000000000..2c51107e3c --- /dev/null +++ b/tests/specs/npm/user_agent_env_var/main.ts @@ -0,0 +1 @@ +console.log(`npm_config_user_agent: ${Deno.env.get("npm_config_user_agent")}`); diff --git a/tests/specs/npm/user_agent_env_var/package.json b/tests/specs/npm/user_agent_env_var/package.json new file mode 100644 index 0000000000..12cc0cc6fb --- /dev/null +++ b/tests/specs/npm/user_agent_env_var/package.json @@ -0,0 +1,8 @@ +{ + "scripts": { + "run-via-bin": "print-npm-user-agent" + }, + "dependencies": { + "@denotest/print-npm-user-agent": "1.0.0" + } +} diff --git a/tests/specs/npm/user_agent_env_var/postinstall.out b/tests/specs/npm/user_agent_env_var/postinstall.out new file mode 100644 index 0000000000..19a08598fb --- /dev/null +++ b/tests/specs/npm/user_agent_env_var/postinstall.out @@ -0,0 +1,10 @@ +Download http://localhost:4260/@denotest%2fprint-npm-user-agent +Download http://localhost:4260/@denotest/print-npm-user-agent/1.0.0.tgz +Initialize @denotest/print-npm-user-agent@1.0.0 +Initialize @denotest/print-npm-user-agent@1.0.0: running 'postinstall' script +error: script 'postinstall' in '@denotest/print-npm-user-agent@1.0.0' failed with exit code 1 +stdout: +postinstall +npm_config_user_agent: deno/[WILDCARD] npm/? deno/[WILDCARD] [WILDCARD] [WILDCARD] + +error: failed to run scripts for packages: @denotest/print-npm-user-agent@1.0.0 diff --git a/tests/specs/npm/user_agent_env_var/run.out b/tests/specs/npm/user_agent_env_var/run.out new file mode 100644 index 0000000000..a630ac412f --- /dev/null +++ b/tests/specs/npm/user_agent_env_var/run.out @@ -0,0 +1 @@ +npm_config_user_agent: deno/[WILDCARD] npm/? deno/[WILDCARD] [WILDCARD] [WILDCARD] diff --git a/tests/specs/npm/user_agent_env_var/test.mjs b/tests/specs/npm/user_agent_env_var/test.mjs new file mode 100644 index 0000000000..ae035d40ef --- /dev/null +++ b/tests/specs/npm/user_agent_env_var/test.mjs @@ -0,0 +1 @@ +console.log(process.env.npm_config_user_agent);