From 8cffbcc94ae76795354e0f4753d1cbdb41c3a8c5 Mon Sep 17 00:00:00 2001 From: Luca Palmieri Date: Sun, 15 Nov 2020 16:01:49 +0000 Subject: [PATCH] Add CI. (#3) * Add CI. * Fix linter + formatting * Fix linter. * Formatting * Update version. --- .github/workflows/audit-on-push.yml | 14 ++++++ .github/workflows/general.yml | 71 +++++++++++++++++++++++++++ .github/workflows/scheduled-audit.yml | 12 +++++ Cargo.toml | 2 +- src/afs.rs | 11 +++-- src/lib.rs | 34 +++++++++---- tests/parse.rs | 28 +++++++++-- 7 files changed, 151 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/audit-on-push.yml create mode 100644 .github/workflows/general.yml create mode 100644 .github/workflows/scheduled-audit.yml diff --git a/.github/workflows/audit-on-push.yml b/.github/workflows/audit-on-push.yml new file mode 100644 index 0000000..e46bb3c --- /dev/null +++ b/.github/workflows/audit-on-push.yml @@ -0,0 +1,14 @@ +name: Security audit +on: + push: + paths: + - '**/Cargo.toml' + - '**/Cargo.lock' +jobs: + security_audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml new file mode 100644 index 0000000..3e90dc1 --- /dev/null +++ b/.github/workflows/general.yml @@ -0,0 +1,71 @@ +name: Rust + +on: [push, pull_request] + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + + fmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - run: rustup component add rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - run: rustup component add clippy + - uses: actions-rs/cargo@v1 + with: + command: clippy + args: -- -D warnings + + coverage: + name: Code coverage + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Run cargo-tarpaulin + uses: actions-rs/tarpaulin@v0.1 + with: + args: '--ignore-tests' diff --git a/.github/workflows/scheduled-audit.yml b/.github/workflows/scheduled-audit.yml new file mode 100644 index 0000000..ee08c8f --- /dev/null +++ b/.github/workflows/scheduled-audit.yml @@ -0,0 +1,12 @@ +name: Security audit +on: + schedule: + - cron: '0 0 * * *' +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 5de0924..91a0a1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2018" name = "cargo-manifest" -version = "0.1.0" +version = "0.2.0" authors = ["Kornel , Luca Palmieri "] description = "Helper crate to parse and manipulate manifests - `Cargo.toml` files." keywords = ["cargo", "metadata", "toml", "serde", "manifest"] diff --git a/src/afs.rs b/src/afs.rs index b075352..f1f5aa8 100644 --- a/src/afs.rs +++ b/src/afs.rs @@ -19,11 +19,12 @@ impl<'a> Filesystem<'a> { impl<'a> AbstractFilesystem for Filesystem<'a> { fn file_names_in(&self, rel_path: &str) -> io::Result>> { - Ok(read_dir(self.path.join(rel_path))?.filter_map(|entry| { - entry.ok().map(|e| { - e.file_name().to_string_lossy().to_string().into_boxed_str() + Ok(read_dir(self.path.join(rel_path))? + .filter_map(|entry| { + entry + .ok() + .map(|e| e.file_name().to_string_lossy().to_string().into_boxed_str()) }) - }) - .collect()) + .collect()) } } diff --git a/src/lib.rs b/src/lib.rs index ed4d4da..f6fdfdd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::large_enum_variant)] //! This crate defines `struct`s that can be deserialized with Serde //! to load and inspect `Cargo.toml` metadata. //! @@ -5,7 +6,6 @@ use std::fs; use std::io; use std::path::Path; -use toml; #[macro_use] extern crate serde_derive; @@ -24,6 +24,7 @@ mod afs; mod error; pub use crate::afs::*; pub use crate::error::Error; +use std::str::FromStr; /// The top-level `Cargo.toml` structure /// @@ -102,13 +103,17 @@ impl Manifest { pub fn from_path(cargo_toml_path: impl AsRef) -> Result { Self::from_path_with_metadata(cargo_toml_path) } +} + +impl FromStr for Manifest { + type Err = Error; /// Parse contents of a `Cargo.toml` file loaded as a string /// /// Note: this is **not** a file name, but file's content. See `from_path`. /// /// It does not call `complete_from_path`, so may be missing implicit data. - pub fn from_str(cargo_toml_content: &str) -> Result { + fn from_str(cargo_toml_content: &str) -> Result { Self::from_slice_with_metadata(cargo_toml_content.as_bytes()) } } @@ -148,7 +153,9 @@ impl Deserialize<'a>> Manifest { /// /// This scans the disk to make the data in the manifest as complete as possible. pub fn complete_from_path(&mut self, path: &Path) -> Result<(), Error> { - let manifest_dir = path.parent().ok_or_else(|| io::Error::new(io::ErrorKind::Other, "bad path"))?; + let manifest_dir = path + .parent() + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "bad path"))?; self.complete_from_abstract_filesystem(Filesystem::new(manifest_dir)) } @@ -373,7 +380,7 @@ impl Dependency { pub fn req(&self) -> &str { match *self { Dependency::Simple(ref v) => v, - Dependency::Detailed(ref d) => d.version.as_ref().map(|s| s.as_str()).unwrap_or("*"), + Dependency::Detailed(ref d) => d.version.as_deref().unwrap_or("*"), } } @@ -393,13 +400,13 @@ impl Dependency { pub fn package(&self) -> Option<&str> { match *self { Dependency::Simple(_) => None, - Dependency::Detailed(ref d) => d.package.as_ref().map(|p| p.as_str()), + Dependency::Detailed(ref d) => d.package.as_deref(), } } // Git URL of this dependency, if any pub fn git(&self) -> Option<&str> { - self.detail().and_then(|d| d.git.as_ref().map(|p| p.as_str())) + self.detail().and_then(|d| d.git.as_deref()) } // `true` if it's an usual crates.io dependency, @@ -409,7 +416,13 @@ impl Dependency { Dependency::Simple(_) => true, Dependency::Detailed(ref d) => { // TODO: allow registry to be set to crates.io explicitly? - d.path.is_none() && d.registry.is_none() && d.registry_index.is_none() && d.git.is_none() && d.tag.is_none() && d.branch.is_none() && d.rev.is_none() + d.path.is_none() + && d.registry.is_none() + && d.registry_index.is_none() + && d.git.is_none() + && d.tag.is_none() + && d.branch.is_none() + && d.rev.is_none() } } } @@ -499,7 +512,7 @@ impl PartialEq for bool { fn eq(&self, p: &Publish) -> bool { match *p { Publish::Flag(flag) => flag == *self, - Publish::Registry(ref reg) => !reg.is_empty() == *self, + Publish::Registry(ref reg) => reg.is_empty() != *self, } } } @@ -526,8 +539,9 @@ fn default_master() -> String { } fn ok_or_default<'de, T, D>(deserializer: D) -> Result - where T: Deserialize<'de> + Default, - D: Deserializer<'de> +where + T: Deserialize<'de> + Default, + D: Deserializer<'de>, { Ok(Deserialize::deserialize(deserializer).unwrap_or_default()) } diff --git a/tests/parse.rs b/tests/parse.rs index 9827775..d307401 100644 --- a/tests/parse.rs +++ b/tests/parse.rs @@ -1,6 +1,7 @@ use cargo_manifest as lib; use cargo_manifest::Manifest; use std::fs::read; +use std::str::FromStr; use toml; #[test] @@ -8,7 +9,8 @@ fn own() { let m = Manifest::from_slice(&read("Cargo.toml").unwrap()).unwrap(); let package = m.package.as_ref().unwrap(); assert_eq!("cargo-manifest", package.name); - let m = Manifest::::from_slice_with_metadata(&read("Cargo.toml").unwrap()).unwrap(); + let m = + Manifest::::from_slice_with_metadata(&read("Cargo.toml").unwrap()).unwrap(); let package = m.package.as_ref().unwrap(); assert_eq!("cargo-manifest", package.name); assert_eq!(lib::Edition::E2018, package.edition); @@ -19,7 +21,17 @@ fn opt_level() { let m = Manifest::from_slice(&read("tests/opt_level.toml").unwrap()).unwrap(); let package = m.package.as_ref().unwrap(); assert_eq!("byteorder", package.name); - assert_eq!(3, m.profile.unwrap().bench.unwrap().opt_level.unwrap().as_integer().unwrap()); + assert_eq!( + 3, + m.profile + .unwrap() + .bench + .unwrap() + .opt_level + .unwrap() + .as_integer() + .unwrap() + ); assert_eq!(false, m.lib.unwrap().bench); assert_eq!(lib::Edition::E2015, package.edition); assert_eq!(1, m.patch.unwrap().len()); @@ -34,7 +46,10 @@ fn autobin() { assert!(package.autobins); assert!(m.lib.is_none()); assert_eq!(1, m.bin.as_ref().unwrap().len()); - assert_eq!(Some("auto-bin"), m.bin.unwrap()[0].name.as_ref().map(|s| s.as_str())); + assert_eq!( + Some("auto-bin"), + m.bin.unwrap()[0].name.as_ref().map(|s| s.as_str()) + ); } #[test] @@ -60,10 +75,13 @@ fn metadata() { #[test] fn legacy() { - let m = Manifest::from_slice(br#"[project] + let m = Manifest::from_slice( + br#"[project] name = "foo" version = "1" - "#).expect("parse old"); + "#, + ) + .expect("parse old"); let package = m.package.as_ref().unwrap(); assert_eq!("foo", package.name); let m = Manifest::from_str("name = \"foo\"\nversion=\"1\"").expect("parse bare");