Repository: dotenv-linter/dotenv-linter
Pull request #242 (2020-08-05 16:15:57)

Add total problems to output and --quiet argument
This PR originates from #240.  
I decided to add an additional flag to be able not to display verbose information such as "Found n problems".
In #240 PR uses the flag `--no-color` for this, but I think we should add the additional flag `--quiet`.

<!--
Thank you for your pull request. Please provide a description above and review
the requirements below.

Bug fixes and new features should include tests.
-->

<!-- _Please make sure to review and check all of these items:_ -->

#### ✔ Checklist:
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] This PR has been added to [CHANGELOG.md](https://github.com/dotenv-linter/dotenv-linter/blob/master/CHANGELOG.md) (at the top of the list);
- [x] Tests for the changes have been added (for bug fixes / features);
- [x] Docs have been added / updated (for bug fixes / features).

<!-- _NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open._ -->


mgrachev: > It's a good idea to make a separate flag to control additional output 🚀
> 
> The only thing I would point out is that this PR adds not only the `--quiet` flag, but also the additional output itself 😂

Fixed 😃
mgrachev: @DDtKey Need your approve again.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58993d5..56b267f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ # Changelog
 
 ## [Unreleased]
 ### 🚀 Added
+- Add total problems to output and `--quiet` argument [#242](https://github.com/dotenv-linter/dotenv-linter/pull/242) ([@wesleimp](https://github.com/wesleimp), [@mgrachev](https://github.com/mgrachev))
 - Add autofix feature (for LowercaseKey check) [#228](https://github.com/dotenv-linter/dotenv-linter/pull/228) ([@evgeniy-r](https://github.com/evgeniy-r))
 - Add installation CI test for Windows (via `install.sh`) [#235](https://github.com/dotenv-linter/dotenv-linter/pull/235) ([@DDtKey](https://github.com/DDtKey))
 
diff --git a/README.md b/README.md
index 39a2a9f..90a6c4a 100644
--- a/README.md
+++ b/README.md
@@ -158,6 +158,8 @@ ## 🚀 Usage
 .env:2 DuplicatedKey: The FOO key is duplicated
 .env:3 UnorderedKey: The BAR key should go before the FOO key
 .env.test:1 LeadingCharacter: Invalid leading character detected
+
+Found 3 problems
 ```
 
 To check another directory, just pass its path as an argument. The same approach works if you need to check any files individually:
@@ -167,6 +169,8 @@ ## 🚀 Usage
 dir1/.env:1 LeadingCharacter: Invalid leading character detected
 dir1/.env:3 IncorrectDelimiter: The FOO-BAR key has incorrect delimiter
 dir2/.my-env-file:1 LowercaseKey: The bar key should be in uppercase
+
+Found 3 problems
 ```
 
 If you need to exclude a file or directory from check, you can use the argument `--exclude PATH` or its short version `-e PATH`:
@@ -175,6 +179,8 @@ ## 🚀 Usage
 $ dotenv-linter --exclude .env.test
 .env:2 DuplicatedKey: The FOO key is duplicated
 .env:3 UnorderedKey: The BAR key should go before the FOO key
+
+Found 2 problems
 ```
 
 If you need a recursive `.env` file search inside directories, you can use the flag `--recursive` or its short version `-r`:
@@ -183,6 +189,8 @@ ## 🚀 Usage
 $ dotenv-linter --recursive
 dir1/.env:2 DuplicatedKey: The FOO key is duplicated
 dir2/subdir/.env:3 IncorrectDelimiter: The FOO-BAR key has incorrect delimiter
+
+Found 2 problems
 ```
 
 If you need to skip some checks, you can use the argument `--skip CHECK_NAME` or its short version `-s CHECK_NAME`:
@@ -190,6 +198,17 @@ ## 🚀 Usage
 ```shell script
 $ dotenv-linter --skip UnorderedKey EndingBlankLine
 .env:2 DuplicatedKey: The FOO key is duplicated
+
+Found 1 problem
+```
+
+If you want to see only warnings without additional information, use the argument `--quiet` or its short version `-q`:
+
+```shell script
+$ dotenv-linter --quiet
+.env:2 DuplicatedKey: The FOO key is duplicated
+.env:3 UnorderedKey: The BAR key should go before the FOO key
+.env.test:1 LeadingCharacter: Invalid leading character detected
 ```
 
 If you need to view all available checks, you can use the flag `--show-checks`:
@@ -210,7 +229,7 @@ ## 🚀 Usage
 ```
 
 `dotenv-linter` can also automatically fix warnings in the files. Currently only one kind of warnings is fixed
-(`LowercaseKey`). You should use the argument `--fix` (or its short version `-f`) for this (will be available in [v2.2.0](https://github.com/dotenv-linter/dotenv-linter/issues/238):
+(`LowercaseKey`). You should use the argument `--fix` (or its short version `-f`) for this (will be available in [v2.2.0](https://github.com/dotenv-linter/dotenv-linter/issues/238)):
 
 ```shell script
 $ dotenv-linter -f
diff --git a/docs/quick_start.md b/docs/quick_start.md
index 99063c5..19e7cf6 100644
--- a/docs/quick_start.md
+++ b/docs/quick_start.md
@@ -4,29 +4,32 @@ ## 🚀 Quick Start
 
 ```sh
 $ dotenv-linter
-
 .env:2 DuplicatedKey: The FOO key is duplicated
 .env:3 UnorderedKey: The BAR key should go before the FOO key
 .env.test:1 LeadingCharacter: Invalid leading character detected
+
+Found 3 problems
 ```
 
 To check another directory, just pass its path as an argument. The same approach works if you need to check any files individually:
 
 ```sh
 $ dotenv-linter dir1 dir2/.my-env-file
-
 dir1/.env:1 LeadingCharacter: Invalid leading character detected
 dir1/.env:3 IncorrectDelimiter: The FOO-BAR key has incorrect delimiter
 dir2/.my-env-file:1 LowercaseKey: The bar key should be in uppercase
+
+Found 3 problems
 ```
 
 If you need to exclude a file from check, you can use the argument `--exclude FILE_PATH` or its short version `-e FILE_PATH`:
 
 ```sh
 $ dotenv-linter --exclude .env.test
-
 .env:2 DuplicatedKey: The FOO key is duplicated
 .env:3 UnorderedKey: The BAR key should go before the FOO key
+
+Found 2 problems
 ```
 
 If you need a recursive search inside directories (deeper than 1 level), you can use the flag `--recursive` or its short version `-r`:
@@ -35,21 +38,32 @@ ## 🚀 Quick Start
 $ dotenv-linter --recursive
 dir1/.env:2 DuplicatedKey: The FOO key is duplicated
 dir2/subdir/.env:3 IncorrectDelimiter: The FOO-BAR key has incorrect delimiter
+
+Found 2 problems
 ```
 
 If you need to skip some checks, you can use the argument `--skip CHECK_NAME` or its short version `-s CHECK_NAME`:
 
 ```sh
 $ dotenv-linter --skip UnorderedKey EndingBlankLine
+.env:2 DuplicatedKey: The FOO key is duplicated
+
+Found 1 problem
+```
 
+If you want to see only warnings without additional information, use the argument `--quiet` or its short version `-q`:
+
+```shell script
+$ dotenv-linter --quiet
 .env:2 DuplicatedKey: The FOO key is duplicated
+.env:3 UnorderedKey: The BAR key should go before the FOO key
+.env.test:1 LeadingCharacter: Invalid leading character detected
 ```
 
 If you need to view all available checks, you can use the argument `--show-checks`:
 
 ```sh
 $ dotenv-linter --show-checks
-
 DuplicatedKey
 EndingBlankLine
 ExtraBlankLine
@@ -62,3 +76,15 @@ ## 🚀 Quick Start
 TrailingWhitespace
 UnorderedKey
 ```
+
+`dotenv-linter` can also automatically fix warnings in the files. Currently only one kind of warnings is fixed
+(`LowercaseKey`). You should use the argument `--fix` (or its short version `-f`) for this (will be available in [v2.2.0](https://github.com/dotenv-linter/dotenv-linter/issues/238)):
+
+```shell script
+$ dotenv-linter -f
+Fixed warnings:
+.env:3 LowercaseKey: The foo key should be in uppercase
+
+Unfixed warnings:
+.env:2 DuplicatedKey: The BAR key is duplicated
+```
diff --git a/src/lib.rs b/src/lib.rs
index a252002..90239cc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,7 +11,7 @@
 pub use checks::available_check_names;
 
 #[allow(clippy::redundant_closure)]
-pub fn run(args: clap::ArgMatches, current_dir: &PathBuf) -> Result<Vec<Warning>, Box<dyn Error>> {
+pub fn run(args: &clap::ArgMatches, current_dir: &PathBuf) -> Result<Vec<Warning>, Box<dyn Error>> {
     let mut file_paths: Vec<PathBuf> = Vec::new();
     let mut skip_checks: Vec<&str> = Vec::new();
     let mut excluded_paths: Vec<PathBuf> = Vec::new();
diff --git a/src/main.rs b/src/main.rs
index e218698..12e276d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,7 +16,7 @@ fn main() -> Result<(), Box<dyn Error>> {
 
     let is_fix = args.is_present("fix");
 
-    let warnings = dotenv_linter::run(args, &current_dir)?;
+    let warnings = dotenv_linter::run(&args, &current_dir)?;
 
     if warnings.is_empty() {
         process::exit(0);
@@ -42,11 +42,25 @@ fn main() -> Result<(), Box<dyn Error>> {
         }
     } else {
         warnings.iter().for_each(|w| println!("{}", w));
+
+        if !args.is_present("quiet") {
+            print_total(warnings.len());
+        }
     }
 
     process::exit(1);
 }
 
+fn print_total(total: usize) {
+    let mut problems = String::from("problem");
+
+    if total > 1 {
+        problems += "s";
+    }
+
+    println!("\n{}", format!("Found {} {}", total, problems));
+}
+
 fn get_args(current_dir: &OsStr) -> clap::ArgMatches {
     clap::App::new(env!("CARGO_PKG_NAME"))
         .about(env!("CARGO_PKG_DESCRIPTION"))
@@ -96,5 +110,11 @@ fn get_args(current_dir: &OsStr) -> clap::ArgMatches {
                 .long("fix")
                 .help("Automatically fixes warnings if possible"),
         )
+        .arg(
+            Arg::with_name("quiet")
+                .short("q")
+                .long("quiet")
+                .help("Don't display additional information"),
+        )
         .get_matches()
 }


Test patch:
diff --git a/tests/args/current_dir.rs b/tests/args/current_dir.rs
index e640693..9df4862 100644
--- a/tests/args/current_dir.rs
+++ b/tests/args/current_dir.rs
@@ -12,10 +12,12 @@ fn checks_current_dir() {
     let testdir = TestDir::new();
     let testfile = testdir.create_testfile(".env", "FOO\n");
 
-    testdir.test_command_fail(format!(
-        "{}:1 KeyWithoutValue: The FOO key should be with a value or have an equal sign\n",
-        testfile.shortname_as_str()
-    ));
+    testdir.test_command_fail(
+        format!(
+            "{}:1 KeyWithoutValue: The FOO key should be with a value or have an equal sign\n\nFound 1 problem\n",
+            testfile.shortname_as_str()
+        )
+    );
 }
 
 #[test]
@@ -25,7 +27,7 @@ fn checks_current_dir_with_dot_arg() {
 
     let args = &["."];
     let expected_output = format!(
-        "{}:1 LowercaseKey: The foo key should be in uppercase\n",
+        "{}:1 LowercaseKey: The foo key should be in uppercase\n\nFound 1 problem\n",
         testfile.shortname_as_str(),
     );
 
diff --git a/tests/args/specific_path.rs b/tests/args/specific_path.rs
index f7ae22d..595208f 100644
--- a/tests/args/specific_path.rs
+++ b/tests/args/specific_path.rs
@@ -11,7 +11,7 @@ fn checks_one_specific_path() {
 
     let args = &[subdir.as_str()];
     let expected_output = format!(
-        "{}:1 LeadingCharacter: Invalid leading character detected\n",
+        "{}:1 LeadingCharacter: Invalid leading character detected\n\nFound 1 problem\n",
         Path::new(&testdir.relative_path(&subdir))
             .join(testfile_2.shortname_as_str())
             .to_str()
@@ -34,7 +34,7 @@ fn checks_two_specific_paths() {
 
     let args = &[subdir_1.as_str(), subdir_2.as_str()];
     let expected_output = format!(
-        "{}:1 LeadingCharacter: Invalid leading character detected\n{}:1 LeadingCharacter: Invalid leading character detected\n",
+        "{}:1 LeadingCharacter: Invalid leading character detected\n{}:1 LeadingCharacter: Invalid leading character detected\n\nFound 2 problems\n",
         Path::new(&testdir.relative_path(&subdir_1))
             .join(testfile_2.shortname_as_str())
             .to_str().expect("multi-platform path to test .env file"),
@@ -54,7 +54,7 @@ fn checks_one_specific_file() {
 
     let args = &[testfile_2.as_str()];
     let expected_output = format!(
-        "{}:1 SpaceCharacter: The line has spaces around equal sign\n",
+        "{}:1 SpaceCharacter: The line has spaces around equal sign\n\nFound 1 problem\n",
         testfile_2.shortname_as_str()
     );
 
@@ -72,7 +72,7 @@ fn checks_two_specific_files() {
 
     let args = &[testfile_2.as_str(), testfile_3.as_str()];
     let expected_output = format!(
-        "{}:2 DuplicatedKey: The FOO key is duplicated\n{}:1 SpaceCharacter: The line has spaces around equal sign\n",
+        "{}:2 DuplicatedKey: The FOO key is duplicated\n{}:1 SpaceCharacter: The line has spaces around equal sign\n\nFound 2 problems\n",
         Path::new(&testdir.relative_path(&subdir))
             .join(testfile_3.shortname_as_str())
             .to_str().expect("multi-platform path to test .env file"),
@@ -93,7 +93,7 @@ fn checks_one_specific_file_and_one_path() {
 
     let args = &[testfile_2.as_str(), subdir.as_str()];
     let expected_output = format!(
-        "{}:2 UnorderedKey: The BAR key should go before the FOO key\n{}:2 DuplicatedKey: The FOO key is duplicated\n",
+        "{}:2 UnorderedKey: The BAR key should go before the FOO key\n{}:2 DuplicatedKey: The FOO key is duplicated\n\nFound 2 problems\n",
         testfile_2.shortname_as_str(),
         Path::new(&testdir.relative_path(&subdir))
             .join(testfile_3.shortname_as_str())
@@ -111,7 +111,7 @@ fn checks_one_specific_file_twice() {
 
     let args = &[testfile_2.as_str(), testfile_2.as_str()];
     let expected_output = format!(
-        "{}:1 LeadingCharacter: Invalid leading character detected\n",
+        "{}:1 LeadingCharacter: Invalid leading character detected\n\nFound 1 problem\n",
         testfile_2.shortname_as_str()
     );
 
diff --git a/tests/checks/ending_blank_line.rs b/tests/checks/ending_blank_line.rs
index a1ca33c..c097bc0 100644
--- a/tests/checks/ending_blank_line.rs
+++ b/tests/checks/ending_blank_line.rs
@@ -32,7 +32,7 @@ fn incorrect_files() {
         let testfile = testdir.create_testfile(".env", content);
         let args = &[testfile.as_str()];
         let expected_output = format!(
-            "{}:{} EndingBlankLine: No blank line at the end of the file\n",
+            "{}:{} EndingBlankLine: No blank line at the end of the file\n\nFound 1 problem\n",
             testfile.shortname_as_str(),
             expected_line_numbers[i]
         );
diff --git a/tests/checks/extra_blank_line.rs b/tests/checks/extra_blank_line.rs
index 6b3cdbc..e2efc75 100644
--- a/tests/checks/extra_blank_line.rs
+++ b/tests/checks/extra_blank_line.rs
@@ -25,7 +25,7 @@ fn two_blank_lines_at_the_beginning() {
     let testfile = testdir.create_testfile(".env", content);
     let args = &[testfile.as_str()];
     let expected_output = format!(
-        "{}:{} ExtraBlankLine: Extra blank line detected\n",
+        "{}:{} ExtraBlankLine: Extra blank line detected\n\nFound 1 problem\n",
         testfile.shortname_as_str(),
         2
     );
@@ -41,7 +41,7 @@ fn two_blank_lines_in_the_middle() {
     let testfile = testdir.create_testfile(".env", content);
     let args = &[testfile.as_str()];
     let expected_output = format!(
-        "{}:{} ExtraBlankLine: Extra blank line detected\n",
+        "{}:{} ExtraBlankLine: Extra blank line detected\n\nFound 1 problem\n",
         testfile.shortname_as_str(),
         4
     );
@@ -57,7 +57,7 @@ fn two_blank_lines_at_the_end() {
     let testfile = testdir.create_testfile(".env", content);
     let args = &[testfile.as_str()];
     let expected_output = format!(
-        "{}:{} ExtraBlankLine: Extra blank line detected\n",
+        "{}:{} ExtraBlankLine: Extra blank line detected\n\nFound 1 problem\n",
         testfile.shortname_as_str(),
         5
     );
diff --git a/tests/cli.rs b/tests/cli.rs
index 820181c..b1f82bb 100644
--- a/tests/cli.rs
+++ b/tests/cli.rs
@@ -2,4 +2,5 @@
 mod checks;
 mod common;
 mod fixes;
+mod flags;
 mod options;
diff --git a/tests/flags/mod.rs b/tests/flags/mod.rs
new file mode 100644
index 0000000..2420ec8
--- /dev/null
+++ b/tests/flags/mod.rs
@@ -0,0 +1,2 @@
+mod quiet;
+mod recursive;
diff --git a/tests/flags/quiet.rs b/tests/flags/quiet.rs
new file mode 100644
index 0000000..02dcfe3
--- /dev/null
+++ b/tests/flags/quiet.rs
@@ -0,0 +1,15 @@
+use crate::common::TestDir;
+
+#[test]
+fn output_without_total() {
+    let test_dir = TestDir::new();
+    let testfile_to_check = test_dir.create_testfile(".env", " BAR='Baz'\n");
+
+    let args = &["--quiet"];
+    let expected_output = format!(
+        "{a}:1 LeadingCharacter: Invalid leading character detected\n{a}:1 QuoteCharacter: The value is wrapped in quotes\n",
+        a=testfile_to_check.shortname_as_str()
+    );
+
+    test_dir.test_command_fail_with_args(args, expected_output);
+}
diff --git a/tests/options/recursive.rs b/tests/flags/recursive.rs
similarity index 97%
rename from tests/options/recursive.rs
rename to tests/flags/recursive.rs
index 7043583..7357536 100644
--- a/tests/options/recursive.rs
+++ b/tests/flags/recursive.rs
@@ -10,7 +10,7 @@ fn checks_one_in_subdir() {
 
     let args = &["-r"];
     let expected_output = format!(
-        "{}:1 LeadingCharacter: Invalid leading character detected\n",
+        "{}:1 LeadingCharacter: Invalid leading character detected\n\nFound 1 problem\n",
         Path::new(&test_dir.relative_path(&test_subdir))
             .join(testfile_2.shortname_as_str())
             .to_str()
@@ -33,7 +33,7 @@ fn checks_files_in_deep_subdirs() {
 
     let args = &["--recursive"];
     let expected_output = format!(
-        "{}:2 UnorderedKey: The BAR key should go before the FOO key\n{}:1 EndingBlankLine: No blank line at the end of the file\n",
+        "{}:2 UnorderedKey: The BAR key should go before the FOO key\n{}:1 EndingBlankLine: No blank line at the end of the file\n\nFound 2 problems\n",
         Path::new(&test_dir.relative_path(&test_subdir_2))
             .join(testfile_2.shortname_as_str())
             .to_str()
@@ -71,7 +71,7 @@ fn checks_recursive_with_exclude_subdir() {
 
     let args = &["--exclude", testfile_to_exclude.as_str(), "--recursive"];
     let expected_output = format!(
-        "{}:2 UnorderedKey: The BAR key should go before the FOO key\n",
+        "{}:2 UnorderedKey: The BAR key should go before the FOO key\n\nFound 1 problem\n",
         Path::new(&test_dir.relative_path(&test_subdir_2))
             .join(testfile_2.shortname_as_str())
             .to_str()
diff --git a/tests/options/exclude.rs b/tests/options/exclude.rs
index 62d2591..a04313b 100644
--- a/tests/options/exclude.rs
+++ b/tests/options/exclude.rs
@@ -29,7 +29,7 @@ fn exclude_one_file_check_one_file() {
 
     let args = &["--exclude", testfile_to_exclude.as_str()];
     let expected_output = format!(
-        "{}:1 LeadingCharacter: Invalid leading character detected\n",
+        "{}:1 LeadingCharacter: Invalid leading character detected\n\nFound 1 problem\n",
         testfile_to_check.shortname_as_str()
     );
 
diff --git a/tests/options/mod.rs b/tests/options/mod.rs
index 52a2eb6..364d24f 100644
--- a/tests/options/mod.rs
+++ b/tests/options/mod.rs
@@ -1,2 +1,1 @@
 mod exclude;
-mod recursive;