Repository: lingui/js-lingui (ts)

Issue:
Run lingui extract for specified files
**Is your feature request related to a problem? Please describe.**
I am trying to run `lingui extract` in CI steps to warn developer if they forget to run `lingui extract`. However running `lingui extract` over the entire project takes ~10mins

**Describe the solution you'd like**
`lingui extract` should take an optional glob that narrow down the list of files the command run on

**Describe alternatives you've considered**
lingui v3 seems to include a watch option. Maybe this is related?

**Additional context**



Pull request:
feat: extract accepts files as cli option
Will close #510

I've adjusted also the help.ts function because when running `yarn extract src/ --verbose` was leading to confusion because params were passed also to `yarn compile` command.

On create-react-app example of Lingui projects results are really good:

### New version with files param:
`yarn extract src/ 1.47s user 0.26s system 111% cpu 1.709 total`

###  Actual code branch without files filter:
`yarn extract 4.19s user 0.33s system 135% cpu 3.345 total`

Patch:
diff --git a/docs/ref/cli.rst b/docs/ref/cli.rst
index b8a18b78..a0d359df 100644
--- a/docs/ref/cli.rst
+++ b/docs/ref/cli.rst
@@ -16,7 +16,8 @@ Install
    .. code-block:: shell
 
       npm install --save-dev @lingui/cli @babel/core
-      # yarn add --dev @lingui/cli @babel/core
+      # Or yarn
+      yarn add --dev @lingui/cli @babel/core
 
 2. Add following scripts to your ``package.json``:
 
@@ -43,7 +44,7 @@ Commands
 ``extract``
 -----------
 
-.. lingui-cli:: extract [--clean] [--overwrite] [--format <format>] [--locale <locale>] [--convert-from <format>] [--verbose]
+.. lingui-cli:: extract [files...] [--clean] [--overwrite] [--format <format>] [--locale <locale>] [--convert-from <format>] [--verbose]
 
 This command extracts messages from source files and creates a message catalog for
 each language using the following steps:
@@ -52,6 +53,29 @@ each language using the following steps:
 2. Merge them with existing catalogs in :conf:`localeDir` (if any)
 3. Write updated message catalogs to :conf:`localeDir`
 
+.. lingui-cli-option:: [files...]
+
+Filters source paths to only extract messages from passed files.
+For ex:
+
+   .. code-block:: shell
+
+      lingui extract src/components
+
+Will extract only messages from ``src/components/**/*`` files, you can also pass multiple paths.
+
+It's useful if you want to run extract command on files that are staged, using for example ``husky``, before commiting will extract messages from staged files:
+
+   .. code-block:: json
+
+      {
+         "husky": {
+            "hooks": {
+               "pre-commit": "lingui extract $(git diff --name-only --staged)"
+            }
+         }
+      }
+
 .. lingui-cli-option:: --clean
 
 Remove obsolete messages from catalogs. Message becomes obsolete
diff --git a/examples/create-react-app/package.json b/examples/create-react-app/package.json
index cdad6593..4f9f460f 100644
--- a/examples/create-react-app/package.json
+++ b/examples/create-react-app/package.json
@@ -3,7 +3,7 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
-    "@lingui/react": "^3.1.0",
+    "@lingui/react": "^3.2.3",
     "@testing-library/jest-dom": "^5.11.5",
     "@testing-library/react": "^11.1.0",
     "@testing-library/user-event": "^12.1.10",
@@ -40,8 +40,8 @@
     ]
   },
   "devDependencies": {
-    "@lingui/cli": "^3.1.0",
-    "@lingui/loader": "^3.1.0",
-    "@lingui/macro": "^3.1.0"
+    "@lingui/cli": "^3.2.3",
+    "@lingui/loader": "^3.2.3",
+    "@lingui/macro": "^3.2.3"
   }
 }
diff --git a/examples/create-react-app/yarn.lock b/examples/create-react-app/yarn.lock
index 7958d77d..e0a4535c 100644
--- a/examples/create-react-app/yarn.lock
+++ b/examples/create-react-app/yarn.lock
@@ -1408,28 +1408,28 @@
     "@types/yargs" "^15.0.0"
     chalk "^4.0.0"
 
-"@lingui/babel-plugin-extract-messages@3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.1.0.tgz#6c24e3082ef205bc0b1b056c112f1b52a3b7cc81"
-  integrity sha512-8wDae+HxpGrN/gsT+fLo+cTkzlE1V9hwMHLmjQ6uA26emyPtXQrJnltHi+gbDYFf/JJgvmVpo6HvqWvn9Kvo9Q==
+"@lingui/babel-plugin-extract-messages@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.2.3.tgz#59f861bb02edb7eb4d29d1d283a3351f98b4e4f4"
+  integrity sha512-F1N6cwjxSxKClUT4yfRnRtJ6lkUckrDx73RSbVL7OgrefQzZS9/RjnufULPV0kU9p1XDKfaBI1YHR4zQvdR+5A==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "3.1.0"
+    "@lingui/conf" "^3.2.3"
     mkdirp "^1.0.4"
 
-"@lingui/cli@3.1.0", "@lingui/cli@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-3.1.0.tgz#bf541403f2d05dd02d79d42568a4b80c4a57ed75"
-  integrity sha512-/zYl7N+uiAUGL1spWqyOuCdBK6sE7YGQVL93n7VAE+lKlLrrjbu0mEGT8DpzBixFqt2JrY1H9M5cpJ4uMAGt/A==
+"@lingui/cli@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-3.2.3.tgz#40b83512edb468fe3b61da00c3f8885d9946c104"
+  integrity sha512-fsbiKrO8CO5dWy3hDQ6a8w0/m82Elv3UZ+T/LPyLT0spSxEVsZbJgySmomy2u/tYEkOEhXipkvoGR8mueaF8rA==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/parser" "^7.11.5"
     "@babel/plugin-syntax-jsx" "^7.10.4"
     "@babel/runtime" "^7.11.2"
     "@babel/types" "^7.11.5"
-    "@lingui/babel-plugin-extract-messages" "3.1.0"
-    "@lingui/conf" "3.1.0"
+    "@lingui/babel-plugin-extract-messages" "^3.2.3"
+    "@lingui/conf" "^3.2.3"
     babel-plugin-macros "^2.8.0"
     bcp-47 "^1.0.7"
     chalk "^4.1.0"
@@ -1451,52 +1451,52 @@
     pseudolocale "^1.1.0"
     ramda "^0.27.1"
 
-"@lingui/conf@3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-3.1.0.tgz#953b71ceef9cf0a07091892a927b16b59577d42a"
-  integrity sha512-DhBGeOC4qY0tjVwTdwLr59YjqcRPfA7+Ehj346cJZXkfLylCb4TLKIhnGJbDF7lReNWDltECJCHxvPfotre6Vw==
+"@lingui/conf@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-3.2.3.tgz#ab3ac70eef8f2f219ce85d8b8516ecc128af477a"
+  integrity sha512-9Zfq/Z0vH9BucaXVbeIIoWDb7RsnqBizdHn9+PUzQx5AiudzBeKrW8gF0IGxFwugFoS5ho8qVLovYoDS2JSDYA==
   dependencies:
     "@babel/runtime" "^7.11.2"
     chalk "^4.1.0"
     cosmiconfig "^7.0.0"
     jest-validate "^26.5.2"
 
-"@lingui/core@3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/core/-/core-3.1.0.tgz#c8e185cee881ccc935ab9c2d363d620c006901f7"
-  integrity sha512-dKUcX2Swm8bjed6qIRYQ9xUv6Yq3kxzfKm+jtdLQCO3hlfq/w6Zt16EsAgeJZ92081ZhlJLNGy/dELEczajUBw==
+"@lingui/core@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/core/-/core-3.2.3.tgz#2eeba173d3a3a1cbe9f9de4ed57380d2dc45ecff"
+  integrity sha512-TiWk6LGjZ9sNVi7itiJDWUIB1Uyr8WKR/8M6RhQVTRnL+Yh3mElsVPjIRPH1he4ClkwaH6G5eDOfWiB67Csgbw==
   dependencies:
     "@babel/runtime" "^7.11.2"
     make-plural "^6.2.2"
     messageformat-parser "^4.1.3"
 
-"@lingui/loader@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/loader/-/loader-3.1.0.tgz#9a9124cd9e5b71c2361e5e446522b72ad8cde5bb"
-  integrity sha512-dUnLykFdLruV/5hjQREcLdoNA3aInddhLEp5fiAIGElxlfVPj77YZZzEJBBUJ/v7v+48AyPOOPmbcbhHfb1BsQ==
+"@lingui/loader@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/loader/-/loader-3.2.3.tgz#13468bc294da4d4f88d00e7bec3ebe2ef83b8d59"
+  integrity sha512-ylyvPeWjomCXZIZC8SZ0VAuhR62vt+jghYdkB0QQbxzgMkwZLTkaA1zGW7im0mjrI0Hwa4PgXCivS7K3krwxSw==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/cli" "3.1.0"
-    "@lingui/conf" "3.1.0"
+    "@lingui/cli" "^3.2.3"
+    "@lingui/conf" "^3.2.3"
     loader-utils "^2.0.0"
     ramda "^0.27.1"
 
-"@lingui/macro@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-3.1.0.tgz#ae98371964cf716f96b67b7207c9d00f4471e0f2"
-  integrity sha512-yE8FGLV0175wAh9nSNOFjtyYITHsA98IRFyMn/OqLbDDummdvahXQrQPtO8SQ/ecVJdh7LrZGmsYawCFVQ2XQg==
+"@lingui/macro@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-3.2.3.tgz#d054f9f6008b068a134d7bb3bfe87b3573c5d556"
+  integrity sha512-XcGUD8qQe8b351qGA/AyX+WKQWJu3T/r8wlXsttKoeFd7OXIitAw53L+OLc6xauM5xUssdaWo6BtOJnLw034gA==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "3.1.0"
+    "@lingui/conf" "^3.2.3"
     ramda "^0.27.1"
 
-"@lingui/react@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/react/-/react-3.1.0.tgz#ff650b03c3a29cb2576941032b916a63d3b2b2c2"
-  integrity sha512-a3eYTcV8V5fhF0k/BxAT2DQNHlY2UPRvZqeA3OkQvkREptExVeNzo3gfS0bdyOGvJIpILFFBIVtxUhvHSU+dmQ==
+"@lingui/react@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/react/-/react-3.2.3.tgz#8cf78a217d4a2314ab38c68521a6dd544f87b258"
+  integrity sha512-oPqy7LhJddBDvgDvfKikZh8sFP4uG1/NaDhIkHXVCwf+ONxuAwsDPvW47e/K5hQ60UX2LqGbbB7LuAFK5Klr1Q==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/core" "3.1.0"
+    "@lingui/core" "^3.2.3"
 
 "@nodelib/fs.scandir@2.1.3":
   version "2.1.3"
diff --git a/examples/js/package.json b/examples/js/package.json
index 1526aad4..68273bdd 100644
--- a/examples/js/package.json
+++ b/examples/js/package.json
@@ -12,13 +12,13 @@
     "pretest": "lingui compile --strict"
   },
   "dependencies": {
-    "@lingui/core": "3.0.0",
-    "@lingui/macro": "3.0.0"
+    "@lingui/core": "^3.2.3",
+    "@lingui/macro": "^3.2.3"
   },
   "devDependencies": {
     "@babel/core": "^7.12.3",
     "@babel/preset-env": "^7.12.1",
-    "@lingui/cli": "3.0.0",
+    "@lingui/cli": "^3.2.3",
     "babel-jest": "^26.6.1",
     "babel-plugin-macros": "^2.8.0",
     "jest": "^26.6.1"
diff --git a/examples/js/yarn.lock b/examples/js/yarn.lock
index bce9924e..1b75076d 100644
--- a/examples/js/yarn.lock
+++ b/examples/js/yarn.lock
@@ -1291,28 +1291,28 @@
     "@types/yargs" "^15.0.0"
     chalk "^4.0.0"
 
-"@lingui/babel-plugin-extract-messages@3.0.0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.0.0.tgz#5bc2c08ccde0ebbe736d5ee22cd0b61bc837f7f1"
-  integrity sha512-atjb6sQbDP8ZLZu5fJdAMK+CJWGs/hyn52JxZi3tPgirORFDAOa/FfDP5Sfnv+3wgEQzFA2igEmSKpyTuyZHBg==
+"@lingui/babel-plugin-extract-messages@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.2.3.tgz#59f861bb02edb7eb4d29d1d283a3351f98b4e4f4"
+  integrity sha512-F1N6cwjxSxKClUT4yfRnRtJ6lkUckrDx73RSbVL7OgrefQzZS9/RjnufULPV0kU9p1XDKfaBI1YHR4zQvdR+5A==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "3.0.0"
+    "@lingui/conf" "^3.2.3"
     mkdirp "^1.0.4"
 
-"@lingui/cli@3.0.0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-3.0.0.tgz#128ce8289d2fbc66cc6a122e1ccc76ff890b8ac7"
-  integrity sha512-ysega+gLQA46i6I9fkW1eQNhx2bYzRTaN0NfFtFxVu4WEIBP0+r+oHGTILys4zFjSj5v0iSJ/2/iroJKI11NeA==
+"@lingui/cli@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-3.2.3.tgz#40b83512edb468fe3b61da00c3f8885d9946c104"
+  integrity sha512-fsbiKrO8CO5dWy3hDQ6a8w0/m82Elv3UZ+T/LPyLT0spSxEVsZbJgySmomy2u/tYEkOEhXipkvoGR8mueaF8rA==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/parser" "^7.11.5"
     "@babel/plugin-syntax-jsx" "^7.10.4"
     "@babel/runtime" "^7.11.2"
     "@babel/types" "^7.11.5"
-    "@lingui/babel-plugin-extract-messages" "3.0.0"
-    "@lingui/conf" "3.0.0"
+    "@lingui/babel-plugin-extract-messages" "^3.2.3"
+    "@lingui/conf" "^3.2.3"
     babel-plugin-macros "^2.8.0"
     bcp-47 "^1.0.7"
     chalk "^4.1.0"
@@ -1334,32 +1334,32 @@
     pseudolocale "^1.1.0"
     ramda "^0.27.1"
 
-"@lingui/conf@3.0.0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-3.0.0.tgz#8a3ea64e7a7c43d12c20aa910d6aeb65911d889b"
-  integrity sha512-oPPU6hdyA2fMlQRB7GoYWApzR2tTXPqN8bGTo3ZFXBOgazAHYgIED/ZrnXEWTKRdGRtxMYkU+xDQ+6BLdgieug==
+"@lingui/conf@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-3.2.3.tgz#ab3ac70eef8f2f219ce85d8b8516ecc128af477a"
+  integrity sha512-9Zfq/Z0vH9BucaXVbeIIoWDb7RsnqBizdHn9+PUzQx5AiudzBeKrW8gF0IGxFwugFoS5ho8qVLovYoDS2JSDYA==
   dependencies:
     "@babel/runtime" "^7.11.2"
     chalk "^4.1.0"
     cosmiconfig "^7.0.0"
     jest-validate "^26.5.2"
 
-"@lingui/core@3.0.0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@lingui/core/-/core-3.0.0.tgz#5591658ea4edaf0e5fc359eef5b70fe292a22265"
-  integrity sha512-Jtwau0dV10SaL/mJmhR+h5Pyos3MTijWvNnPeIiaKfVtXskhopspuKjux0Q2BeDipmGXMxcF6JAuVJvTFxJ47w==
+"@lingui/core@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/core/-/core-3.2.3.tgz#2eeba173d3a3a1cbe9f9de4ed57380d2dc45ecff"
+  integrity sha512-TiWk6LGjZ9sNVi7itiJDWUIB1Uyr8WKR/8M6RhQVTRnL+Yh3mElsVPjIRPH1he4ClkwaH6G5eDOfWiB67Csgbw==
   dependencies:
     "@babel/runtime" "^7.11.2"
     make-plural "^6.2.2"
     messageformat-parser "^4.1.3"
 
-"@lingui/macro@3.0.0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-3.0.0.tgz#afdc4890251e38b657e7c1b4bb357e5a36bf6637"
-  integrity sha512-Gugk8u1tlFEsaQnfzMidDdsbq/OFs3VYZ8H8XfEvygyNtWMZgKjbe1bPpwHEf4+fS3YJHWg/0GfHwIfzbJMP5g==
+"@lingui/macro@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-3.2.3.tgz#d054f9f6008b068a134d7bb3bfe87b3573c5d556"
+  integrity sha512-XcGUD8qQe8b351qGA/AyX+WKQWJu3T/r8wlXsttKoeFd7OXIitAw53L+OLc6xauM5xUssdaWo6BtOJnLw034gA==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "3.0.0"
+    "@lingui/conf" "^3.2.3"
     ramda "^0.27.1"
 
 "@sinonjs/commons@^1.7.0":
diff --git a/examples/next-js/package.json b/examples/next-js/package.json
index 5332909c..053222cc 100644
--- a/examples/next-js/package.json
+++ b/examples/next-js/package.json
@@ -10,17 +10,17 @@
     "start": "next start"
   },
   "dependencies": {
-    "@lingui/core": "^3.1.0",
-    "@lingui/react": "^3.1.0",
+    "@lingui/core": "^3.2.3",
+    "@lingui/react": "^3.2.3",
     "classnames": "^2.2.6",
     "next": "10.0.1",
     "react": "17.0.1",
     "react-dom": "17.0.1"
   },
   "devDependencies": {
-    "@lingui/cli": "^3.1.0",
-    "@lingui/loader": "^3.1.0",
-    "@lingui/macro": "^3.1.0",
+    "@lingui/cli": "^3.2.3",
+    "@lingui/loader": "^3.2.3",
+    "@lingui/macro": "^3.2.3",
     "@types/react": "^16.9.56",
     "babel-plugin-macros": "^2.8.0",
     "typescript": "^4.0.5"
diff --git a/examples/next-js/yarn.lock b/examples/next-js/yarn.lock
index e629273b..60589d9f 100644
--- a/examples/next-js/yarn.lock
+++ b/examples/next-js/yarn.lock
@@ -1107,28 +1107,28 @@
     "@types/yargs" "^15.0.0"
     chalk "^4.0.0"
 
-"@lingui/babel-plugin-extract-messages@3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.1.0.tgz#6c24e3082ef205bc0b1b056c112f1b52a3b7cc81"
-  integrity sha512-8wDae+HxpGrN/gsT+fLo+cTkzlE1V9hwMHLmjQ6uA26emyPtXQrJnltHi+gbDYFf/JJgvmVpo6HvqWvn9Kvo9Q==
+"@lingui/babel-plugin-extract-messages@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.2.3.tgz#59f861bb02edb7eb4d29d1d283a3351f98b4e4f4"
+  integrity sha512-F1N6cwjxSxKClUT4yfRnRtJ6lkUckrDx73RSbVL7OgrefQzZS9/RjnufULPV0kU9p1XDKfaBI1YHR4zQvdR+5A==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "3.1.0"
+    "@lingui/conf" "^3.2.3"
     mkdirp "^1.0.4"
 
-"@lingui/cli@3.1.0", "@lingui/cli@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-3.1.0.tgz#bf541403f2d05dd02d79d42568a4b80c4a57ed75"
-  integrity sha512-/zYl7N+uiAUGL1spWqyOuCdBK6sE7YGQVL93n7VAE+lKlLrrjbu0mEGT8DpzBixFqt2JrY1H9M5cpJ4uMAGt/A==
+"@lingui/cli@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-3.2.3.tgz#40b83512edb468fe3b61da00c3f8885d9946c104"
+  integrity sha512-fsbiKrO8CO5dWy3hDQ6a8w0/m82Elv3UZ+T/LPyLT0spSxEVsZbJgySmomy2u/tYEkOEhXipkvoGR8mueaF8rA==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/parser" "^7.11.5"
     "@babel/plugin-syntax-jsx" "^7.10.4"
     "@babel/runtime" "^7.11.2"
     "@babel/types" "^7.11.5"
-    "@lingui/babel-plugin-extract-messages" "3.1.0"
-    "@lingui/conf" "3.1.0"
+    "@lingui/babel-plugin-extract-messages" "^3.2.3"
+    "@lingui/conf" "^3.2.3"
     babel-plugin-macros "^2.8.0"
     bcp-47 "^1.0.7"
     chalk "^4.1.0"
@@ -1150,52 +1150,52 @@
     pseudolocale "^1.1.0"
     ramda "^0.27.1"
 
-"@lingui/conf@3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-3.1.0.tgz#953b71ceef9cf0a07091892a927b16b59577d42a"
-  integrity sha512-DhBGeOC4qY0tjVwTdwLr59YjqcRPfA7+Ehj346cJZXkfLylCb4TLKIhnGJbDF7lReNWDltECJCHxvPfotre6Vw==
+"@lingui/conf@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-3.2.3.tgz#ab3ac70eef8f2f219ce85d8b8516ecc128af477a"
+  integrity sha512-9Zfq/Z0vH9BucaXVbeIIoWDb7RsnqBizdHn9+PUzQx5AiudzBeKrW8gF0IGxFwugFoS5ho8qVLovYoDS2JSDYA==
   dependencies:
     "@babel/runtime" "^7.11.2"
     chalk "^4.1.0"
     cosmiconfig "^7.0.0"
     jest-validate "^26.5.2"
 
-"@lingui/core@3.1.0", "@lingui/core@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/core/-/core-3.1.0.tgz#c8e185cee881ccc935ab9c2d363d620c006901f7"
-  integrity sha512-dKUcX2Swm8bjed6qIRYQ9xUv6Yq3kxzfKm+jtdLQCO3hlfq/w6Zt16EsAgeJZ92081ZhlJLNGy/dELEczajUBw==
+"@lingui/core@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/core/-/core-3.2.3.tgz#2eeba173d3a3a1cbe9f9de4ed57380d2dc45ecff"
+  integrity sha512-TiWk6LGjZ9sNVi7itiJDWUIB1Uyr8WKR/8M6RhQVTRnL+Yh3mElsVPjIRPH1he4ClkwaH6G5eDOfWiB67Csgbw==
   dependencies:
     "@babel/runtime" "^7.11.2"
     make-plural "^6.2.2"
     messageformat-parser "^4.1.3"
 
-"@lingui/loader@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/loader/-/loader-3.1.0.tgz#9a9124cd9e5b71c2361e5e446522b72ad8cde5bb"
-  integrity sha512-dUnLykFdLruV/5hjQREcLdoNA3aInddhLEp5fiAIGElxlfVPj77YZZzEJBBUJ/v7v+48AyPOOPmbcbhHfb1BsQ==
+"@lingui/loader@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/loader/-/loader-3.2.3.tgz#13468bc294da4d4f88d00e7bec3ebe2ef83b8d59"
+  integrity sha512-ylyvPeWjomCXZIZC8SZ0VAuhR62vt+jghYdkB0QQbxzgMkwZLTkaA1zGW7im0mjrI0Hwa4PgXCivS7K3krwxSw==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/cli" "3.1.0"
-    "@lingui/conf" "3.1.0"
+    "@lingui/cli" "^3.2.3"
+    "@lingui/conf" "^3.2.3"
     loader-utils "^2.0.0"
     ramda "^0.27.1"
 
-"@lingui/macro@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-3.1.0.tgz#ae98371964cf716f96b67b7207c9d00f4471e0f2"
-  integrity sha512-yE8FGLV0175wAh9nSNOFjtyYITHsA98IRFyMn/OqLbDDummdvahXQrQPtO8SQ/ecVJdh7LrZGmsYawCFVQ2XQg==
+"@lingui/macro@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-3.2.3.tgz#d054f9f6008b068a134d7bb3bfe87b3573c5d556"
+  integrity sha512-XcGUD8qQe8b351qGA/AyX+WKQWJu3T/r8wlXsttKoeFd7OXIitAw53L+OLc6xauM5xUssdaWo6BtOJnLw034gA==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "3.1.0"
+    "@lingui/conf" "^3.2.3"
     ramda "^0.27.1"
 
-"@lingui/react@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@lingui/react/-/react-3.1.0.tgz#ff650b03c3a29cb2576941032b916a63d3b2b2c2"
-  integrity sha512-a3eYTcV8V5fhF0k/BxAT2DQNHlY2UPRvZqeA3OkQvkREptExVeNzo3gfS0bdyOGvJIpILFFBIVtxUhvHSU+dmQ==
+"@lingui/react@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@lingui/react/-/react-3.2.3.tgz#8cf78a217d4a2314ab38c68521a6dd544f87b258"
+  integrity sha512-oPqy7LhJddBDvgDvfKikZh8sFP4uG1/NaDhIkHXVCwf+ONxuAwsDPvW47e/K5hQ60UX2LqGbbB7LuAFK5Klr1Q==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/core" "3.1.0"
+    "@lingui/core" "^3.2.3"
 
 "@next/env@10.0.1":
   version "10.0.1"
diff --git a/packages/cli/src/api/catalog.ts b/packages/cli/src/api/catalog.ts
index 0a17f420..3d826db8 100644
--- a/packages/cli/src/api/catalog.ts
+++ b/packages/cli/src/api/catalog.ts
@@ -141,7 +141,14 @@ export class Catalog {
     }
 
     try {
-      this.sourcePaths.forEach((filename) =>
+      let paths = this.sourcePaths
+      if (options.files) {
+        options.files = options.files.map(p => normalize(p, false))
+        const regex = new RegExp(options.files.join("|"), "i")
+        paths = paths.filter((path: string) => regex.test(path))
+      }
+
+      paths.forEach((filename) =>
         extract(filename, tmpDir, {
           verbose: options.verbose,
           babelOptions: this.config.extractBabelOptions,
diff --git a/packages/cli/src/api/help.ts b/packages/cli/src/api/help.ts
index 3141e71f..bafdc774 100644
--- a/packages/cli/src/api/help.ts
+++ b/packages/cli/src/api/help.ts
@@ -30,20 +30,14 @@ export function helpRun(command: string) {
       .find(([_, value]) => value.includes(`lingui ${command}`))
 
     if (res) {
-      return `${preCommand} ${res[0]}`
+      command = res[0]
     }
   }
 
-  return `${preCommand} ${command}`
+  return `${runCommand} ${command}`
 }
 
-let commands
-try {
-  commands = JSON.parse(process.env.npm_config_argv).original.slice(0, -1)
-} catch (e) {
-  commands = ["run"]
-}
 const isYarn =
   process.env.npm_config_user_agent &&
   process.env.npm_config_user_agent.includes("yarn")
-const preCommand = [isYarn ? "yarn" : "npm", ...commands].join(" ")
+const runCommand = isYarn ? "yarn": "npm run"
\ No newline at end of file
diff --git a/packages/cli/src/lingui-extract-template.ts b/packages/cli/src/lingui-extract-template.ts
index 742585a0..86b2cb7a 100644
--- a/packages/cli/src/lingui-extract-template.ts
+++ b/packages/cli/src/lingui-extract-template.ts
@@ -8,6 +8,7 @@ import { detect } from "./api/detect"
 
 export type CliExtractTemplateOptions = {
   verbose: boolean
+  files?: string[]
 }
 
 export default function command(
diff --git a/packages/cli/src/lingui-extract.ts b/packages/cli/src/lingui-extract.ts
index 6e1dee5b..f8d729e0 100644
--- a/packages/cli/src/lingui-extract.ts
+++ b/packages/cli/src/lingui-extract.ts
@@ -10,6 +10,7 @@ import { helpRun } from "./api/help"
 
 export type CliExtractOptions = {
   verbose: boolean
+  files?: string[]
   clean: boolean
   overwrite: boolean
   locale: string


Test patch:
diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml
index ffffc2bf..2efcc9d2 100644
--- a/.github/workflows/release-test.yml
+++ b/.github/workflows/release-test.yml
@@ -1,9 +1,6 @@
 name: release-workflow-test
 
 on:
-  pull_request:
-    branches:
-      - '*'
   push:
     branches:
       - main
diff --git a/packages/cli/src/api/__snapshots__/catalog.test.ts.snap b/packages/cli/src/api/__snapshots__/catalog.test.ts.snap
index d6a3ac41..0ff28abc 100644
--- a/packages/cli/src/api/__snapshots__/catalog.test.ts.snap
+++ b/packages/cli/src/api/__snapshots__/catalog.test.ts.snap
@@ -44,6 +44,41 @@ Object {
 }
 `;
 
+exports[`Catalog collect should extract only files passed on options 1`] = `
+Object {
+  Component A: Object {
+    extractedComments: Array [],
+    origin: Array [
+      Array [
+        collect/componentA/componentA.js,
+        1,
+      ],
+    ],
+  },
+  Hello World: Object {
+    extractedComments: Array [
+      Comment A,
+      Comment A again,
+      Hello comment,
+    ],
+    origin: Array [
+      Array [
+        collect/componentA/componentA.js,
+        2,
+      ],
+      Array [
+        collect/componentA/componentA.js,
+        3,
+      ],
+      Array [
+        collect/componentA/index.js,
+        1,
+      ],
+    ],
+  },
+}
+`;
+
 exports[`Catalog collect should handle errors 1`] = `Object {}`;
 
 exports[`Catalog make should collect and write catalogs 1`] = `
diff --git a/packages/cli/src/api/catalog.test.ts b/packages/cli/src/api/catalog.test.ts
index 41b846c7..48ff884c 100644
--- a/packages/cli/src/api/catalog.test.ts
+++ b/packages/cli/src/api/catalog.test.ts
@@ -147,6 +147,24 @@ describe("Catalog", function () {
       expect(messages).toMatchSnapshot()
     })
 
+    it("should extract only files passed on options", function () {
+      const catalog = new Catalog(
+        {
+          name: "messages",
+          path: "locales/{locale}",
+          include: [fixture("collect/componentA"), fixture("collect/componentB.js")],
+          exclude: [],
+        },
+        mockConfig()
+      )
+
+      const messages = catalog.collect({
+        ...defaultMakeOptions,
+        files: [fixture("collect/componentA")]
+      })
+      expect(messages).toMatchSnapshot()
+    })
+
     it("should handle errors", function () {
       const catalog = new Catalog(
         {