diff --git a/CHANGELOG.md b/CHANGELOG.md index e178c7e537..6dbf944ea7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Features + +- Prompt for login after interactive install ([#3406](https://github.com/getsentry/sentry-cli/pull/3406)) + ## 3.7.0 ### Features diff --git a/scripts/__tests__/prompt-login.test.js b/scripts/__tests__/prompt-login.test.js new file mode 100644 index 0000000000..38c1fa8962 --- /dev/null +++ b/scripts/__tests__/prompt-login.test.js @@ -0,0 +1,26 @@ +const { promptLogin } = require('../prompt-login'); + +describe('promptLogin', () => { + test('runs login for an interactive install', () => { + const spawnSync = jest.fn(); + + promptLogin('/path/to/sentry-cli', { isTTY: true }, { isTTY: true }, spawnSync); + + expect(spawnSync).toHaveBeenCalledWith( + '/path/to/sentry-cli', + ['login', '--global', '--if-needed'], + { stdio: 'inherit' } + ); + }); + + test.each([ + [{ isTTY: false }, { isTTY: true }], + [{ isTTY: true }, { isTTY: false }], + ])('skips login for a non-interactive install', (stdin, stdout) => { + const spawnSync = jest.fn(); + + promptLogin('/path/to/sentry-cli', stdin, stdout, spawnSync); + + expect(spawnSync).not.toHaveBeenCalled(); + }); +}); diff --git a/scripts/install.js b/scripts/install.js index fd02e64206..c52db331c8 100755 --- a/scripts/install.js +++ b/scripts/install.js @@ -17,6 +17,7 @@ const which = require('which'); const helper = require('../js/helper'); const pkgInfo = require('../package.json'); const { Logger } = require('../js/logger'); +const { promptLogin } = require('./prompt-login'); const logger = new Logger(getLogStream('stderr')); @@ -317,6 +318,7 @@ if (distributionPackageName === undefined) { try { require.resolve(`${distributionPackageName}/${distributionSubpath}`); // If the `resolve` call succeeds it means a binary was installed successfully via optional dependencies so we can skip the manual postinstall download. + promptLogin(helper.getPath()); process.exit(0); } catch (e) { // Optional dependencies likely didn't get installed - proceed with fallback downloading manually @@ -329,6 +331,7 @@ This can happen if you use an option to disable optional dependencies during ins downloadBinary() .then(() => checkVersion()) + .then(() => promptLogin(helper.getPath())) .then(() => { process.exit(0); }) diff --git a/scripts/prompt-login.js b/scripts/prompt-login.js new file mode 100644 index 0000000000..cd498bb6cd --- /dev/null +++ b/scripts/prompt-login.js @@ -0,0 +1,20 @@ +'use strict'; + +const childProcess = require('child_process'); + +function promptLogin( + binaryPath, + stdin = process.stdin, + stdout = process.stdout, + spawnSync = childProcess.spawnSync +) { + if (!stdin.isTTY || !stdout.isTTY) { + return; + } + + spawnSync(binaryPath, ['login', '--global', '--if-needed'], { + stdio: 'inherit', + }); +} + +module.exports = { promptLogin }; diff --git a/src/commands/login.rs b/src/commands/login.rs index c7c8957d7d..4eeed19c3d 100644 --- a/src/commands/login.rs +++ b/src/commands/login.rs @@ -10,13 +10,21 @@ use crate::utils::auth_token::AuthToken; use crate::utils::ui::{prompt, prompt_to_continue}; pub fn make_command(command: Command) -> Command { - command.about("Authenticate with the Sentry server.").arg( - Arg::new("global") - .short('g') - .long("global") - .action(ArgAction::SetTrue) - .help("Store authentication token globally rather than locally."), - ) + command + .about("Authenticate with the Sentry server.") + .arg( + Arg::new("global") + .short('g') + .long("global") + .action(ArgAction::SetTrue) + .help("Store authentication token globally rather than locally."), + ) + .arg( + Arg::new("if_needed") + .long("if-needed") + .action(ArgAction::SetTrue) + .hide(true), + ) } fn update_config(config: &Config, token: AuthToken, url: &str) -> Result<()> { @@ -28,6 +36,11 @@ fn update_config(config: &Config, token: AuthToken, url: &str) -> Result<()> { pub fn execute(matches: &ArgMatches) -> Result<()> { let config = Config::current(); + + if matches.get_flag("if_needed") && config.get_auth().is_some() { + return Ok(()); + } + let token_url = format!( "{}/orgredirect/organizations/:orgslug/settings/auth-tokens/", config.get_base_url()? diff --git a/tests/integration/_cases/login/login-if-needed.trycmd b/tests/integration/_cases/login/login-if-needed.trycmd new file mode 100644 index 0000000000..211ef4a3ef --- /dev/null +++ b/tests/integration/_cases/login/login-if-needed.trycmd @@ -0,0 +1,4 @@ +``` +$ sentry-cli login --if-needed --auth-token 0000000000000000000000000000000000000000000000000000000000000000 +? success +```