-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Block publishing on dirty directories #2714
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,9 +32,13 @@ pub fn publish(manifest_path: &Path, | |
| config: &Config, | ||
| token: Option<String>, | ||
| index: Option<String>, | ||
| verify: bool) -> CargoResult<()> { | ||
| verify: bool, allow_untracked: bool) -> CargoResult<()> { | ||
| let pkg = try!(Package::for_path(&manifest_path, config)); | ||
|
|
||
| if !allow_untracked { | ||
| try!(check_directory_cleanliness()); | ||
| } | ||
|
|
||
| if !pkg.publish() { | ||
| bail!("some crates cannot be published.\n\ | ||
| `{}` is marked as unpublishable", pkg.name()); | ||
|
|
@@ -55,6 +59,42 @@ pub fn publish(manifest_path: &Path, | |
| Ok(()) | ||
| } | ||
|
|
||
| fn check_git_cleanliness(repo: &git2::Repository) -> CargoResult<()> { | ||
| let mut opts = git2::StatusOptions::new(); | ||
| opts.include_untracked(true).recurse_untracked_dirs(true); | ||
| let status = try!(repo.statuses(Some(&mut opts))); | ||
| let files:Vec<String> = status.iter().map(|entry| { | ||
| let file = entry.index_to_workdir() | ||
| .and_then(|dir| dir.old_file().path()); | ||
| match file { | ||
| Some(file) => format!("{}", file.display()), | ||
| None => "file not displayable".to_string() | ||
| } | ||
| }).collect(); | ||
|
|
||
| if !files.is_empty(){ | ||
| bail!("{} uncommited or untacked files \ | ||
| that need to be addressed before publishing. to force the \ | ||
| publish command include --allow-untracked\nproblem files:\n{}", | ||
| files.len(), files.join("\n")); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| fn open_git_repo() -> Result<git2::Repository, git2::Error> { | ||
| let current_path = Path::new("."); | ||
| git2::Repository::discover(current_path) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is so small now it can probably just be inlined below: git2::Repository::discover(".").and_then(check_git_cleanliness)There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure how. the lack of a known system to check (git) should return on Ok(()). check_directory_cleanliness logic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah right, yeah, in that case you could do something like: match discover(".") {
Ok(repo) => check(repo),
Err(..) => Ok(()),
} |
||
| } | ||
|
|
||
| fn check_directory_cleanliness() -> CargoResult<()> { | ||
| if let Ok(repo) = open_git_repo() { | ||
| check_git_cleanliness(&repo) | ||
| } else { | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| fn verify_dependencies(pkg: &Package, registry_src: &SourceId) | ||
| -> CargoResult<()> { | ||
| for dep in pkg.dependencies().iter() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ use flate2::read::GzDecoder; | |
| use tar::Archive; | ||
| use url::Url; | ||
|
|
||
| use support::{project, execs}; | ||
| use support::execs; | ||
| use support::paths; | ||
| use support::git::repo; | ||
|
|
||
|
|
@@ -36,8 +36,100 @@ fn setup() { | |
| .build(); | ||
| } | ||
|
|
||
| test!(uncommited_git_files_allowed { | ||
| let root = paths::root().join("uncommited_git_files_allowed"); | ||
| let p = repo(&root) | ||
| .file("Cargo.toml", r#" | ||
| [project] | ||
| name = "foo" | ||
| version = "0.0.1" | ||
| authors = [] | ||
| license = "MIT" | ||
| description = "foo" | ||
| "#) | ||
| .nocommit_file("bad","file") | ||
| .file("src/main.rs", "fn main() {}"); | ||
| p.build(); | ||
| let mut cargo = ::cargo_process(); | ||
| cargo.cwd(p.root()); | ||
| assert_that(cargo.arg("publish").arg("--allow-untracked").arg("--no-verify"), | ||
| execs().with_status(0).with_stdout(&format!("\ | ||
| [UPDATING] registry `{reg}` | ||
| [PACKAGING] foo v0.0.1 ({dir}) | ||
| [UPLOADING] foo v0.0.1 ({dir})", | ||
| dir = p.url(), | ||
| reg = registry()))); | ||
| }); | ||
|
|
||
| test!(uncommited_git_files_error_from_sub_crate { | ||
| let root = paths::root().join("sub_uncommited_git"); | ||
| let p = repo(&root) | ||
| .file("Cargo.toml", r#" | ||
| [project] | ||
| name = "foo" | ||
| version = "0.0.1" | ||
| authors = [] | ||
| license = "MIT" | ||
| description = "foo" | ||
| "#) | ||
| .nocommit_file("bad.txt","file") | ||
| .file("src/main.rs", "fn main() {}") | ||
| .file("sub/lib.rs", "pub fn l() {}") | ||
| .file("sub/Cargo.toml", r#" | ||
| [package] | ||
| name = "crates-io" | ||
| version = "0.2.0" | ||
| authors = [] | ||
| license = "MIT/Apache-2.0" | ||
| repository = "https://github.com/rust-lang/cargo" | ||
| description = """ | ||
| """ | ||
|
|
||
| [lib] | ||
| name = "crates_io" | ||
| path = "lib.rs" | ||
| "#); | ||
| p.build(); | ||
|
|
||
| let mut cargo = ::cargo_process(); | ||
| cargo.cwd(p.root().join("sub")); | ||
| assert_that(cargo.arg("publish").arg("--no-verify"), | ||
| execs().with_status(101).with_stderr(&"\ | ||
| [ERROR] 1 uncommited or untacked files that need to be addressed before \ | ||
| publishing. to force the publish command include --allow-untracked | ||
| problem files: | ||
| bad.txt", | ||
| )); | ||
| }); | ||
|
|
||
| test!(uncommited_git_files_error { | ||
| let root = paths::root().join("uncommited_git_files_error"); | ||
| let p = repo(&root) | ||
| .file("Cargo.toml", r#" | ||
| [project] | ||
| name = "foo" | ||
| version = "0.0.1" | ||
| authors = [] | ||
| license = "MIT" | ||
| description = "foo" | ||
| "#) | ||
| .nocommit_file("bad.txt","file") | ||
| .file("src/main.rs", "fn main() {}"); | ||
| p.build(); | ||
|
|
||
| let mut cargo = ::cargo_process(); | ||
| cargo.cwd(p.root()); | ||
| assert_that(cargo.arg("publish").arg("--no-verify"), | ||
| execs().with_status(101).with_stderr_contains(&"\ | ||
| [ERROR] 1 uncommited or untacked files that need to be addressed before \ | ||
| publishing. to force the publish command include --allow-untracked | ||
| problem files:", | ||
| ).with_stderr_contains(&"bad.txt")); | ||
| }); | ||
|
|
||
| test!(simple { | ||
| let p = project("foo") | ||
| let root = paths::root().join("simple"); | ||
| let p = repo(&root) | ||
| .file("Cargo.toml", r#" | ||
| [project] | ||
| name = "foo" | ||
|
|
@@ -47,8 +139,12 @@ test!(simple { | |
| description = "foo" | ||
| "#) | ||
| .file("src/main.rs", "fn main() {}"); | ||
| p.build(); | ||
|
|
||
| let mut cargo = ::cargo_process(); | ||
| cargo.cwd(p.root()); | ||
|
|
||
| assert_that(p.cargo_process("publish").arg("--no-verify"), | ||
| assert_that(cargo.arg("publish").arg("--no-verify"), | ||
| execs().with_status(0).with_stdout(&format!("\ | ||
| [UPDATING] registry `{reg}` | ||
| [PACKAGING] foo v0.0.1 ({dir}) | ||
|
|
@@ -84,7 +180,8 @@ test!(simple { | |
| }); | ||
|
|
||
| test!(git_deps { | ||
| let p = project("foo") | ||
| let root = paths::root().join("git_deps"); | ||
| let p = repo(&root) | ||
|
||
| .file("Cargo.toml", r#" | ||
| [project] | ||
| name = "foo" | ||
|
|
@@ -97,16 +194,20 @@ test!(git_deps { | |
| git = "git://path/to/nowhere" | ||
| "#) | ||
| .file("src/main.rs", "fn main() {}"); | ||
| p.build(); | ||
|
|
||
| assert_that(p.cargo_process("publish").arg("-v").arg("--no-verify"), | ||
| let mut cargo = ::cargo_process(); | ||
| cargo.cwd(p.root()); | ||
| assert_that(cargo.arg("publish").arg("-v").arg("--no-verify"), | ||
| execs().with_status(101).with_stderr("\ | ||
| [ERROR] all dependencies must come from the same source. | ||
| dependency `foo` comes from git://path/to/nowhere instead | ||
| ")); | ||
| }); | ||
|
|
||
| test!(path_dependency_no_version { | ||
| let p = project("foo") | ||
| let root = paths::root().join("path_dependency_no_version"); | ||
| let p = repo(&root) | ||
| .file("Cargo.toml", r#" | ||
| [project] | ||
| name = "foo" | ||
|
|
@@ -126,16 +227,20 @@ test!(path_dependency_no_version { | |
| authors = [] | ||
| "#) | ||
| .file("bar/src/lib.rs", ""); | ||
| p.build(); | ||
|
|
||
| assert_that(p.cargo_process("publish"), | ||
| let mut cargo = ::cargo_process(); | ||
| cargo.cwd(p.root()); | ||
| assert_that(cargo.arg("publish"), | ||
| execs().with_status(101).with_stderr("\ | ||
| [ERROR] all path dependencies must have a version specified when publishing. | ||
| dependency `bar` does not specify a version | ||
| ")); | ||
| }); | ||
|
|
||
| test!(unpublishable_crate { | ||
| let p = project("foo") | ||
| let root = paths::root().join("unpublishable_crate"); | ||
| let p = repo(&root) | ||
| .file("Cargo.toml", r#" | ||
| [project] | ||
| name = "foo" | ||
|
|
@@ -146,8 +251,11 @@ test!(unpublishable_crate { | |
| publish = false | ||
| "#) | ||
| .file("src/main.rs", "fn main() {}"); | ||
| p.build(); | ||
|
|
||
| assert_that(p.cargo_process("publish"), | ||
| let mut cargo = ::cargo_process(); | ||
| cargo.cwd(p.root()); | ||
| assert_that(cargo.arg("publish"), | ||
| execs().with_status(101).with_stderr("\ | ||
| [ERROR] some crates cannot be published. | ||
| `foo` is marked as unpublishable | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can probably just be: