Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
22 changes: 19 additions & 3 deletions src/bin/cargo/commands/publish.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::command_prelude::*;
use std::io::IsTerminal;
use std::ops::Not;

use cargo::ops::{self, PublishOpts};
use cargo_credential::Secret;

pub fn cli() -> Command {
subcommand("publish")
Expand Down Expand Up @@ -45,13 +48,26 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
.into());
}

let token = args
.get_one::<String>("token")
.cloned()
.or_else(|| {
if std::io::stdin().is_terminal().not()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would really like to know why most windows-based and one mac-based "Test" checks were terminated in Github before I added this not a terminal condition here like in similar implementation in login command. Process hanged waiting input with no input provided? 🤔

&& let token_from_stdin = cargo_credential::read_line().unwrap_or_default()
&& token_from_stdin.is_empty().not()
{
Some(token_from_stdin)
} else {
None
}
})
.map(Secret::from);

ops::publish(
&ws,
&PublishOpts {
gctx,
token: args
.get_one::<String>("token")
.map(|s| s.to_string().into()),
token,
reg_or_index,
verify: !args.flag("no-verify"),
allow_dirty: args.flag("allow-dirty"),
Expand Down
1 change: 1 addition & 0 deletions src/doc/man/cargo-publish.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ following steps:

This command requires you to be authenticated with either the `--token` option
or using {{man "cargo-login" 1}}.
Instead of `--token` option, _token_ value might also be provided via stdin.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little confused reading this. I'm wondering if it would help to be more explicit about only reading stdin if it is not a terminal. Maybe something like this?

Suggested change
Instead of `--token` option, _token_ value might also be provided via stdin.
Instead of using the `--token` option, the _token_ value may be piped in via stdin.


See [the reference](../reference/publishing.html) for more details about
packaging and publishing.
Expand Down
3 changes: 2 additions & 1 deletion src/doc/man/generated_txt/cargo-publish.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ DESCRIPTION
manually. This timeout does not affect the upload.

This command requires you to be authenticated with either the --token
option or using cargo-login(1).
option or using cargo-login(1). Instead of --token option, token value
might also be provided via stdin.

See the reference
<https://doc.rust-lang.org/cargo/reference/publishing.html> for more
Expand Down
1 change: 1 addition & 0 deletions src/doc/src/commands/cargo-publish.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ following steps:

This command requires you to be authenticated with either the `--token` option
or using [cargo-login(1)](cargo-login.html).
Instead of `--token` option, _token_ value might also be provided via stdin.

See [the reference](../reference/publishing.html) for more details about
packaging and publishing.
Expand Down
1 change: 1 addition & 0 deletions src/etc/man/cargo-publish.1
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ manually. This timeout does not affect the upload.
.sp
This command requires you to be authenticated with either the \fB\-\-token\fR option
or using \fBcargo\-login\fR(1).
Instead of \fB\-\-token\fR option, \fItoken\fR value might also be provided via stdin.
.sp
See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/publishing.html> for more details about
packaging and publishing.
Expand Down
137 changes: 137 additions & 0 deletions tests/testsuite/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4509,3 +4509,140 @@ Caused by:
"#]])
.run();
}

#[cargo_test]
fn publish_reads_token_from_stdin() {
let registry = RegistryBuilder::new()
.alternative_named("i-need-token")
.http_api()
.token(registry::Token::Plaintext("TOKEN".to_string()))
.auth_required()
.build();

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2024"
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("publish --no-verify")
.with_stdin("TOKEN")
.replace_crates_io(registry.index_url())
.with_status(0)
.with_stderr_data(str![[r##"
[UPDATING] crates.io index
[WARNING] manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ([ROOT]/foo)
[PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed)
[UPLOADING] foo v0.0.1 ([ROOT]/foo)
[UPLOADED] foo v0.0.1 to registry `crates-io`
[NOTE] waiting for foo v0.0.1 to be available at registry `crates-io`
[HELP] you may press ctrl-c to skip waiting; the crate should be available shortly
[PUBLISHED] foo v0.0.1 at registry `crates-io`

"##]])
.run();
}

#[cargo_test]
fn publish_works_without_token_specified_when_login_is_made_before() {
let registry = RegistryBuilder::new()
.alternative_named("i-need-token")
.http_api()
.token(registry::Token::Plaintext("TOKEN".to_string()))
.auth_required()
.build();

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2024"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("login -v")
.replace_crates_io(registry.index_url())
.with_status(0)
.with_stdin("TOKEN")
.run();

p.cargo("publish --no-verify")
.replace_crates_io(registry.index_url())
.with_status(0)
.with_stderr_data(str![[r##"
[UPDATING] crates.io index
[WARNING] manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ([ROOT]/foo)
[PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed)
[UPLOADING] foo v0.0.1 ([ROOT]/foo)
[UPLOADED] foo v0.0.1 to registry `crates-io`
[NOTE] waiting for foo v0.0.1 to be available at registry `crates-io`
[HELP] you may press ctrl-c to skip waiting; the crate should be available shortly
[PUBLISHED] foo v0.0.1 at registry `crates-io`

"##]])
.run();
}

#[cargo_test]
fn publish_fails_without_token_specified_when_login_failed_before() {
let registry = RegistryBuilder::new()
.alternative_named("i-need-token")
.http_api()
.token(registry::Token::Plaintext("TOKEN".to_string()))
.auth_required()
.build();

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2024"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("login -v")
.replace_crates_io(registry.index_url())
.with_status(101)
.with_stderr_data(str![[r##"
[UPDATING] crates.io index
[CREDENTIAL] cargo:token get crates-io
[CREDENTIAL] cargo:token login crates-io
please paste the token for crates-io below
[ERROR] credential provider `cargo:token` failed action `login`

Caused by:
please provide a non-empty token

"##]])
.run();

p.cargo("publish --no-verify")
.replace_crates_io(registry.index_url())
.with_status(101)
.with_stderr_data(str![[r##"
[UPDATING] crates.io index
[ERROR] no token found, please run `cargo login`
or use environment variable CARGO_REGISTRY_TOKEN

"##]])
.run();
}
Loading