Skip to content

Commit

Permalink
surface forge fmt errors, clean up and colorize terminal output (#4)
Browse files Browse the repository at this point in the history
* fix: show warnings/errors from forge fmt

* style: better looking log outputs

* build: bump version

* chore: small cleanup

* Added helpful error message (#6)

Signed-off-by: Matt Solomon <[email protected]>

Signed-off-by: Matt Solomon <[email protected]>

Signed-off-by: Matt Solomon <[email protected]>
Co-authored-by: John Feras <[email protected]>
  • Loading branch information
mds1 and jferas committed Nov 7, 2022
1 parent bf8c7d4 commit 9a7351a
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 20 deletions.
14 changes: 13 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
license = "MIT"
name = "scopelint"
repository = "https://github.com/ScopeLift/scopelint"
version = "0.0.10"
version = "0.0.11"

[dependencies]
colored = "2.0.0"
grep = "0.2.10"
regex = "1.6.0"
taplo = "0.11.0"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Formatting and checking does the following:
- Install with `cargo install scopelint`.
- Format code with `scopelint fmt`.
- Validate formatting with `scopelint check`.
- Print the version with `scopelint --version`.
- Use the ScopeLift [foundry template](https://github.com/ScopeLift/foundry-template/) to automatically run scopelint and slither in CI.

## Limitations
Expand Down
43 changes: 28 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![warn(missing_docs, unreachable_pub, unused, rust_2021_compatibility)]
#![warn(clippy::all, clippy::pedantic, clippy::cargo, clippy::nursery)]

use colored::Colorize;
use grep::{
matcher::Matcher,
regex::RegexMatcher,
Expand Down Expand Up @@ -39,8 +40,8 @@ impl Config {
2 => match args[1].as_str() {
"fmt" => Ok(Self { mode: Mode::Format }),
"check" => Ok(Self { mode: Mode::Check }),
"version" => Ok(Self { mode: Mode::Version }),
_ => Err("Unrecognized mode"),
"--version" | "-v" => Ok(Self { mode: Mode::Version }),
_ => Err("Unrecognized mode: Must be 'fmt', 'check', or '--version'"),
},
_ => Err("Too many arguments"),
}
Expand Down Expand Up @@ -80,7 +81,12 @@ fn version() {

fn fmt(taplo_opts: taplo::formatter::Options) -> Result<(), Box<dyn Error>> {
// Format Solidity with forge
process::Command::new("forge").arg("fmt").output().expect("forge fmt failed");
let forge_status = process::Command::new("forge").arg("fmt").output()?;

// Print any warnings/errors from `forge fmt`.
if !forge_status.stderr.is_empty() {
print!("{}", String::from_utf8(forge_status.stderr)?);
}

// Format `foundry.toml` with taplo.
let config_orig = fs::read_to_string("./foundry.toml")?;
Expand Down Expand Up @@ -109,15 +115,22 @@ fn check(taplo_opts: taplo::formatter::Options) -> Result<(), Box<dyn Error>> {
fn validate_fmt(taplo_opts: taplo::formatter::Options) -> Result<(), Box<dyn Error>> {
// Check Solidity with `forge fmt`
let forge_status = process::Command::new("forge").arg("fmt").arg("--check").output()?;
let forge_ok = forge_status.status.success();

// Print any warnings/errors from `forge fmt`.
let stderr = String::from_utf8(forge_status.stderr)?;
let forge_ok = forge_status.status.success() && stderr.is_empty();
print!("{stderr}"); // Prints nothing if stderr is empty.

// Check TOML with `taplo fmt`
let config_orig = fs::read_to_string("./foundry.toml")?;
let config_fmt = taplo::formatter::format(&config_orig, taplo_opts);
let taplo_ok = config_orig == config_fmt;

if !forge_ok || !taplo_ok {
eprintln!("Error: Formatting failed, run `scopelint fmt` to fix");
eprintln!(
"{}: Formatting validation failed, run `scopelint fmt` to fix",
"error".bold().red()
);
return Err("Invalid fmt found".into())
}
Ok(())
Expand All @@ -128,8 +141,8 @@ fn validate_names() -> Result<(), Box<dyn Error>> {
let results = validate(paths)?;

if !results.is_valid() {
eprintln!("{results}");
eprintln!("Error: Naming conventions failed, see details above");
eprint!("{results}");
eprintln!("{}: Naming conventions failed, see details above", "error".bold().red());
return Err("Invalid names found".into())
}
Ok(())
Expand All @@ -153,18 +166,18 @@ impl InvalidItem {
fn description(&self) -> String {
match self.kind {
Validator::Test => {
format!("Invalid test name in {} on line {}: {}\n", self.file, self.line, self.text)
format!("Invalid test name in {} on line {}: {}", self.file, self.line, self.text)
}
Validator::Constant => {
format!(
"Invalid constant or immutable name in {} on line {}: {}\n",
"Invalid constant or immutable name in {} on line {}: {}",
self.file, self.line, self.text
)
}
Validator::Script => format!("Invalid script interface in {}\n", self.file),
Validator::Script => format!("Invalid script interface in {}", self.file),
Validator::Src => {
format!(
"Invalid src method name in {} on line {}: {}\n",
"Invalid src method name in {} on line {}: {}",
self.file, self.line, self.text
)
}
Expand All @@ -182,16 +195,16 @@ struct ValidationResults {
impl fmt::Display for ValidationResults {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
for item in &self.invalid_tests {
write!(f, "{}", item.description())?;
writeln!(f, "{}", item.description())?;
}
for item in &self.invalid_constants {
write!(f, "{}", item.description())?;
writeln!(f, "{}", item.description())?;
}
for item in &self.invalid_scripts {
write!(f, "{}", item.description())?;
writeln!(f, "{}", item.description())?;
}
for item in &self.invalid_src {
write!(f, "{}", item.description())?;
writeln!(f, "{}", item.description())?;
}
Ok(())
}
Expand Down
7 changes: 4 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
#![doc = include_str!("../README.md")]
#![warn(missing_docs, unreachable_pub, unused, rust_2021_compatibility)]
#![warn(clippy::all, clippy::pedantic, clippy::cargo, clippy::nursery)]
use colored::Colorize;
use std::{env, process};

fn main() {
let args: Vec<String> = env::args().collect();

let config = scopelint::Config::build(&args).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {err}");
eprintln!("{}: Argument parsing failed with '{err}'", "error".bold().red());
process::exit(1);
});

if let Err(err) = scopelint::run(&config) {
eprintln!("\nExecution failed: {err}");
if let Err(_err) = scopelint::run(&config) {
// All warnings/errors have already been logged.
process::exit(1);
}
}

0 comments on commit 9a7351a

Please sign in to comment.