Repository: dotenv-linter/dotenv-linter
Pull request #616 (2022-12-31 15:11:30)

chore(deps): bump `clap` from 3.1.10 to 4.0.32
<!--
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] Commit messages have been written in [Conventional Commits](https://www.conventionalcommits.org) format;
- [ ] Tests for the changes have been added (for bug fixes / features);
- [ ] Docs have been added / updated on the [dotenv-linter.github.io](https://github.com/dotenv-linter/dotenv-linter.github.io) (for bug fixes / features).

<!-- _NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open._ -->


codecov-commenter: # [Codecov](https://codecov.io/gh/dotenv-linter/dotenv-linter/pull/616?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter) Report
> Merging [#616](https://codecov.io/gh/dotenv-linter/dotenv-linter/pull/616?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter) (289cb29) into [master](https://codecov.io/gh/dotenv-linter/dotenv-linter/commit/785528c531324e3439ac6d3eefcd12c2b63a88f9?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter) (785528c) will **increase** coverage by `0.08%`.
> The diff coverage is `92.59%`.

```diff
@@            Coverage Diff             @@
##           master     #616      +/-   ##
==========================================
+ Coverage   98.91%   98.99%   +0.08%     
==========================================
  Files          43       43              
  Lines        2768     2793      +25     
==========================================
+ Hits         2738     2765      +27     
+ Misses         30       28       -2     
```


| [Impacted Files](https://codecov.io/gh/dotenv-linter/dotenv-linter/pull/616?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter) | Coverage Δ | |
|---|---|---|
| [src/cli.rs](https://codecov.io/gh/dotenv-linter/dotenv-linter/pull/616/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter#diff-c3JjL2NsaS5ycw==) | `94.04% <90.90%> (-5.96%)` | :arrow_down: |
| [src/lib.rs](https://codecov.io/gh/dotenv-linter/dotenv-linter/pull/616/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter#diff-c3JjL2xpYi5ycw==) | `99.03% <95.65%> (+0.54%)` | :arrow_up: |
| [src/main.rs](https://codecov.io/gh/dotenv-linter/dotenv-linter/pull/616/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter#diff-c3JjL21haW4ucnM=) | `100.00% <100.00%> (+20.68%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotenv-linter)


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5aeaf33..09e65c3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -67,7 +67,7 @@ jobs:
           mkdir -p $HOME/bin
           sh "${GITHUB_WORKSPACE}/install.sh" -b $HOME/bin
       - name: Verify successful installation
-        run: $HOME/bin/dotenv-linter -v
+        run: $HOME/bin/dotenv-linter --version
 
   install_specific_versions:
     strategy:
@@ -82,7 +82,7 @@ jobs:
           mkdir -p $HOME/bin
           sh "${GITHUB_WORKSPACE}/install.sh" -b $HOME/bin v${{ matrix.version }}
       - name: Verify successful installation
-        run: test "$($HOME/bin/dotenv-linter -v)" = "dotenv-linter ${{ matrix.version }}"
+        run: test "$($HOME/bin/dotenv-linter --version)" = "dotenv-linter ${{ matrix.version }}"
 
   install_specific_versions_wrong_input:
     strategy:
@@ -126,7 +126,7 @@ jobs:
           sh "${GITHUB_WORKSPACE}/install.sh" -b $HOME/bin
       - name: Verify successful installation
         shell: bash
-        run: $HOME/bin/dotenv-linter.exe -v
+        run: $HOME/bin/dotenv-linter.exe --version
 
   windows_install_specific_versions:
     strategy:
@@ -142,7 +142,7 @@ jobs:
           sh "${GITHUB_WORKSPACE}/install.sh" -b $HOME/bin v${{ matrix.version }}
       - name: Verify successful installation
         shell: bash # it uses Git Bash, i.e. MinGW
-        run: test "$($HOME/bin/dotenv-linter -v)" = "dotenv-linter ${{ matrix.version }}"
+        run: test "$($HOME/bin/dotenv-linter --version)" = "dotenv-linter ${{ matrix.version }}"
 
   windows_install_specific_versions_wrong_input:
     strategy:
@@ -175,7 +175,7 @@ jobs:
           mkdir -p $HOME/bin
           sh "${GITHUB_WORKSPACE}/install.sh" -b $HOME/bin
       - name: Verify successful installation
-        run: $HOME/bin/dotenv-linter -v
+        run: $HOME/bin/dotenv-linter --version
 
   ###################
   ### Docker jobs ###
diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml
index 4b778e6..3468d0a 100644
--- a/.github/workflows/linters.yml
+++ b/.github/workflows/linters.yml
@@ -9,6 +9,8 @@ jobs:
       - uses: reviewdog/action-misspell@v1
         with:
           locale: "US"
+          fail_on_error: true
+          reporter: github-pr-review
 
   yamllint:
     runs-on: ubuntu-latest
@@ -16,9 +18,8 @@ jobs:
       - uses: actions/checkout@v3
       - uses: reviewdog/action-yamllint@v1
         with:
-          github_token: ${{ secrets.github_token }}
-          reporter: github-pr-review
           fail_on_error: true
+          reporter: github-pr-review
           yamllint_flags: '-d "{extends: default, rules: {truthy: disable}}" .'
 
   shellcheck:
@@ -27,9 +28,9 @@ jobs:
       - uses: actions/checkout@v3
       - uses: reviewdog/action-shellcheck@v1
         with:
-          github_token: ${{ secrets.github_token }}
-          fail_on_error: true
           exclude: "./.git/*"
+          fail_on_error: true
+          reporter: github-pr-review
 
   commitlint:
     runs-on: ubuntu-latest
@@ -45,7 +46,6 @@ jobs:
       - uses: actions/checkout@v3
       - uses: reviewdog/action-hadolint@v1
         with:
-          github_token: ${{ secrets.github_token }}
           fail_on_error: true
           reporter: github-pr-review
 
diff --git a/Cargo.lock b/Cargo.lock
index af36a6c..572fc7f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -34,7 +34,7 @@ version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
  "libc",
  "winapi",
 ]
@@ -127,24 +127,44 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "3.1.10"
+version = "3.2.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3124f3f75ce09e22d1410043e1e24f2ecc44fad3afe4f08408f1f7663d68da2b"
+checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
 dependencies = [
- "atty",
  "bitflags",
- "clap_lex",
+ "clap_lex 0.2.4",
  "indexmap",
+ "textwrap",
+]
+
+[[package]]
+name = "clap"
+version = "4.0.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
+dependencies = [
+ "bitflags",
+ "clap_lex 0.3.0",
+ "is-terminal",
+ "once_cell",
  "strsim",
  "termcolor",
- "textwrap",
 ]
 
 [[package]]
 name = "clap_lex"
-version = "0.1.1"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
 dependencies = [
  "os_str_bytes",
 ]
@@ -179,7 +199,7 @@ dependencies = [
  "atty",
  "cast",
  "ciborium",
- "clap",
+ "clap 3.2.23",
  "criterion-plot",
  "itertools",
  "lazy_static",
@@ -286,7 +306,7 @@ name = "dotenv-linter"
 version = "3.3.0"
 dependencies = [
  "assert_cmd",
- "clap",
+ "clap 4.0.32",
  "colored",
  "criterion",
  "dunce",
@@ -307,6 +327,27 @@ version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 
+[[package]]
+name = "errno"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
 [[package]]
 name = "fastrand"
 version = "1.7.0"
@@ -391,6 +432,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "hermit-abi"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "idna"
 version = "0.2.3"
@@ -421,6 +471,28 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "io-lifetimes"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
+dependencies = [
+ "hermit-abi 0.2.6",
+ "io-lifetimes",
+ "rustix",
+ "windows-sys",
+]
+
 [[package]]
 name = "itertools"
 version = "0.10.3"
@@ -453,9 +525,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.112"
+version = "0.2.139"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
+checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
 
 [[package]]
 name = "log"
@@ -512,15 +590,15 @@ version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
  "libc",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.10.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
 
 [[package]]
 name = "oorandom"
@@ -702,6 +780,20 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "rustix"
+version = "0.36.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
 [[package]]
 name = "rustls"
 version = "0.20.2"
@@ -836,9 +928,9 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16"
 
 [[package]]
 name = "textwrap"
-version = "0.15.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
+checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
 
 [[package]]
 name = "thiserror"
@@ -1095,3 +1187,60 @@ name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
diff --git a/Cargo.toml b/Cargo.toml
index 15e320f..cc0656b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "dotenv-linter"
 version = "3.3.0" # managed by release.sh
-authors = ["Mikhail Grachev <work@mgrachev.com>"]
+authors = ["Mikhail Grachev <work@mgrachev.com>", "dotenv-linter core team & contributors"]
 categories = ["command-line-utilities"]
 edition = "2021"
 homepage = "https://dotenv-linter.github.io"
@@ -13,7 +13,7 @@ repository = "https://github.com/dotenv-linter/dotenv-linter"
 description = "Lightning-fast linter for .env files"
 
 [dependencies]
-clap = "3.1.10"
+clap = { version = "4.0.32", features = ["cargo"] }
 colored = "2.0.0"
 
 [dependencies.update-informer]
diff --git a/Dockerfile b/Dockerfile
index ef3b0a8..e764233 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM messense/rust-musl-cross:x86_64-musl as builder
+FROM messense/rust-musl-cross:x86_64-musl AS builder
 
 WORKDIR /
 
diff --git a/benches/check.rs b/benches/check.rs
index f92e120..52d889d 100644
--- a/benches/check.rs
+++ b/benches/check.rs
@@ -10,7 +10,7 @@ pub fn check_benchmark(c: &mut Criterion) {
     let path = temp.into_path();
 
     let current_dir = env::current_dir().expect("get current dir");
-    let app = dotenv_linter::cli::new(current_dir.as_os_str());
+    let app = dotenv_linter::cli::command();
     let matches = app.get_matches_from(vec!["dotenv-linter", path.to_str().expect("path to str")]);
 
     fs::copy("benches/fixtures/simple.env", path.join(".env")).expect("copy .env file");
diff --git a/benches/compare.rs b/benches/compare.rs
index e466fa2..da8e616 100644
--- a/benches/compare.rs
+++ b/benches/compare.rs
@@ -10,7 +10,7 @@ pub fn compare_benchmark(c: &mut Criterion) {
     let path = temp.into_path();
 
     let current_dir = env::current_dir().expect("get current dir");
-    let app = dotenv_linter::cli::new(path.as_os_str());
+    let app = dotenv_linter::cli::command();
     let matches = app.get_matches_from(vec![
         "dotenv-linter",
         "compare",
diff --git a/benches/fix.rs b/benches/fix.rs
index 4409921..f87226d 100644
--- a/benches/fix.rs
+++ b/benches/fix.rs
@@ -32,7 +32,7 @@ fn generate_arg_matches(app: &Command, with_backup: bool) -> ArgMatches {
 /// Runs the Fix Benchmark
 pub fn fix_benchmark(c: &mut Criterion) {
     let current_dir = env::current_dir().expect("get current dir");
-    let app = dotenv_linter::cli::new(current_dir.as_os_str());
+    let app = dotenv_linter::cli::command();
     c.bench_function("dotenv_linter fix", |b| {
         // Disable output to STDOUT
         #[cfg(not(windows))]
@@ -48,7 +48,7 @@ pub fn fix_benchmark(c: &mut Criterion) {
 /// Runs the fix Benchmark with Backup
 pub fn fix_benchmark_with_backup(c: &mut Criterion) {
     let current_dir = env::current_dir().expect("get current dir");
-    let app = dotenv_linter::cli::new(current_dir.as_os_str());
+    let app = dotenv_linter::cli::command();
     c.bench_function("dotenv_linter fix with backup", |b| {
         // Disable output to STDOUT
         #[cfg(not(windows))]
diff --git a/dprint.json b/dprint.json
index c07c34b..d5205e2 100644
--- a/dprint.json
+++ b/dprint.json
@@ -6,11 +6,12 @@
   },
   "toml": {
   },
-  "includes": ["**/*.{json,md,toml}"],
+  "includes": ["**/*.{json,md,toml}", "Dockerfile"],
   "excludes": ["target/"],
   "plugins": [
     "https://plugins.dprint.dev/json-0.15.0.wasm",
     "https://plugins.dprint.dev/markdown-0.13.0.wasm",
-    "https://plugins.dprint.dev/toml-0.5.4.wasm"
+    "https://plugins.dprint.dev/toml-0.5.4.wasm",
+    "https://plugins.dprint.dev/dockerfile-0.3.0.wasm"
   ]
 }
diff --git a/install.sh b/install.sh
index 1957d9f..8d4e951 100644
--- a/install.sh
+++ b/install.sh
@@ -34,6 +34,7 @@ parse_args() {
     case $1 in
         -h|--help)
             usage "$0"
+            # shellcheck disable=SC2317
             shift # past argument
             ;;
         -b|--bindir)
@@ -115,7 +116,7 @@ main() {
     install "${_temp_dir}/${_file_name}" "${BINDIR}/" || err "Failed to install"
     _exe_path=${BINDIR}/${_file_name}
 
-    println "Successfully installed $($_exe_path -v) to ${_exe_path}"
+    println "Successfully installed $($_exe_path --version) to ${_exe_path}"
 
     rm -rf "${_temp_dir}"
 
diff --git a/src/cli.rs b/src/cli.rs
index 8deece3..d36164a 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,29 +1,68 @@
-use clap::{Arg, Command};
-use std::ffi::OsStr;
-
-pub fn new(current_dir: &OsStr) -> Command {
-    Command::new(env!("CARGO_PKG_NAME"))
-        .about(env!("CARGO_PKG_DESCRIPTION"))
-        .author(env!("CARGO_PKG_AUTHORS"))
-        .version(env!("CARGO_PKG_VERSION"))
+use crate::Result;
+use clap::{command, Arg, ArgAction, Command};
+
+pub fn run() -> Result<i32> {
+    #[cfg(windows)]
+    colored::control::set_virtual_terminal(true).ok();
+
+    let current_dir = std::env::current_dir()?;
+    let args = command().get_matches();
+
+    disable_color_output(&args);
+
+    match args.subcommand() {
+        None => {
+            let total_warnings = crate::check(&args, &current_dir)?;
+
+            if total_warnings == 0 {
+                return Ok(0);
+            }
+        }
+        Some(("fix", fix_args)) => {
+            crate::fix(fix_args, &current_dir)?;
+
+            return Ok(0);
+        }
+        Some(("list", _)) => {
+            crate::available_check_names()
+                .iter()
+                .for_each(|name| println!("{}", name));
+
+            return Ok(0);
+        }
+        Some(("compare", compare_args)) => {
+            disable_color_output(compare_args);
+
+            let warnings = crate::compare(compare_args, &current_dir)?;
+            if warnings.is_empty() {
+                return Ok(0);
+            }
+        }
+        _ => {
+            eprintln!("unknown command");
+        }
+    }
+
+    Ok(1)
+}
+
+pub fn command() -> Command {
+    command!()
         .disable_help_subcommand(true)
-        .propagate_version(true)
-        .mut_arg("version", |a| a.short('v'))
-        .args(common_args(current_dir))
+        .args(common_args())
         .arg(not_check_updates_flag())
-        .subcommands([compare_command(), fix_command(current_dir), list_command()])
+        .subcommands([compare_command(), fix_command(), list_command()])
 }
 
-fn compare_command<'a>() -> Command<'a> {
+fn compare_command() -> Command {
     Command::new("compare")
         .visible_alias("c")
         .args(&vec![
             Arg::new("input")
                 .help("Files to compare")
-                .multiple_occurrences(true)
-                .multiple_values(true)
-                .min_values(2)
-                .required(true),
+                .action(ArgAction::Append)
+                .required(true)
+                .num_args(2..),
             no_color_flag(),
             quiet_flag(),
         ])
@@ -31,86 +70,92 @@ fn compare_command<'a>() -> Command<'a> {
         .override_usage("dotenv-linter compare [OPTIONS] <input>...")
 }
 
-fn fix_command(current_dir: &OsStr) -> Command {
+fn fix_command() -> Command {
     Command::new("fix")
         .visible_alias("f")
-        .args(common_args(current_dir))
+        .args(common_args())
         .arg(
             Arg::new("no-backup")
                 .long("no-backup")
-                .help("Prevents backing up .env files"),
+                .help("Prevents backing up .env files")
+                .action(ArgAction::SetTrue),
         )
         .override_usage("dotenv-linter fix [OPTIONS] <input>...")
         .about("Automatically fixes warnings")
 }
 
-fn list_command<'a>() -> Command<'a> {
+fn list_command() -> Command {
     Command::new("list")
         .visible_alias("l")
         .override_usage("dotenv-linter list")
         .about("Shows list of available checks")
 }
 
-fn common_args(current_dir: &OsStr) -> Vec<Arg> {
+fn common_args() -> Vec<Arg> {
     vec![
         Arg::new("input")
             .help("files or paths")
             .index(1)
-            .default_value_os(current_dir)
-            .multiple_occurrences(true)
-            .multiple_values(true),
+            .action(ArgAction::Append)
+            .num_args(0..),
         Arg::new("exclude")
             .short('e')
             .long("exclude")
             .value_name("FILE_NAME")
             .help("Excludes files from check")
-            .multiple_occurrences(true)
-            .multiple_values(true)
-            .takes_value(true),
+            .action(ArgAction::Append)
+            .num_args(0..),
         Arg::new("skip")
             .short('s')
             .long("skip")
             .value_name("CHECK_NAME")
             .help("Skips checks")
-            .multiple_occurrences(true)
-            .multiple_values(true)
-            .takes_value(true),
+            .action(ArgAction::Append)
+            .num_args(0..),
         Arg::new("recursive")
             .short('r')
             .long("recursive")
-            .help("Recursively searches and checks .env files"),
+            .help("Recursively searches and checks .env files")
+            .action(ArgAction::SetTrue),
         no_color_flag(),
         quiet_flag(),
     ]
 }
 
-fn quiet_flag<'a>() -> Arg<'a> {
+fn quiet_flag() -> Arg {
     Arg::new("quiet")
         .short('q')
         .long("quiet")
         .help("Doesn't display additional information")
+        .action(ArgAction::SetTrue)
 }
 
-fn no_color_flag<'a>() -> Arg<'a> {
+fn no_color_flag() -> Arg {
     Arg::new("no-color")
         .long("no-color")
         .help("Turns off the colored output")
+        .action(ArgAction::SetTrue)
 }
 
-fn not_check_updates_flag<'a>() -> Arg<'a> {
+fn not_check_updates_flag() -> Arg {
     Arg::new("not-check-updates")
         .long("not-check-updates")
         .help("Doesn't check for updates")
+        .action(ArgAction::SetTrue)
+}
+
+fn disable_color_output(args: &clap::ArgMatches) {
+    if args.get_flag("no-color") {
+        colored::control::set_override(false);
+    }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
-    use std::env;
 
     #[test]
     fn verify_app() {
-        let current_dir = env::current_dir().expect("Failed to get current dir");
-        new(current_dir.as_os_str()).debug_assert();
+        command().debug_assert();
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 8fd440a..9378de2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,5 @@
 use crate::{common::*, quote_type::QuoteType};
-use clap::Values;
+use clap::parser::ValuesRef;
 use std::{
     collections::{BTreeMap, HashSet},
     path::{Path, PathBuf},
@@ -21,10 +21,10 @@ pub fn check(args: &clap::ArgMatches, current_dir: &Path) -> Result<usize> {
     let lines_map = get_lines(
         args,
         current_dir,
-        args.is_present("recursive"),
-        args.values_of("exclude"),
+        args.get_flag("recursive"),
+        args.get_many("exclude"),
     );
-    let output = CheckOutput::new(args.is_present("quiet"), lines_map.len());
+    let output = CheckOutput::new(args.get_flag("quiet"), lines_map.len());
 
     if lines_map.is_empty() {
         output.print_nothing_to_check();
@@ -36,9 +36,9 @@ pub fn check(args: &clap::ArgMatches, current_dir: &Path) -> Result<usize> {
     }
 
     let skip_checks: Vec<LintKind> = args
-        .values_of("skip")
+        .get_many::<String>("skip")
         .unwrap_or_default()
-        .filter_map(|check: &str| LintKind::from_str(check).ok())
+        .filter_map(|check| LintKind::from_str(check).ok())
         .collect();
 
     let warnings_count =
@@ -68,10 +68,10 @@ pub fn fix(args: &clap::ArgMatches, current_dir: &Path) -> Result<()> {
     let lines_map = get_lines(
         args,
         current_dir,
-        args.is_present("recursive"),
-        args.values_of("exclude"),
+        args.get_flag("recursive"),
+        args.get_many("exclude"),
     );
-    let output = FixOutput::new(args.is_present("quiet"), lines_map.len());
+    let output = FixOutput::new(args.get_flag("quiet"), lines_map.len());
 
     // Nothing to fix
     if lines_map.is_empty() {
@@ -80,9 +80,9 @@ pub fn fix(args: &clap::ArgMatches, current_dir: &Path) -> Result<()> {
     }
 
     let skip_checks: Vec<LintKind> = args
-        .values_of("skip")
+        .get_many::<String>("skip")
         .unwrap_or_default()
-        .filter_map(|check: &str| LintKind::from_str(check).ok())
+        .filter_map(|check| LintKind::from_str(check).ok())
         .collect();
 
     for (index, (fe, strings)) in lines_map.into_iter().enumerate() {
@@ -98,7 +98,7 @@ pub fn fix(args: &clap::ArgMatches, current_dir: &Path) -> Result<()> {
             output.print_not_all_warnings_fixed();
         }
         if fixes_done > 0 {
-            let should_backup = !args.is_present("no-backup");
+            let should_backup = !args.get_flag("no-backup");
             // create backup copy unless user specifies not to
             if should_backup {
                 let backup_file = fs_utils::backup_file(&fe)?;
@@ -121,7 +121,7 @@ pub fn fix(args: &clap::ArgMatches, current_dir: &Path) -> Result<()> {
 pub fn compare(args: &clap::ArgMatches, current_dir: &Path) -> Result<Vec<CompareWarning>> {
     let mut all_keys: HashSet<String> = HashSet::new();
     let lines_map = get_lines(args, current_dir, false, None);
-    let output = CompareOutput::new(args.is_present("quiet"));
+    let output = CompareOutput::new(args.get_flag("quiet"));
 
     let mut warnings: Vec<CompareWarning> = Vec::new();
     let mut files_to_compare: Vec<CompareFileType> = Vec::new();
@@ -180,9 +180,9 @@ fn get_lines(
     args: &clap::ArgMatches,
     current_dir: &Path,
     is_recursive: bool,
-    exclude: Option<Values>,
+    exclude: Option<ValuesRef<String>>,
 ) -> BTreeMap<FileEntry, Vec<String>> {
-    let file_paths: Vec<PathBuf> = get_needed_file_paths(args, is_recursive, exclude);
+    let file_paths: Vec<PathBuf> = get_needed_file_paths(args, current_dir, is_recursive, exclude);
 
     file_paths
         .iter()
@@ -195,8 +195,9 @@ fn get_lines(
 /// Getting a list of all files for checking/fixing without custom exclusion files
 fn get_needed_file_paths(
     args: &clap::ArgMatches,
+    current_dir: &Path,
     is_recursive: bool,
-    exclude: Option<Values>,
+    exclude: Option<ValuesRef<String>>,
 ) -> Vec<PathBuf> {
     let mut file_paths: Vec<PathBuf> = Vec::new();
     let mut excluded_paths: Vec<PathBuf> = Vec::new();
@@ -207,9 +208,26 @@ fn get_needed_file_paths(
             .collect();
     }
 
-    if let Some(inputs) = args.values_of("input") {
+    match args.get_many::<String>("input") {
+        Some(inputs) => {
+            let input_paths = inputs
+                .filter_map(|s| fs_utils::canonicalize(s).ok())
+                .collect();
+
+            file_paths.extend(get_file_paths(input_paths, &excluded_paths, is_recursive));
+        }
+        None => {
+            file_paths.extend(get_file_paths(
+                vec![current_dir.to_path_buf()],
+                &excluded_paths,
+                is_recursive,
+            ));
+        }
+    }
+
+    if let Some(inputs) = args.get_many("input") {
         let input_paths = inputs
-            .filter_map(|s| fs_utils::canonicalize(s).ok())
+            .filter_map(|s: &String| fs_utils::canonicalize(s).ok())
             .collect();
 
         file_paths.extend(get_file_paths(input_paths, &excluded_paths, is_recursive));
@@ -326,7 +344,7 @@ fn print_new_version_if_available(args: &clap::ArgMatches) {
     use colored::*;
     use update_informer::{registry, Check};
 
-    if args.is_present("not-check-updates") || args.is_present("quiet") {
+    if args.get_flag("not-check-updates") || args.get_flag("quiet") {
         return;
     }
 
diff --git a/src/main.rs b/src/main.rs
index fe4b364..ceba390 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,52 +1,6 @@
-use dotenv_linter::Result;
-use std::{env, process};
+use dotenv_linter::{cli, Result};
 
 fn main() -> Result<()> {
-    #[cfg(windows)]
-    colored::control::set_virtual_terminal(true).ok();
-
-    let current_dir = env::current_dir()?;
-    let args = dotenv_linter::cli::new(current_dir.as_os_str()).get_matches();
-
-    disable_color_output(&args);
-
-    match args.subcommand() {
-        None => {
-            let total_warnings = dotenv_linter::check(&args, &current_dir)?;
-
-            if total_warnings == 0 {
-                process::exit(0);
-            }
-        }
-        Some(("fix", fix_args)) => {
-            dotenv_linter::fix(fix_args, &current_dir)?;
-            process::exit(0);
-        }
-        Some(("list", _)) => {
-            dotenv_linter::available_check_names()
-                .iter()
-                .for_each(|name| println!("{}", name));
-
-            process::exit(0);
-        }
-        Some(("compare", compare_args)) => {
-            disable_color_output(compare_args);
-
-            let warnings = dotenv_linter::compare(compare_args, &current_dir)?;
-            if warnings.is_empty() {
-                process::exit(0);
-            }
-        }
-        _ => {
-            eprintln!("unknown command");
-        }
-    }
-
-    process::exit(1);
-}
-
-fn disable_color_output(args: &clap::ArgMatches) {
-    if args.is_present("no-color") {
-        colored::control::set_override(false);
-    }
+    let code = cli::run()?;
+    std::process::exit(code);
 }


Test patch:
diff --git a/tests/flags/version.rs b/tests/flags/version.rs
index 609b90e..0b1107a 100644
--- a/tests/flags/version.rs
+++ b/tests/flags/version.rs
@@ -5,5 +5,5 @@ fn short_version() {
     let testdir = TestDir::new();
     let expected = format!("{} {}\n", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
 
-    testdir.test_command_success_with_args(["-v"], expected);
+    testdir.test_command_success_with_args(["-V"], expected);
 }