fmt: check formatting with --check (#1001)

This commit is contained in:
Hoàng Đức Hiếu 2021-11-01 11:27:59 +07:00 committed by GitHub
parent 9987a0b8ae
commit 1cf8a714e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 89 additions and 5 deletions

7
Cargo.lock generated
View file

@ -231,6 +231,7 @@ dependencies = [
"log",
"pretty_assertions",
"regex",
"similar",
"snafu",
"strum",
"strum_macros",
@ -463,6 +464,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
[[package]]
name = "similar"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
[[package]]
name = "snafu"
version = "0.6.10"

View file

@ -28,6 +28,7 @@ lexiclean = "0.0.1"
libc = "0.2.0"
log = "0.4.4"
regex = "1.5.4"
similar = "2.1.0"
snafu = "0.6.0"
strum_macros = "0.22.0"
target = "2.0.0"

View file

@ -20,7 +20,7 @@ _just() {
case "${cmd}" in
just)
opts=" -q -u -v -e -l -h -V -f -d -c -s --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --unstable --verbose --changelog --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show --dotenv-filename --dotenv-path <ARGUMENTS>... "
opts=" -q -u -v -e -l -h -V -f -d -c -s --check --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --unstable --verbose --changelog --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show --dotenv-filename --dotenv-path <ARGUMENTS>... "
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0

View file

@ -32,6 +32,7 @@ edit:completion:arg-completer[just] = [@words]{
cand --show 'Show information about <RECIPE>'
cand --dotenv-filename 'Search for environment file named <DOTENV-FILENAME> instead of `.env`'
cand --dotenv-path 'Load environment file at <DOTENV-PATH> instead of searching for one'
cand --check 'Run `--fmt` in ''check'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.'
cand --dry-run 'Print what just would do without doing it'
cand --highlight 'Highlight echoed recipe lines in bold'
cand --no-dotenv 'Don''t load `.env` file'

View file

@ -23,6 +23,7 @@ complete -c just -n "__fish_use_subcommand" -l completions -d 'Print shell compl
complete -c just -n "__fish_use_subcommand" -s s -l show -d 'Show information about <RECIPE>'
complete -c just -n "__fish_use_subcommand" -l dotenv-filename -d 'Search for environment file named <DOTENV-FILENAME> instead of `.env`'
complete -c just -n "__fish_use_subcommand" -l dotenv-path -d 'Load environment file at <DOTENV-PATH> instead of searching for one'
complete -c just -n "__fish_use_subcommand" -l check -d 'Run `--fmt` in \'check\' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.'
complete -c just -n "__fish_use_subcommand" -l dry-run -d 'Print what just would do without doing it'
complete -c just -n "__fish_use_subcommand" -l highlight -d 'Highlight echoed recipe lines in bold'
complete -c just -n "__fish_use_subcommand" -l no-dotenv -d 'Don\'t load `.env` file'

View file

@ -37,6 +37,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
[CompletionResult]::new('--show', 'show', [CompletionResultType]::ParameterName, 'Show information about <RECIPE>')
[CompletionResult]::new('--dotenv-filename', 'dotenv-filename', [CompletionResultType]::ParameterName, 'Search for environment file named <DOTENV-FILENAME> instead of `.env`')
[CompletionResult]::new('--dotenv-path', 'dotenv-path', [CompletionResultType]::ParameterName, 'Load environment file at <DOTENV-PATH> instead of searching for one')
[CompletionResult]::new('--check', 'check', [CompletionResultType]::ParameterName, 'Run `--fmt` in ''check'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.')
[CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'Print what just would do without doing it')
[CompletionResult]::new('--highlight', 'highlight', [CompletionResultType]::ParameterName, 'Highlight echoed recipe lines in bold')
[CompletionResult]::new('--no-dotenv', 'no-dotenv', [CompletionResultType]::ParameterName, 'Don''t load `.env` file')

View file

@ -33,6 +33,7 @@ _just() {
'--show=[Show information about <RECIPE>]: :_just_commands' \
'(--dotenv-path)--dotenv-filename=[Search for environment file named <DOTENV-FILENAME> instead of `.env`]' \
'--dotenv-path=[Load environment file at <DOTENV-PATH> instead of searching for one]' \
'--check[Run `--fmt` in '\''check'\'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.]' \
'(-q --quiet)--dry-run[Print what just would do without doing it]' \
'--highlight[Highlight echoed recipe lines in bold]' \
'--no-dotenv[Don'\''t load `.env` file]' \

View file

@ -15,6 +15,7 @@ pub(crate) const DEFAULT_SHELL_ARG: &str = "-cu";
#[derive(Debug, PartialEq)]
pub(crate) struct Config {
pub(crate) color: Color,
pub(crate) check: bool,
pub(crate) dry_run: bool,
pub(crate) highlight: bool,
pub(crate) invocation_directory: PathBuf,
@ -81,6 +82,7 @@ mod cmd {
mod arg {
pub(crate) const ARGUMENTS: &str = "ARGUMENTS";
pub(crate) const CHECK: &str = "CHECK";
pub(crate) const CHOOSER: &str = "CHOOSER";
pub(crate) const CLEAR_SHELL_ARGS: &str = "CLEAR-SHELL-ARGS";
pub(crate) const COLOR: &str = "COLOR";
@ -116,6 +118,12 @@ impl Config {
.version_message("Print version information")
.setting(AppSettings::ColoredHelp)
.setting(AppSettings::TrailingVarArg)
.arg(
Arg::with_name(arg::CHECK)
.long("check")
.requires(cmd::FORMAT)
.help("Run `--fmt` in 'check' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required."),
)
.arg(
Arg::with_name(arg::CHOOSER)
.long("chooser")
@ -532,6 +540,7 @@ impl Config {
|| matches.occurrences_of(arg::SHELL_ARG) > 0;
Ok(Self {
check: matches.is_present(arg::CHECK),
dry_run: matches.is_present(arg::DRY_RUN),
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
shell: matches.value_of(arg::SHELL).unwrap().to_owned(),
@ -594,6 +603,9 @@ USAGE:
FLAGS:
--changelog Print changelog
--check Run `--fmt` in 'check' mode. Exits with 0 if
justfile is formatted correctly. Exits with 1 and
prints a diff if formatting is required.
--choose Select one or more recipes to run using a binary.
If `--chooser` is not passed the chooser defaults
to the value of $JUST_CHOOSER, falling back to

View file

@ -75,6 +75,7 @@ pub(crate) enum Error<'src> {
variable: String,
suggestion: Option<Suggestion<'src>>,
},
FormatCheckFoundDiff,
FunctionCall {
function: Name<'src>,
message: String,
@ -458,6 +459,9 @@ impl<'src> ColorDisplay for Error<'src> {
write!(f, "\n{}", suggestion)?;
}
}
FormatCheckFoundDiff => {
write!(f, "Formatted justfile differs from original.")?;
}
FunctionCall { function, message } => {
write!(
f,

View file

@ -77,7 +77,7 @@ impl Subcommand {
justfile.run(config, &search, overrides, &[])?
}
Dump => Self::dump(ast),
Format => Self::format(config, ast, &search)?,
Format => Self::format(config, ast, &src, &search)?,
List => Self::list(config, justfile),
Run {
arguments,
@ -255,11 +255,22 @@ impl Subcommand {
Ok(())
}
fn format(config: &Config, ast: Ast, search: &Search) -> Result<(), Error<'static>> {
fn format(config: &Config, ast: Ast, src: &str, search: &Search) -> Result<(), Error<'static>> {
config.require_unstable("The `--fmt` command is currently unstable.")?;
if let Err(io_error) =
File::create(&search.justfile).and_then(|mut file| write!(file, "{}", ast))
let src_formatted = ast.to_string();
if config.check {
if src == src_formatted {
Ok(())
} else {
print!(
"{}",
similar::udiff::unified_diff(similar::Algorithm::Patience, &src, &src_formatted, 2, None)
);
Err(Error::FormatCheckFoundDiff)
}
} else if let Err(io_error) =
File::create(&search.justfile).and_then(|mut file| file.write_all(&src_formatted.as_bytes()))
{
Err(Error::WriteJustfile {
justfile: search.justfile.clone(),

View file

@ -11,6 +11,51 @@ test! {
status: EXIT_FAILURE,
}
test! {
name: check_without_fmt,
justfile: "",
args: ("--check"),
stderr_regex: "error: The following required arguments were not provided:
--fmt
(.|\\n)+",
status: EXIT_FAILURE,
}
test! {
name: dry_run_ok,
justfile: r#"
# comment with spaces
export x := `backtick
with
lines`
recipe: deps
echo "$x"
deps:
echo {{ x }}
echo '$x'
"#,
args: ("--unstable", "--fmt", "--check"),
status: EXIT_SUCCESS,
}
test! {
name: dry_run_found_diff,
justfile: "x:=``\n",
args: ("--unstable", "--fmt", "--check"),
stdout: "
@@ -1 +1 @@
-x:=``
+x := ``
",
stderr: "
error: Formatted justfile differs from original.
",
status: EXIT_FAILURE,
}
#[test]
fn unstable_passed() {
let tmp = tempdir();