Repository: Redocly/redocly-cli
Pull request #1580 (2024-06-04 12:09:56)

chore: aggregate data regarding API types and versions usage
## What/Why/How?

Aggregate data regarding API types and versions usage.

~Important: it's better to wait until https://github.com/Redocly/redocly-cli/pull/1493 is merged. Otherwise could run into multiple merge conflicts.~



## Reference

Resolves https://github.com/Redocly/redocly-cli/issues/1297


## Testing

- [x] Additionally checked the push command
- [x] Additionally tested with the `push` action

## Screenshots (optional)

## Check yourself

- [x] Code changed? - Tested with redoc/reference-docs/workflows (internal)
- [x] All new/updated code is covered with tests
- [ ] New package installed? - Tested in different environments (browser/node)

## Security

- [x] Security impact of change has been considered
- [x] Code follows company security practices and guidelines


changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 765f56bd30e4f20954f117ffc1e185825075d62e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/Redocly/redocly-cli/new/chore/aggregate-data-regarding-api-types?filename=.changeset/angry-bananas-march.md&value=---%0A%22%40redocly%2Fcli%22%3A%20patch%0A%22%40redocly%2Fopenapi-core%22%3A%20patch%0A---%0A%0Achore%3A%20aggregate%20data%20regarding%20API%20types%20and%20versions%20usage%0A)


github-actions[bot]: <!-- jest coverage report action for options with hash 3339ae53a38c44382c0fb4491bdb282d -->

## Coverage report 

Multiple errors occurred
```
 1 | Error: The process '/opt/hostedtoolcache/node/20.13.1/x64/bin/npm' failed with exit code 2
 2 | Error: The process '/opt/hostedtoolcache/node/20.13.1/x64/bin/npm' failed with exit code 1
```


| <div title="Status of coverage:&#10; 🟢 - ok&#10; 🟡 - slightly more than threshold&#10; 🔴 - under the threshold">St.<sup>:grey_question:</sup></div> | Category   | Percentage                                                     | Covered / Total |
| :----------------------------------------------------------------------------------------------------------------------------------------------------: | :--------- | :------------------------------------------------------------- | :-------------: |
|                                                                           🟡                                                                           | Statements | <div title="Base coverage is: 77.26%">68.59% (-8.67% 🔻)</div> |    3987/5813    |
|                                                                           🔴                                                                           | Branches   | <div title="Base coverage is: 67.57%">59.31% (-8.25% 🔻)</div> |    2188/3689    |
|                                                                           🟡                                                                           | Functions  | <div title="Base coverage is: 70.94%">62.52% (-8.42% 🔻)</div> |     659/1054    |
|                                                                           🟡                                                                           | Lines      | <div title="Base coverage is: 77.45%">68.42% (-9.03% 🔻)</div> |    3731/5453    |


<details><summary>Show files with reduced coverage 🔻</summary>
<br/>

| <div title="Status of coverage:&#10; 🟢 - ok&#10; 🟡 - slightly more than threshold&#10; 🔴 - under the threshold">St.<sup>:grey_question:</sup></div> | File                                                                          | Statements                                                      | Branches                                                        | Functions                                                       | Lines                                                           |
| :----------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------- | :-------------------------------------------------------------- | :-------------------------------------------------------------- | :-------------------------------------------------------------- | :-------------------------------------------------------------- |
|                                                                           🟢                                                                           | core/src/lint.ts                                                              | 95.83%                                                          | <div title="Base coverage is: 83.33%">81.82% (-1.52% 🔻)</div>  | 100%                                                            | 95.74%                                                          |
|                                                                           🟡                                                                           | <div title="cli/src/utils/miscellaneous.ts">`...` / miscellaneous.ts</div>    | <div title="Base coverage is: 64.9%">63.27% (-1.63% 🔻)</div>   | 51.09%                                                          | <div title="Base coverage is: 75.47%">69.81% (-5.66% 🔻)</div>  | <div title="Base coverage is: 64.32%">62.66% (-1.66% 🔻)</div>  |
|                                                                           🔴                                                                           | <div title="cli/src/commands/push.ts">`...` / push.ts</div>                   | <div title="Base coverage is: 73.81%">24.12% (-49.69% 🔻)</div> | <div title="Base coverage is: 68.46%">22.31% (-46.15% 🔻)</div> | <div title="Base coverage is: 54.55%">27.27% (-27.27% 🔻)</div> | <div title="Base coverage is: 76.25%">25% (-51.25% 🔻)</div>    |
|                                                                           🔴                                                                           | <div title="cli/src/cms/commands/push.ts">`...` / push.ts</div>               | <div title="Base coverage is: 87.32%">16.9% (-70.42% 🔻)</div>  | <div title="Base coverage is: 58.33%">0% (-58.33% 🔻)</div>     | <div title="Base coverage is: 100%">10% (-90% 🔻)</div>         | <div title="Base coverage is: 86.96%">17.39% (-69.57% 🔻)</div> |
|                                                                           🔴                                                                           | <div title="cli/src/cms/commands/push-status.ts">`...` / push-status.ts</div> | <div title="Base coverage is: 91.57%">14.46% (-77.11% 🔻)</div> | <div title="Base coverage is: 77.27%">0% (-77.27% 🔻)</div>     | <div title="Base coverage is: 100%">7.14% (-92.86% 🔻)</div>    | <div title="Base coverage is: 91.57%">14.46% (-77.11% 🔻)</div> |
|                                                                           🔴                                                                           | <div title="cli/src/utils/js-utils.ts">`...` / js-utils.ts</div>              | <div title="Base coverage is: 86.67%">33.33% (-53.33% 🔻)</div> | <div title="Base coverage is: 81.82%">0% (-81.82% 🔻)</div>     | <div title="Base coverage is: 100%">0% (-100% 🔻)</div>         | <div title="Base coverage is: 92.86%">35.71% (-57.14% 🔻)</div> |
|                                                                           🟢                                                                           | <div title="cli/src/cms/commands/utils.ts">`...` / utils.ts</div>             | <div title="Base coverage is: 100%">92.86% (-7.14% 🔻)</div>    | <div title="Base coverage is: 87.5%">81.25% (-6.25% 🔻)</div>   | 100%                                                            | <div title="Base coverage is: 100%">92.86% (-7.14% 🔻)</div>    |
|                                                                           🔴                                                                           | <div title="cli/src/commands/join.ts">`...` / join.ts</div>                   | <div title="Base coverage is: 68.87%">4.72% (-64.15% 🔻)</div>  | <div title="Base coverage is: 54.7%">0% (-54.7% 🔻)</div>       | <div title="Base coverage is: 66.67%">2.08% (-64.58% 🔻)</div>  | <div title="Base coverage is: 70.39%">4.93% (-65.46% 🔻)</div>  |
|                                                                           🔴                                                                           | <div title="cli/src/commands/split/index.ts">`...` / index.ts</div>           | <div title="Base coverage is: 67.48%">23.17% (-44.31% 🔻)</div> | <div title="Base coverage is: 58.4%">13.95% (-44.45% 🔻)</div>  | <div title="Base coverage is: 85.19%">11.11% (-74.07% 🔻)</div> | <div title="Base coverage is: 70.59%">24.68% (-45.91% 🔻)</div> |
|                                                                           🟢                                                                           | cli/src/wrapper.ts                                                            | <div title="Base coverage is: 100%">95.83% (-4.17% 🔻)</div>    | 100%                                                            | <div title="Base coverage is: 100%">80% (-20% 🔻)</div>         | <div title="Base coverage is: 100%">95.65% (-4.35% 🔻)</div>    |
|                                                                           🟢                                                                           | <div title="cli/src/commands/bundle.ts">`...` / bundle.ts</div>               | 86.27%                                                          | 71.79%                                                          | 100%                                                            | 86.27%                                                          |
|                                                                           🔴                                                                           | <div title="cli/src/commands/build-docs/index.ts">`...` / index.ts</div>      | <div title="Base coverage is: 96%">46.15% (-49.85% 🔻)</div>    | <div title="Base coverage is: 60%">0% (-60% 🔻)</div>           | 100%                                                            | <div title="Base coverage is: 95.65%">44% (-51.65% 🔻)</div>    |
|                                                                           🟡                                                                           | <div title="cli/src/commands/build-docs/utils.ts">`...` / utils.ts</div>      | <div title="Base coverage is: 69.77%">65.12% (-4.65% 🔻)</div>  | <div title="Base coverage is: 38.24%">35.29% (-2.94% 🔻)</div>  | <div title="Base coverage is: 83.33%">66.67% (-16.67% 🔻)</div> | <div title="Base coverage is: 71.43%">66.67% (-4.76% 🔻)</div>  |

</details>

## Test suite run failed

<details><summary>Failed tests: 56/740. Failed suites: 8/103.</summary>
<br/>

```
  ● handlePushStatus() › should throw error if organization not provided

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: "No organization provided, please use --organization option or specify the 'organization' field in the config file.·
    "

    Number of calls: 0

       99 |     );
      100 |
    > 101 |     expect(process.stderr.write).toHaveBeenCalledWith(
          |                                  ^
      102 |       `No organization provided, please use --organization option or specify the 'organization' field in the config file.` +
      103 |         '\n\n'
      104 |     );

      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:101:34
      at fulfilled (packages/cli/src/cms/commands/__tests__/push-status.test.ts:5:58)

  ● handlePushStatus() › should throw error if organization not provided

    expect(received).rejects.toThrowErrorMatchingInlineSnapshot(snapshot)

    Snapshot name: `handlePushStatus() should throw error if organization not provided 1`

    Snapshot: "No organization provided, please use --organization option or specify the 'organization' field in the config file."
    Received: "Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined."

       95 |         mockConfig
       96 |       )
    >  97 |     ).rejects.toThrowErrorMatchingInlineSnapshot(
          |               ^
       98 |       `"No organization provided, please use --organization option or specify the 'organization' field in the config file."`
       99 |     );
      100 |

      at Object.toThrowErrorMatchingInlineSnapshot (node_modules/expect/build/index.js:218:22)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:97:15
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:86:68)

  ● handlePushStatus() › should print success push status for preview-build

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:111:27
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:107:71)

  ● handlePushStatus() › should print success push status for preview and production builds

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:130:27
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:126:87)

  ● handlePushStatus() › should print failed push status for preview build

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: "❌ Preview deploy fail.
    Preview URL: https://preview-test-url·
    "

    Number of calls: 0

      172 |     `);
      173 |
    > 174 |     expect(process.stderr.write).toHaveBeenCalledWith(
          |                                  ^
      175 |       '❌ Preview deploy fail.\nPreview URL: https://preview-test-url' + '\n\n'
      176 |     );
      177 |   });

      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:174:34
      at fulfilled (packages/cli/src/cms/commands/__tests__/push-status.test.ts:5:58)

  ● handlePushStatus() › should print failed push status for preview build

    expect(received).rejects.toThrowErrorMatchingInlineSnapshot(snapshot)

    Snapshot name: `handlePushStatus() should print failed push status for preview build 1`

    - Snapshot  - 2
    + Received  + 1

    - ❌ Preview deploy fail.
    - Preview URL: https://preview-test-url
    + Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      167 |         mockConfig
      168 |       )
    > 169 |     ).rejects.toThrowErrorMatchingInlineSnapshot(`
          |               ^
      170 |       "❌ Preview deploy fail.
      171 |       Preview URL: https://preview-test-url"
      172 |     `);

      at Object.toThrowErrorMatchingInlineSnapshot (node_modules/expect/build/index.js:218:22)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:169:15
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:148:70)

  ● handlePushStatus() › should print success push status for preview build and print scorecards

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:200:27
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:179:92)

  ● handlePushStatus() › should print message if there is no changes

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:235:27
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:220:64)

  ● handlePushStatus() › return value › should return preview deployment info

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:256:44
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:252:60)

  ● handlePushStatus() › return value › should return preview and production deployment info

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:283:44
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:279:75)

  ● handlePushStatus() › "wait" option › should wait for preview "success" deployment status

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:347:44
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:314:74)

  ● handlePushStatus() › "wait" option › should wait for production "success" status after preview "success" status

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:420:44
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:372:97)

  ● handlePushStatus() › "continue-on-deploy-failures" option › should throw error if option value is false

    expect(received).rejects.toThrowErrorMatchingInlineSnapshot(snapshot)

    Snapshot name: `handlePushStatus() "continue-on-deploy-failures" option should throw error if option value is false 1`

    - Snapshot  - 2
    + Received  + 1

    - ❌ Preview deploy fail.
    - Preview URL: https://preview-test-url
    + Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      469 |           mockConfig
      470 |         )
    > 471 |       ).rejects.toThrowErrorMatchingInlineSnapshot(`
          |                 ^
      472 |         "❌ Preview deploy fail.
      473 |         Preview URL: https://preview-test-url"
      474 |       `);

      at Object.toThrowErrorMatchingInlineSnapshot (node_modules/expect/build/index.js:218:22)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:471:17
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:447:66)

  ● handlePushStatus() › "continue-on-deploy-failures" option › should not throw error if option value is true

    expect(received).resolves.toStrictEqual()

    Received promise rejected instead of resolved
    Rejected to value: [TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.]

      488 |       });
      489 |
    > 490 |       await expect(
          |             ^
      491 |         handlePushStatus(
      492 |           {
      493 |             domain: 'test-domain',

      at expect (node_modules/expect/build/index.js:113:15)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:490:13
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:477:69)

  ● handlePushStatus() › "onRetry" callback › should be called when command retries request to API in wait mode for preview deploy

    TypeError: Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      46 |   const spinner = new Spinner();
      47 |
    > 48 |   const { organization, project: projectId, pushId, wait } = argv;
         |           ^
      49 |
      50 |   const orgId = organization || config.organization;
      51 |

      at organization (packages/cli/src/cms/commands/push-status.ts:48:11)
      at packages/cli/src/cms/commands/push-status.ts:3169:39
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push-status.ts:3118:10)
      at handlePushStatus (packages/cli/src/cms/commands/push-status.ts:3211:10)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:548:44
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:513:107)

  ● handlePushStatus() › "max-execution-time" option › should throw error in case "max-execution-time" was exceeded

    expect(received).rejects.toThrowErrorMatchingInlineSnapshot(snapshot)

    Snapshot name: `handlePushStatus() "max-execution-time" option should throw error in case "max-execution-time" was exceeded 1`

    - Snapshot  - 2
    + Received  + 1

    - ✗ Failed to get push status. Reason: Timeout exceeded
    -
    + Cannot destructure property 'organization' of '((cov_s8twd953u(...).s[25]++) , argv)' as it is undefined.

      630 |           mockConfig
      631 |         )
    > 632 |       ).rejects.toThrowErrorMatchingInlineSnapshot(`
          |                 ^
      633 |         "✗ Failed to get push status. Reason: Timeout exceeded
      634 |         "
      635 |       `);

      at Object.toThrowErrorMatchingInlineSnapshot (node_modules/expect/build/index.js:218:22)
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:632:17
      at packages/cli/src/cms/commands/__tests__/push-status.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push-status.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push-status.test.ts:605:83)

```
---
```
  ● push › pushes definition

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:28:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:27:38)

  ● push › fails if jobId value is an empty string

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:58:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:57:60)

  ● push › fails if batchSize value is less than 2

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:75:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:74:60)

  ● push › push with --files

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:98:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:91:38)

  ● push › push should fail if organization not provided

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:122:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:121:66)

  ● push › push should work with organization in config

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:143:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:141:65)

  ● push › push should work if destination not provided but api in config is provided

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:178:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:171:95)

  ● push › push should fail if apis not provided

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:195:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:192:58)

  ● push › push should fail if destination not provided

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:215:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:212:65)

  ● push › push should fail if destination format is not valid

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:236:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:233:72)

  ● push › push should work and encode name with spaces

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push.test.ts:264:21
      at packages/cli/src/__tests__/commands/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:255:65)

  ● transformPush › should adapt the existing syntax

    TypeError: Cannot destructure property 'apis' of '((cov_2b3wzvcupy(...).s[173]++) , _c)' as it is undefined.

      365 |   (callback: typeof handlePush) =>
      366 |   ({
    > 367 |     argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
          |             ^
      368 |     config,
      369 |     version,
      370 |   }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {

      at apis (packages/cli/src/commands/push.ts:367:13)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:284:22)

  ● transformPush › should adapt the existing syntax (including branchName)

    TypeError: Cannot destructure property 'apis' of '((cov_2b3wzvcupy(...).s[173]++) , _c)' as it is undefined.

      365 |   (callback: typeof handlePush) =>
      366 |   ({
    > 367 |     argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
          |             ^
      368 |     config,
      369 |     version,
      370 |   }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {

      at apis (packages/cli/src/commands/push.ts:367:13)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:300:22)

  ● transformPush › should use --branch option firstly

    TypeError: Cannot destructure property 'apis' of '((cov_2b3wzvcupy(...).s[173]++) , _c)' as it is undefined.

      365 |   (callback: typeof handlePush) =>
      366 |   ({
    > 367 |     argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
          |             ^
      368 |     config,
      369 |     version,
      370 |   }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {

      at apis (packages/cli/src/commands/push.ts:367:13)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:317:22)

  ● transformPush › should work for a destination only

    TypeError: Cannot destructure property 'apis' of '((cov_2b3wzvcupy(...).s[173]++) , _c)' as it is undefined.

      365 |   (callback: typeof handlePush) =>
      366 |   ({
    > 367 |     argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
          |             ^
      368 |     config,
      369 |     version,
      370 |   }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {

      at apis (packages/cli/src/commands/push.ts:367:13)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:335:22)

  ● transformPush › should work for a api only

    TypeError: Cannot destructure property 'apis' of '((cov_2b3wzvcupy(...).s[173]++) , _c)' as it is undefined.

      365 |   (callback: typeof handlePush) =>
      366 |   ({
    > 367 |     argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
          |             ^
      368 |     config,
      369 |     version,
      370 |   }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {

      at apis (packages/cli/src/commands/push.ts:367:13)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:350:22)

  ● transformPush › should use destination from option

    TypeError: Cannot destructure property 'apis' of '((cov_2b3wzvcupy(...).s[173]++) , _c)' as it is undefined.

      365 |   (callback: typeof handlePush) =>
      366 |   ({
    > 367 |     argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
          |             ^
      368 |     config,
      369 |     version,
      370 |   }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {

      at apis (packages/cli/src/commands/push.ts:367:13)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:366:22)

  ● transformPush › should use --job-id option firstly

    TypeError: Cannot destructure property 'apis' of '((cov_2b3wzvcupy(...).s[173]++) , _c)' as it is undefined.

      365 |   (callback: typeof handlePush) =>
      366 |   ({
    > 367 |     argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
          |             ^
      368 |     config,
      369 |     version,
      370 |   }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {

      at apis (packages/cli/src/commands/push.ts:367:13)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:384:22)

  ● transformPush › should accept no arguments at all

    TypeError: Cannot destructure property 'apis' of '((cov_2b3wzvcupy(...).s[173]++) , _c)' as it is undefined.

      365 |   (callback: typeof handlePush) =>
      366 |   ({
    > 367 |     argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
          |             ^
      368 |     config,
      369 |     version,
      370 |   }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {

      at apis (packages/cli/src/commands/push.ts:367:13)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push.test.ts:406:22)

```
---
```
  ● handlePush() › should upload files

    TypeError: Cannot destructure property 'organization' of '((cov_29o50go0lt(...).s[25]++) , argv)' as it is undefined.

      48 |   const startTime = Date.now(); // for push-status command
      49 |
    > 50 |   const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
         |           ^
      51 |
      52 |   const orgId = organization || config.organization;
      53 |

      at organization (packages/cli/src/cms/commands/push.ts:50:11)
      at packages/cli/src/cms/commands/push.ts:2221:40
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push.ts:2170:10)
      at handlePush (packages/cli/src/cms/commands/push.ts:2264:10)
      at packages/cli/src/cms/commands/__tests__/push.test.ts:66:21
      at packages/cli/src/cms/commands/__tests__/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push.test.ts:52:40)

  ● handlePush() › should return push id

    TypeError: Cannot destructure property 'organization' of '((cov_29o50go0lt(...).s[25]++) , argv)' as it is undefined.

      48 |   const startTime = Date.now(); // for push-status command
      49 |
    > 50 |   const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
         |           ^
      51 |
      52 |   const orgId = organization || config.organization;
      53 |

      at organization (packages/cli/src/cms/commands/push.ts:50:11)
      at packages/cli/src/cms/commands/push.ts:2221:40
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push.ts:2170:10)
      at handlePush (packages/cli/src/cms/commands/push.ts:2264:10)
      at packages/cli/src/cms/commands/__tests__/push.test.ts:135:36
      at packages/cli/src/cms/commands/__tests__/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push.test.ts:121:42)

  ● handlePush() › should collect files from directory and preserve file structure

    TypeError: Cannot destructure property 'organization' of '((cov_29o50go0lt(...).s[25]++) , argv)' as it is undefined.

      48 |   const startTime = Date.now(); // for push-status command
      49 |
    > 50 |   const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
         |           ^
      51 |
      52 |   const orgId = organization || config.organization;
      53 |

      at organization (packages/cli/src/cms/commands/push.ts:50:11)
      at packages/cli/src/cms/commands/push.ts:2221:40
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push.ts:2170:10)
      at handlePush (packages/cli/src/cms/commands/push.ts:2264:10)
      at packages/cli/src/cms/commands/__tests__/push.test.ts:191:21
      at packages/cli/src/cms/commands/__tests__/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push.test.ts:159:84)

  ● handlePush() › should not upload files if no files passed

    TypeError: Cannot destructure property 'organization' of '((cov_29o50go0lt(...).s[25]++) , argv)' as it is undefined.

      48 |   const startTime = Date.now(); // for push-status command
      49 |
    > 50 |   const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
         |           ^
      51 |
      52 |   const orgId = organization || config.organization;
      53 |

      at organization (packages/cli/src/cms/commands/push.ts:50:11)
      at packages/cli/src/cms/commands/push.ts:2221:40
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push.ts:2170:10)
      at handlePush (packages/cli/src/cms/commands/push.ts:2264:10)
      at packages/cli/src/cms/commands/__tests__/push.test.ts:233:21
      at packages/cli/src/cms/commands/__tests__/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push.test.ts:229:63)

  ● handlePush() › should get organization from config if not passed

    TypeError: Cannot destructure property 'organization' of '((cov_29o50go0lt(...).s[25]++) , argv)' as it is undefined.

      48 |   const startTime = Date.now(); // for push-status command
      49 |
    > 50 |   const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
         |           ^
      51 |
      52 |   const orgId = organization || config.organization;
      53 |

      at organization (packages/cli/src/cms/commands/push.ts:50:11)
      at packages/cli/src/cms/commands/push.ts:2221:40
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push.ts:2170:10)
      at handlePush (packages/cli/src/cms/commands/push.ts:2264:10)
      at packages/cli/src/cms/commands/__tests__/push.test.ts:268:21
      at packages/cli/src/cms/commands/__tests__/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push.test.ts:254:70)

  ● handlePush() › should get domain from env if not passed

    TypeError: Cannot destructure property 'organization' of '((cov_29o50go0lt(...).s[25]++) , argv)' as it is undefined.

      48 |   const startTime = Date.now(); // for push-status command
      49 |
    > 50 |   const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
         |           ^
      51 |
      52 |   const orgId = organization || config.organization;
      53 |

      at organization (packages/cli/src/cms/commands/push.ts:50:11)
      at packages/cli/src/cms/commands/push.ts:2221:40
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/push.ts:2170:10)
      at handlePush (packages/cli/src/cms/commands/push.ts:2264:10)
      at packages/cli/src/cms/commands/__tests__/push.test.ts:315:21
      at packages/cli/src/cms/commands/__tests__/push.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/cms/commands/__tests__/push.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/cms/commands/__tests__/push.test.ts:300:61)

```
---
```
  ● handleJoin › should call exitWithError because only one entrypoint

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:17:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:16:74)

  ● handleJoin › should call exitWithError because passed all 3 options for tags

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:22:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:21:84)

  ● handleJoin › should call exitWithError because passed all 2 options for tags

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:39:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:38:84)

  ● handleJoin › should call exitWithError because Only OpenAPI 3.0 and OpenAPI 3.1 are supported

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:55:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:54:101)

  ● handleJoin › should call exitWithError if mixing OpenAPI 3.0 and 3.1

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:71:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:67:76)

  ● handleJoin › should call writeToFileByExtension function

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:86:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:84:64)

  ● handleJoin › should call writeToFileByExtension function for OpenAPI 3.1

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:103:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:101:80)

  ● handleJoin › should call writeToFileByExtension function with custom output file

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:120:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:118:88)

  ● handleJoin › should call writeToFileByExtension function with json file extension

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:138:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:136:89)

  ● handleJoin › should call skipDecorators and skipPreprocessors

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:155:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:153:69)

  ● handleJoin › should handle join with prefix-components-with-info-prop and null values

    TypeError: Cannot read properties of undefined (reading 'apis')

      72 |   const startedAt = performance.now();
      73 |
    > 74 |   if (argv.apis.length < 2) {
         |            ^
      75 |     return exitWithError(`At least 2 apis should be provided.`);
      76 |   }
      77 |

      at apis (packages/cli/src/commands/join.ts:74:12)
      at packages/cli/src/commands/join.ts:9696:39
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/join.ts:9645:10)
      at handleJoin (packages/cli/src/commands/join.ts:9751:10)
      at packages/cli/src/__tests__/commands/join.test.ts:171:21
      at packages/cli/src/__tests__/commands/join.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/join.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/join.test.ts:168:93)

```
---
```
  ● #split › should split the file and show the success message

    TypeError: Cannot destructure property 'api' of '((cov_1dusz43mmk(...).s[25]++) , argv)' as it is undefined.

      48 | export async function handleSplit({ argv, collectSpecVersion }: CommandArgs<SplitOptions>) {
      49 |   const startedAt = performance.now();
    > 50 |   const { api, outDir, separator } = argv;
         |           ^
      51 |   validateDefinitionFileName(api!);
      52 |   const ext = getAndValidateFileExtension(api);
      53 |   const openapi = readYaml(api!) as Oas3Definition | Oas3_1Definition;

      at api (packages/cli/src/commands/split/index.ts:50:11)
      at packages/cli/src/commands/split/index.ts:5768:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/split/index.ts:5717:10)
      at handleSplit (packages/cli/src/commands/split/index.ts:5813:10)
      at packages/cli/src/commands/split/__tests__/index.test.ts:27:22
      at packages/cli/src/commands/split/__tests__/index.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/split/__tests__/index.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/commands/split/__tests__/index.test.ts:23:71)

  ● #split › should use the correct separator

    TypeError: Cannot destructure property 'api' of '((cov_1dusz43mmk(...).s[25]++) , argv)' as it is undefined.

      48 | export async function handleSplit({ argv, collectSpecVersion }: CommandArgs<SplitOptions>) {
      49 |   const startedAt = performance.now();
    > 50 |   const { api, outDir, separator } = argv;
         |           ^
      51 |   validateDefinitionFileName(api!);
      52 |   const ext = getAndValidateFileExtension(api);
      53 |   const openapi = readYaml(api!) as Oas3Definition | Oas3_1Definition;

      at api (packages/cli/src/commands/split/index.ts:50:11)
      at packages/cli/src/commands/split/index.ts:5768:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/split/index.ts:5717:10)
      at handleSplit (packages/cli/src/commands/split/index.ts:5813:10)
      at packages/cli/src/commands/split/__tests__/index.test.ts:48:22
      at packages/cli/src/commands/split/__tests__/index.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/split/__tests__/index.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/commands/split/__tests__/index.test.ts:43:53)

```
---
```
  ● commandWrapper › should send telemetry if there is "telemetry: on" in the config

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    - Expected
    + Received

      {},
      0,
      false,
    + undefined,

    Number of calls: 1

      27 |     expect(handleLint).toHaveBeenCalledTimes(1);
      28 |     expect(sendTelemetry).toHaveBeenCalledTimes(1);
    > 29 |     expect(sendTelemetry).toHaveBeenCalledWith({}, 0, false);
         |                           ^
      30 |   });
      31 |
      32 |   it('should NOT send telemetry if there is "telemetry: off" in the config', async () => {

      at packages/cli/src/__tests__/wrapper.test.ts:29:27
      at fulfilled (packages/cli/src/__tests__/wrapper.test.ts:5:58)

```
---
```
  ● push-with-region › should call login with default domain when region is US

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push-region.test.ts:31:21
      at packages/cli/src/__tests__/commands/push-region.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push-region.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push-region.test.ts:29:76)

  ● push-with-region › should call login with EU domain when region is EU

    TypeError: Cannot read properties of undefined (reading 'region')

      62 |
      63 | export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
    > 64 |   const client = new RedoclyClient(config.region);
         |                                           ^
      65 |   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
      66 |   if (!isAuthorized) {
      67 |     const clientToken = await promptClientToken(client.domain);

      at region (packages/cli/src/commands/push.ts:64:43)
      at packages/cli/src/commands/push.ts:6067:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/push.ts:6016:10)
      at handlePush (packages/cli/src/commands/push.ts:6222:10)
      at packages/cli/src/__tests__/commands/push-region.test.ts:46:21
      at packages/cli/src/__tests__/commands/push-region.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/push-region.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/push-region.test.ts:44:71)

```
---
```
  ● build-docs › should work correctly when calling handlerBuildCommand

    TypeError: Cannot read properties of undefined (reading 'api')

      17 |   const startedAt = performance.now();
      18 |
    > 19 |   const config = getMergedConfig(configFromFile, argv.api);
         |                                                       ^
      20 |   const apis = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
      21 |   const { path: pathToApi } = apis[0];
      22 |

      at api (packages/cli/src/commands/build-docs/index.ts:19:55)
      at packages/cli/src/commands/build-docs/index.ts:1209:40
      at Object.<anonymous>.__awaiter (packages/cli/src/commands/build-docs/index.ts:1158:10)
      at __awaiter (packages/cli/src/commands/build-docs/index.ts:16:34)
      at packages/cli/src/__tests__/commands/build-docs.test.ts:42:30
      at packages/cli/src/__tests__/commands/build-docs.test.ts:8:71
      at Object.<anonymous>.__awaiter (packages/cli/src/__tests__/commands/build-docs.test.ts:4:12)
      at Object.<anonymous> (packages/cli/src/__tests__/commands/build-docs.test.ts:40:75)

```

</details>


<p align="right">Report generated by <a href="https://github.com/ArtiomTr/jest-coverage-report-action">🧪jest coverage report action</a> from 765f56bd30e4f20954f117ffc1e185825075d62e</p>

github-actions[bot]: | Command | Mean [s] | Min [s] | Max [s] | Relative |
|:---|---:|---:|---:|---:|
| `redocly lint packages/core/src/benchmark/benches/rebilly.yaml` | 1.015 ± 0.029 | 0.956 | 1.059 | 1.01 ± 0.04 |
| `redocly-next lint packages/core/src/benchmark/benches/rebilly.yaml` | 1.002 ± 0.020 | 0.980 | 1.040 | 1.00 |

<!-- thollander/actions-comment-pull-request "latest-vs-next-comparison" -->
lornajane: Please update the related docs as well `/docs/usage-data.md` to add these fields to the data collection list.

Patch:
diff --git a/docs/usage-data.md b/docs/usage-data.md
index 9cd94e3f..2c161efe 100644
--- a/docs/usage-data.md
+++ b/docs/usage-data.md
@@ -16,6 +16,8 @@ When a command is run, the following data is collected:
 - values from `REDOCLY_ENVIRONMENT`
 - CLI version
 - Node.js and NPM versions
+- whether the `redocly.yaml` configuration file exists
+- API specification version
 
 Values such as file names, organization IDs, and URLs are removed, replaced by just "URL" or "file", etc.
 
diff --git a/packages/cli/src/cms/commands/push-status.ts b/packages/cli/src/cms/commands/push-status.ts
index b52d80d0..428957d9 100644
--- a/packages/cli/src/cms/commands/push-status.ts
+++ b/packages/cli/src/cms/commands/push-status.ts
@@ -1,18 +1,19 @@
 import * as colors from 'colorette';
-import type { Config, OutputFormat } from '@redocly/openapi-core';
-
 import { exitWithError, printExecutionTime } from '../../utils/miscellaneous';
 import { Spinner } from '../../utils/spinner';
 import { DeploymentError } from '../utils';
 import { ReuniteApiClient, getApiKeys, getDomain } from '../api';
 import { capitalize } from '../../utils/js-utils';
+import { retryUntilConditionMet } from './utils';
+
+import type { OutputFormat } from '@redocly/openapi-core';
+import type { CommandArgs } from '../../wrapper';
 import type {
   DeploymentStatus,
   DeploymentStatusResponse,
   PushResponse,
   ScorecardItem,
 } from '../api/types';
-import { retryUntilConditionMet } from './utils';
 
 const RETRY_INTERVAL_MS = 5000; // 5 sec
 
@@ -37,10 +38,10 @@ export interface PushStatusSummary {
   commit: PushResponse['commit'];
 }
 
-export async function handlePushStatus(
-  argv: PushStatusOptions,
-  config: Config
-): Promise<PushStatusSummary | undefined> {
+export async function handlePushStatus({
+  argv,
+  config,
+}: CommandArgs<PushStatusOptions>): Promise<PushStatusSummary | undefined> {
   const startedAt = performance.now();
   const spinner = new Spinner();
 
diff --git a/packages/cli/src/cms/commands/push.ts b/packages/cli/src/cms/commands/push.ts
index 9fc7249b..a3b43ee6 100644
--- a/packages/cli/src/cms/commands/push.ts
+++ b/packages/cli/src/cms/commands/push.ts
@@ -11,7 +11,8 @@ import {
 import { handlePushStatus } from './push-status';
 import { ReuniteApiClient, getDomain, getApiKeys } from '../api';
 
-import type { OutputFormat, Config } from '@redocly/openapi-core';
+import type { OutputFormat } from '@redocly/openapi-core';
+import type { CommandArgs } from '../../wrapper';
 
 export type PushOptions = {
   apis?: string[];
@@ -42,10 +43,11 @@ export type PushOptions = {
 
 type FileToUpload = { name: string; path: string };
 
-export async function handlePush(
-  argv: PushOptions,
-  config: Config
-): Promise<{ pushId: string } | void> {
+export async function handlePush({
+  argv,
+  config,
+  version,
+}: CommandArgs<PushOptions>): Promise<{ pushId: string } | void> {
   const startedAt = performance.now(); // for printing execution time
   const startTime = Date.now(); // for push-status command
 
@@ -131,8 +133,8 @@ export async function handlePush(
     if (waitForDeployment) {
       process.stdout.write('\n');
 
-      await handlePushStatus(
-        {
+      await handlePushStatus({
+        argv: {
           organization: orgId,
           project: projectId,
           pushId: id,
@@ -142,8 +144,9 @@ export async function handlePush(
           'start-time': startTime,
           'continue-on-deploy-failures': argv['continue-on-deploy-failures'],
         },
-        config
-      );
+        config,
+        version,
+      });
     }
     verbose &&
       printExecutionTime(
diff --git a/packages/cli/src/commands/build-docs/index.ts b/packages/cli/src/commands/build-docs/index.ts
index e837d44d..69977bef 100644
--- a/packages/cli/src/commands/build-docs/index.ts
+++ b/packages/cli/src/commands/build-docs/index.ts
@@ -2,17 +2,21 @@ import { loadAndBundleSpec } from 'redoc';
 import { dirname, resolve } from 'path';
 import { writeFileSync, mkdirSync } from 'fs';
 import { performance } from 'perf_hooks';
-
+import { getMergedConfig, isAbsoluteUrl } from '@redocly/openapi-core';
 import { getObjectOrJSON, getPageHTML } from './utils';
-import type { BuildDocsArgv } from './types';
-import { Config, getMergedConfig, isAbsoluteUrl } from '@redocly/openapi-core';
 import { exitWithError, getExecutionTime, getFallbackApisOrExit } from '../../utils/miscellaneous';
 
-export const handlerBuildCommand = async (argv: BuildDocsArgv, configFromFile: Config) => {
+import type { BuildDocsArgv } from './types';
+import type { CommandArgs } from '../../wrapper';
+
+export const handlerBuildCommand = async ({
+  argv,
+  config: configFromFile,
+  collectSpecData,
+}: CommandArgs<BuildDocsArgv>) => {
   const startedAt = performance.now();
 
   const config = getMergedConfig(configFromFile, argv.api);
-
   const apis = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
   const { path: pathToApi } = apis[0];
 
@@ -31,6 +35,7 @@ export const handlerBuildCommand = async (argv: BuildDocsArgv, configFromFile: C
     const elapsed = getExecutionTime(startedAt);
 
     const api = await loadAndBundleSpec(isAbsoluteUrl(pathToApi) ? pathToApi : resolve(pathToApi));
+    collectSpecData?.(api);
     const pageHTML = await getPageHTML(
       api,
       pathToApi,
diff --git a/packages/cli/src/commands/bundle.ts b/packages/cli/src/commands/bundle.ts
index dea5786e..ee32d728 100644
--- a/packages/cli/src/commands/bundle.ts
+++ b/packages/cli/src/commands/bundle.ts
@@ -1,4 +1,7 @@
-import { formatProblems, getTotals, getMergedConfig, bundle, Config } from '@redocly/openapi-core';
+import { performance } from 'perf_hooks';
+import { blue, gray, green, yellow } from 'colorette';
+import { writeFileSync } from 'fs';
+import { formatProblems, getTotals, getMergedConfig, bundle } from '@redocly/openapi-core';
 import {
   dumpBundle,
   getExecutionTime,
@@ -8,12 +11,11 @@ import {
   printUnusedWarnings,
   saveBundle,
   sortTopLevelKeysForOas,
+  checkForDeprecatedOptions,
 } from '../utils/miscellaneous';
+
 import type { OutputExtensions, Skips, Totals } from '../types';
-import { performance } from 'perf_hooks';
-import { blue, gray, green, yellow } from 'colorette';
-import { writeFileSync } from 'fs';
-import { checkForDeprecatedOptions } from '../utils/miscellaneous';
+import type { CommandArgs } from '../wrapper';
 
 export type BundleOptions = {
   apis?: string[];
@@ -28,7 +30,12 @@ export type BundleOptions = {
   'keep-url-references'?: boolean;
 } & Skips;
 
-export async function handleBundle(argv: BundleOptions, config: Config, version: string) {
+export async function handleBundle({
+  argv,
+  config,
+  version,
+  collectSpecData,
+}: CommandArgs<BundleOptions>) {
   const removeUnusedComponents =
     argv['remove-unused-components'] ||
     config.rawConfig?.styleguide?.decorators?.hasOwnProperty('remove-unused-components');
@@ -59,6 +66,7 @@ export async function handleBundle(argv: BundleOptions, config: Config, version:
         dereference: argv.dereferenced,
         removeUnusedComponents,
         keepUrlRefs: argv['keep-url-references'],
+        collectSpecData,
       });
 
       const fileTotals = getTotals(problems);
diff --git a/packages/cli/src/commands/join.ts b/packages/cli/src/commands/join.ts
index 8953fc28..04309193 100644
--- a/packages/cli/src/commands/join.ts
+++ b/packages/cli/src/commands/join.ts
@@ -2,7 +2,6 @@ import * as path from 'path';
 import { red, blue, yellow, green } from 'colorette';
 import { performance } from 'perf_hooks';
 import {
-  Config,
   SpecVersion,
   BaseResolver,
   formatProblems,
@@ -38,6 +37,7 @@ import type {
   Oas3Server,
   Oas3_1Definition,
 } from '@redocly/openapi-core/lib/typings/openapi';
+import type { CommandArgs } from '../wrapper';
 
 const Tags = 'tags';
 const xTagGroups = 'x-tagGroups';
@@ -64,7 +64,11 @@ export type JoinOptions = {
   'lint-config'?: RuleSeverity;
 };
 
-export async function handleJoin(argv: JoinOptions, config: Config, packageVersion: string) {
+export async function handleJoin({
+  argv,
+  config,
+  version: packageVersion,
+}: CommandArgs<JoinOptions>) {
   const startedAt = performance.now();
 
   if (argv.apis.length < 2) {
diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts
index acc3ae68..8030b9a0 100644
--- a/packages/cli/src/commands/lint.ts
+++ b/packages/cli/src/commands/lint.ts
@@ -1,7 +1,6 @@
 import { blue, gray } from 'colorette';
 import { performance } from 'perf_hooks';
 import {
-  Config,
   formatProblems,
   getMergedConfig,
   getTotals,
@@ -23,10 +22,11 @@ import {
 } from '../utils/miscellaneous';
 import { getCommandNameFromArgs } from '../utils/getCommandNameFromArgs';
 
+import type { Arguments } from 'yargs';
 import type { OutputFormat, ProblemSeverity, RuleSeverity } from '@redocly/openapi-core';
 import type { RawConfigProcessor } from '@redocly/openapi-core/lib/config';
 import type { CommandOptions, Skips, Totals } from '../types';
-import type { Arguments } from 'yargs';
+import type { CommandArgs } from '../wrapper';
 
 export type LintOptions = {
   apis?: string[];
@@ -38,7 +38,12 @@ export type LintOptions = {
   'lint-config'?: RuleSeverity;
 } & Omit<Skips, 'skip-decorator'>;
 
-export async function handleLint(argv: LintOptions, config: Config, version: string) {
+export async function handleLint({
+  argv,
+  config,
+  version,
+  collectSpecData,
+}: CommandArgs<LintOptions>) {
   const apis = await getFallbackApisOrExit(argv.apis, config);
 
   if (!apis.length) {
@@ -74,6 +79,7 @@ export async function handleLint(argv: LintOptions, config: Config, version: str
       const results = await lint({
         ref: path,
         config: resolvedConfig,
+        collectSpecData,
       });
 
       const fileTotals = getTotals(results);
diff --git a/packages/cli/src/commands/login.ts b/packages/cli/src/commands/login.ts
index 14d1c1d7..8b5c89d6 100644
--- a/packages/cli/src/commands/login.ts
+++ b/packages/cli/src/commands/login.ts
@@ -1,7 +1,9 @@
-import { Region, RedoclyClient, Config } from '@redocly/openapi-core';
+import { Region, RedoclyClient } from '@redocly/openapi-core';
 import { blue, green, gray } from 'colorette';
 import { promptUser } from '../utils/miscellaneous';
 
+import type { CommandArgs } from '../wrapper';
+
 export function promptClientToken(domain: string) {
   return promptUser(
     green(
@@ -17,7 +19,7 @@ export type LoginOptions = {
   config?: string;
 };
 
-export async function handleLogin(argv: LoginOptions, config: Config) {
+export async function handleLogin({ argv, config }: CommandArgs<LoginOptions>) {
   const region = argv.region || config.region;
   const client = new RedoclyClient(region);
   const clientToken = await promptClientToken(client.domain);
diff --git a/packages/cli/src/commands/preview-docs/index.ts b/packages/cli/src/commands/preview-docs/index.ts
index 896e12cc..9afc0d63 100644
--- a/packages/cli/src/commands/preview-docs/index.ts
+++ b/packages/cli/src/commands/preview-docs/index.ts
@@ -7,7 +7,9 @@ import {
   loadConfigAndHandleErrors,
 } from '../../utils/miscellaneous';
 import startPreviewServer from './preview-server/preview-server';
+
 import type { Skips } from '../../types';
+import type { CommandArgs } from '../../wrapper';
 
 export type PreviewDocsOptions = {
   port: number;
@@ -18,7 +20,10 @@ export type PreviewDocsOptions = {
   force?: boolean;
 } & Omit<Skips, 'skip-rule'>;
 
-export async function previewDocs(argv: PreviewDocsOptions, configFromFile: Config) {
+export async function previewDocs({
+  argv,
+  config: configFromFile,
+}: CommandArgs<PreviewDocsOptions>) {
   let isAuthorizedWithRedocly = false;
   let redocOptions: any = {};
   let config = await reloadConfig(configFromFile);
diff --git a/packages/cli/src/commands/preview-project/index.ts b/packages/cli/src/commands/preview-project/index.ts
index e86a6308..cc32bf63 100644
--- a/packages/cli/src/commands/preview-project/index.ts
+++ b/packages/cli/src/commands/preview-project/index.ts
@@ -4,12 +4,13 @@ import { spawn } from 'child_process';
 import { PRODUCT_NAMES, PRODUCT_PACKAGES } from './constants';
 
 import type { PreviewProjectOptions, Product } from './types';
+import type { CommandArgs } from '../../wrapper';
 
-export const previewProject = async (args: PreviewProjectOptions) => {
-  const { plan, port } = args;
-  const projectDir = args['source-dir'];
+export const previewProject = async ({ argv }: CommandArgs<PreviewProjectOptions>) => {
+  const { plan, port } = argv;
+  const projectDir = argv['source-dir'];
 
-  const product = args.product || tryGetProductFromPackageJson(projectDir);
+  const product = argv.product || tryGetProductFromPackageJson(projectDir);
 
   if (!isValidProduct(product)) {
     process.stderr.write(`Invalid product ${product}`);
diff --git a/packages/cli/src/commands/push.ts b/packages/cli/src/commands/push.ts
index b34ac087..f3def883 100644
--- a/packages/cli/src/commands/push.ts
+++ b/packages/cli/src/commands/push.ts
@@ -26,6 +26,8 @@ import {
 import { promptClientToken } from './login';
 import { handlePush as handleCMSPush } from '../cms/commands/push';
 
+import type { CommandArgs } from '../wrapper';
+
 const DEFAULT_VERSION = 'latest';
 
 export const DESTINATION_REGEX =
@@ -59,7 +61,7 @@ export function commonPushHandler({
   return transformPush(handlePush);
 }
 
-export async function handlePush(argv: PushOptions, config: Config): Promise<void> {
+export async function handlePush({ argv, config }: CommandArgs<PushOptions>): Promise<void> {
   const client = new RedoclyClient(config.region);
   const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
   if (!isAuthorized) {
@@ -366,16 +368,11 @@ type BarePushArgs = Omit<PushOptions, 'destination' | 'branchName'> & {
 
 export const transformPush =
   (callback: typeof handlePush) =>
-  (
-    {
-      apis,
-      branch,
-      'batch-id': batchId,
-      'job-id': jobId,
-      ...rest
-    }: BarePushArgs & { 'batch-id'?: string },
-    config: Config
-  ) => {
+  ({
+    argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
+    config,
+    version,
+  }: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {
     const [maybeApiOrDestination, maybeDestination, maybeBranchName] = apis || [];
 
     if (batchId) {
@@ -414,16 +411,17 @@ export const transformPush =
       apiFile = maybeApiOrDestination;
     }
 
-    return callback(
-      {
+    return callback({
+      argv: {
         ...rest,
         destination: rest.destination ?? destination,
         api: apiFile,
         branchName: branch ?? maybeBranchName,
         'job-id': jobId || batchId,
       },
-      config
-    );
+      config,
+      version,
+    });
   };
 
 export function getApiRoot({
diff --git a/packages/cli/src/commands/split/index.ts b/packages/cli/src/commands/split/index.ts
index bd0951f5..49ea5749 100644
--- a/packages/cli/src/commands/split/index.ts
+++ b/packages/cli/src/commands/split/index.ts
@@ -36,6 +36,7 @@ import type {
   Oas3PathItem,
   Referenced,
 } from './types';
+import type { CommandArgs } from '../../wrapper';
 
 export type SplitOptions = {
   api: string;
@@ -44,12 +45,13 @@ export type SplitOptions = {
   config?: string;
 };
 
-export async function handleSplit(argv: SplitOptions) {
+export async function handleSplit({ argv, collectSpecData }: CommandArgs<SplitOptions>) {
   const startedAt = performance.now();
   const { api, outDir, separator } = argv;
   validateDefinitionFileName(api!);
   const ext = getAndValidateFileExtension(api);
   const openapi = readYaml(api!) as Oas3Definition | Oas3_1Definition;
+  collectSpecData?.(openapi);
   splitDefinition(openapi, outDir, separator, ext);
   process.stderr.write(
     `🪓 Document: ${blue(api!)} ${green('is successfully split')}
@@ -292,7 +294,7 @@ function iteratePathItems(
 
   for (const pathName of Object.keys(pathItems)) {
     const pathFile = `${path.join(outDir, pathToFilename(pathName, pathSeparator))}.${ext}`;
-    const pathData = pathItems[pathName] as Oas3PathItem;
+    const pathData = pathItems[pathName];
 
     if (isRef(pathData)) continue;
 
diff --git a/packages/cli/src/commands/stats.ts b/packages/cli/src/commands/stats.ts
index b6af03df..84e438d4 100755
--- a/packages/cli/src/commands/stats.ts
+++ b/packages/cli/src/commands/stats.ts
@@ -1,7 +1,6 @@
 import { performance } from 'perf_hooks';
 import * as colors from 'colorette';
 import {
-  Config,
   StyleguideConfig,
   normalizeTypes,
   BaseResolver,
@@ -15,7 +14,9 @@ import {
 } from '@redocly/openapi-core';
 import { getFallbackApisOrExit } from '../utils/miscellaneous';
 import { printExecutionTime } from '../utils/miscellaneous';
+
 import type { StatsAccumulator, StatsName, WalkContext, OutputFormat } from '@redocly/openapi-core';
+import type { CommandArgs } from '../wrapper';
 
 const statsAccumulator: StatsAccumulator = {
   refs: { metric: '🚗 References', total: 0, color: 'red', items: new Set() },
@@ -86,10 +87,11 @@ export type StatsOptions = {
   config?: string;
 };
 
-export async function handleStats(argv: StatsOptions, config: Config) {
+export async function handleStats({ argv, config, collectSpecData }: CommandArgs<StatsOptions>) {
   const [{ path }] = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
   const externalRefResolver = new BaseResolver(config.resolve);
   const { bundle: document } = await bundle({ config, ref: path });
+  collectSpecData?.(document.parsed);
   const lintConfig: StyleguideConfig = config.styleguide;
   const specVersion = detectSpec(document.parsed);
   const types = normalizeTypes(
diff --git a/packages/cli/src/utils/miscellaneous.ts b/packages/cli/src/utils/miscellaneous.ts
index 2e6a42fb..9b597070 100644
--- a/packages/cli/src/utils/miscellaneous.ts
+++ b/packages/cli/src/utils/miscellaneous.ts
@@ -541,7 +541,10 @@ export function cleanColors(input: string): string {
 export async function sendTelemetry(
   argv: Arguments | undefined,
   exit_code: ExitCode,
-  has_config: boolean | undefined
+  has_config: boolean | undefined,
+  spec_version: string | undefined,
+  spec_keyword: string | undefined,
+  spec_full_version: string | undefined
 ): Promise<void> {
   try {
     if (!argv) {
@@ -569,6 +572,9 @@ export async function sendTelemetry(
       environment_ci: process.env.CI,
       raw_input: cleanRawInput(process.argv.slice(2)),
       has_config,
+      spec_version,
+      spec_keyword,
+      spec_full_version,
     };
     await fetch(`https://api.redocly.com/registry/telemetry/cli`, {
       method: 'POST',
@@ -598,6 +604,9 @@ export type Analytics = {
   environment_ci?: string;
   raw_input: string;
   has_config?: boolean;
+  spec_version?: string;
+  spec_keyword?: string;
+  spec_full_version?: string;
 };
 
 function isFile(value: string) {
diff --git a/packages/cli/src/wrapper.ts b/packages/cli/src/wrapper.ts
index 60df5b25..df27a116 100644
--- a/packages/cli/src/wrapper.ts
+++ b/packages/cli/src/wrapper.ts
@@ -1,22 +1,48 @@
-import { Config, Region, doesYamlFileExist } from '@redocly/openapi-core';
-import type { Arguments } from 'yargs';
+import { detectSpec, doesYamlFileExist } from '@redocly/openapi-core';
+import { isPlainObject } from '@redocly/openapi-core/lib/utils';
 import { version } from './utils/update-version-notifier';
-import {
-  ExitCode,
-  exitWithError,
-  loadConfigAndHandleErrors,
-  sendTelemetry,
-} from './utils/miscellaneous';
+import { exitWithError, loadConfigAndHandleErrors, sendTelemetry } from './utils/miscellaneous';
 import { lintConfigCallback } from './commands/lint';
+
+import type { Arguments } from 'yargs';
+import type { Config, Region } from '@redocly/openapi-core';
+import type { CollectFn } from '@redocly/openapi-core/lib/utils';
+import type { ExitCode } from './utils/miscellaneous';
 import type { CommandOptions } from './types';
 
+export type CommandArgs<T extends CommandOptions> = {
+  argv: T;
+  config: Config;
+  version: string;
+  collectSpecData?: CollectFn;
+};
+
 export function commandWrapper<T extends CommandOptions>(
-  commandHandler?: (argv: T, config: Config, version: string) => Promise<unknown>
+  commandHandler?: (wrapperArgs: CommandArgs<T>) => Promise<unknown>
 ) {
   return async (argv: Arguments<T>) => {
     let code: ExitCode = 2;
     let hasConfig;
     let telemetry;
+    let specVersion: string | undefined;
+    let specKeyword: string | undefined;
+    let specFullVersion: string | undefined;
+    const collectSpecData: CollectFn = (document) => {
+      specVersion = detectSpec(document);
+      if (!isPlainObject(document)) return;
+      specKeyword = document?.openapi
+        ? 'openapi'
+        : document?.swagger
+        ? 'swagger'
+        : document?.asyncapi
+        ? 'asyncapi'
+        : document?.arazzo
+        ? 'arazzo'
+        : undefined;
+      if (specKeyword) {
+        specFullVersion = document[specKeyword] as string;
+      }
+    };
     try {
       if (argv.config && !doesYamlFileExist(argv.config)) {
         exitWithError('Please provide a valid path to the configuration file.');
@@ -32,14 +58,14 @@ export function commandWrapper<T extends CommandOptions>(
       hasConfig = !config.styleguide.recommendedFallback;
       code = 1;
       if (typeof commandHandler === 'function') {
-        await commandHandler(argv, config, version);
+        await commandHandler({ argv, config, version, collectSpecData });
       }
       code = 0;
     } catch (err) {
       // Do nothing
     } finally {
       if (process.env.REDOCLY_TELEMETRY !== 'off' && telemetry !== 'off') {
-        await sendTelemetry(argv, code, hasConfig);
+        await sendTelemetry(argv, code, hasConfig, specVersion, specKeyword, specFullVersion);
       }
       process.once('beforeExit', () => {
         process.exit(code);
diff --git a/packages/core/src/bundle.ts b/packages/core/src/bundle.ts
index 99280185..848f8e23 100755
--- a/packages/core/src/bundle.ts
+++ b/packages/core/src/bundle.ts
@@ -24,6 +24,7 @@ import type { WalkContext, UserContext, ResolveResult, NormalizedProblem } from
 import type { Config, StyleguideConfig } from './config';
 import type { OasRef } from './typings/openapi';
 import type { Document, ResolvedRefMap } from './resolve';
+import type { CollectFn } from './utils';
 
 export enum OasVersion {
   Version2 = 'oas2',
@@ -82,6 +83,7 @@ export async function bundle(
   opts: {
     ref?: string;
     doc?: Document;
+    collectSpecData?: CollectFn;
   } & BundleOptions
 ) {
   const {
@@ -100,6 +102,7 @@ export async function bundle(
   if (document instanceof Error) {
     throw document;
   }
+  opts.collectSpecData?.(document.parsed);
 
   return bundleDocument({
     document,
diff --git a/packages/core/src/lint.ts b/packages/core/src/lint.ts
index b40408d7..3012332c 100755
--- a/packages/core/src/lint.ts
+++ b/packages/core/src/lint.ts
@@ -22,14 +22,17 @@ import type {
   Oas3Visitor,
   RuleInstanceConfig,
 } from './visitors';
+import type { CollectFn } from './utils';
 
 export async function lint(opts: {
   ref: string;
   config: Config;
   externalRefResolver?: BaseResolver;
+  collectSpecData?: CollectFn;
 }) {
   const { ref, externalRefResolver = new BaseResolver(opts.config.resolve) } = opts;
   const document = (await externalRefResolver.resolveDocument(null, ref, true)) as Document;
+  opts.collectSpecData?.(document.parsed);
 
   return lintDocument({
     document,
diff --git a/packages/core/src/oas-types.ts b/packages/core/src/oas-types.ts
index 491e0cf6..90ab032a 100644
--- a/packages/core/src/oas-types.ts
+++ b/packages/core/src/oas-types.ts
@@ -1,4 +1,4 @@
-import {
+import type {
   Oas3Rule,
   Oas3Preprocessor,
   Oas2Rule,
@@ -16,7 +16,7 @@ import { Oas3_1Types } from './types/oas3_1';
 import { AsyncApi2Types } from './types/asyncapi2';
 import { AsyncApi3Types } from './types/asyncapi3';
 import { ArazzoTypes } from './types/arazzo';
-import {
+import type {
   BuiltInAsync2RuleId,
   BuiltInAsync3RuleId,
   BuiltInCommonOASRuleId,
@@ -24,6 +24,7 @@ import {
   BuiltInOAS2RuleId,
   BuiltInOAS3RuleId,
 } from './types/redocly-yaml';
+import { isPlainObject } from './utils';
 
 export enum SpecVersion {
   OAS2 = 'oas2',
@@ -93,8 +94,8 @@ export type Async2DecoratorsSet = Record<string, Async2Preprocessor>;
 export type Async3DecoratorsSet = Record<string, Async3Preprocessor>;
 export type ArazzoDecoratorsSet = Record<string, ArazzoPreprocessor>;
 
-export function detectSpec(root: any): SpecVersion {
-  if (typeof root !== 'object') {
+export function detectSpec(root: unknown): SpecVersion {
+  if (!isPlainObject(root)) {
     throw new Error(`Document must be JSON object, got ${typeof root}`);
   }
 
@@ -102,11 +103,11 @@ export function detectSpec(root: any): SpecVersion {
     throw new Error(`Invalid OpenAPI version: should be a string but got "${typeof root.openapi}"`);
   }
 
-  if (root.openapi && root.openapi.startsWith('3.0')) {
+  if (typeof root.openapi === 'string' && root.openapi.startsWith('3.0')) {
     return SpecVersion.OAS3_0;
   }
 
-  if (root.openapi && root.openapi.startsWith('3.1')) {
+  if (typeof root.openapi === 'string' && root.openapi.startsWith('3.1')) {
     return SpecVersion.OAS3_1;
   }
 
@@ -114,16 +115,15 @@ export function detectSpec(root: any): SpecVersion {
     return SpecVersion.OAS2;
   }
 
-  // if not detected yet
   if (root.openapi || root.swagger) {
     throw new Error(`Unsupported OpenAPI version: ${root.openapi || root.swagger}`);
   }
 
-  if (root.asyncapi && root.asyncapi.startsWith('2.')) {
+  if (typeof root.asyncapi === 'string' && root.asyncapi.startsWith('2.')) {
     return SpecVersion.Async2;
   }
 
-  if (root.asyncapi && root.asyncapi.startsWith('3.')) {
+  if (typeof root.asyncapi === 'string' && root.asyncapi.startsWith('3.')) {
     return SpecVersion.Async3;
   }
 
@@ -131,7 +131,7 @@ export function detectSpec(root: any): SpecVersion {
     throw new Error(`Unsupported AsyncAPI version: ${root.asyncapi}`);
   }
 
-  if (root.arazzo && root.arazzo.startsWith('1.')) {
+  if (typeof root.arazzo === 'string' && root.arazzo.startsWith('1.')) {
     return SpecVersion.Arazzo;
   }
 
diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts
index 35061d68..acef7aa7 100644
--- a/packages/core/src/utils.ts
+++ b/packages/core/src/utils.ts
@@ -38,15 +38,15 @@ export function isDefined<T>(x: T | undefined): x is T {
   return x !== undefined;
 }
 
-export function isPlainObject(value: any): value is Record<string, unknown> {
+export function isPlainObject(value: unknown): value is Record<string, unknown> {
   return value !== null && typeof value === 'object' && !Array.isArray(value);
 }
 
-export function isEmptyObject(value: any): value is Record<string, unknown> {
+export function isEmptyObject(value: unknown): value is Record<string, unknown> {
   return isPlainObject(value) && Object.keys(value).length === 0;
 }
 
-export function isEmptyArray(value: any) {
+export function isEmptyArray(value: unknown) {
   return Array.isArray(value) && value.length === 0;
 }
 
@@ -317,3 +317,5 @@ export function dequal(foo: any, bar: any): boolean {
 
   return foo !== foo && bar !== bar;
 }
+
+export type CollectFn = (value: unknown) => void;


Test patch:
diff --git a/packages/cli/src/__tests__/commands/build-docs.test.ts b/packages/cli/src/__tests__/commands/build-docs.test.ts
index 39583b98..37438b6e 100644
--- a/packages/cli/src/__tests__/commands/build-docs.test.ts
+++ b/packages/cli/src/__tests__/commands/build-docs.test.ts
@@ -39,8 +39,8 @@ describe('build-docs', () => {
 
   it('should work correctly when calling handlerBuildCommand', async () => {
     const processExitMock = jest.spyOn(process, 'exit').mockImplementation();
-    await handlerBuildCommand(
-      {
+    await handlerBuildCommand({
+      argv: {
         o: '',
         title: 'test',
         disableGoogleFont: false,
@@ -49,8 +49,9 @@ describe('build-docs', () => {
         theme: { openapi: {} },
         api: '../some-path/openapi.yaml',
       } as BuildDocsArgv,
-      {} as any
-    );
+      config: {} as any,
+      version: 'cli-version',
+    });
     expect(loadAndBundleSpec).toBeCalledTimes(1);
     expect(getFallbackApisOrExit).toBeCalledTimes(1);
     expect(processExitMock).toBeCalledTimes(0);
diff --git a/packages/cli/src/__tests__/commands/join.test.ts b/packages/cli/src/__tests__/commands/join.test.ts
index 3ee2caf0..8980be4c 100644
--- a/packages/cli/src/__tests__/commands/join.test.ts
+++ b/packages/cli/src/__tests__/commands/join.test.ts
@@ -14,21 +14,21 @@ describe('handleJoin', () => {
   colloreteYellowMock.mockImplementation((string: string) => string);
 
   it('should call exitWithError because only one entrypoint', async () => {
-    await handleJoin({ apis: ['first.yaml'] }, {} as any, 'cli-version');
+    await handleJoin({ argv: { apis: ['first.yaml'] }, config: {} as any, version: 'cli-version' });
     expect(exitWithError).toHaveBeenCalledWith(`At least 2 apis should be provided.`);
   });
 
   it('should call exitWithError because passed all 3 options for tags', async () => {
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml'],
         'prefix-tags-with-info-prop': 'something',
         'without-x-tag-groups': true,
         'prefix-tags-with-filename': true,
       },
-      {} as any,
-      'cli-version'
-    );
+      config: {} as any,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toHaveBeenCalledWith(
       `You use prefix-tags-with-filename, prefix-tags-with-info-prop, without-x-tag-groups together.\nPlease choose only one!`
@@ -36,15 +36,15 @@ describe('handleJoin', () => {
   });
 
   it('should call exitWithError because passed all 2 options for tags', async () => {
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml'],
         'without-x-tag-groups': true,
         'prefix-tags-with-filename': true,
       },
-      {} as any,
-      'cli-version'
-    );
+      config: {} as any,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toHaveBeenCalledWith(
       `You use prefix-tags-with-filename, without-x-tag-groups together.\nPlease choose only one!`
@@ -52,13 +52,13 @@ describe('handleJoin', () => {
   });
 
   it('should call exitWithError because Only OpenAPI 3.0 and OpenAPI 3.1 are supported', async () => {
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml'],
       },
-      ConfigFixture as any,
-      'cli-version'
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
     expect(exitWithError).toHaveBeenCalledWith(
       'Only OpenAPI 3.0 and OpenAPI 3.1 are supported: undefined.'
     );
@@ -68,13 +68,13 @@ describe('handleJoin', () => {
     (detectSpec as jest.Mock)
       .mockImplementationOnce(() => 'oas3_0')
       .mockImplementationOnce(() => 'oas3_1');
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml'],
       },
-      ConfigFixture as any,
-      'cli-version'
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toHaveBeenCalledWith(
       'All APIs must use the same OpenAPI version: undefined.'
@@ -83,13 +83,13 @@ describe('handleJoin', () => {
 
   it('should call writeToFileByExtension function', async () => {
     (detectSpec as jest.Mock).mockReturnValue('oas3_0');
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml'],
       },
-      ConfigFixture as any,
-      'cli-version'
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(writeToFileByExtension).toHaveBeenCalledWith(
       expect.any(Object),
@@ -100,13 +100,13 @@ describe('handleJoin', () => {
 
   it('should call writeToFileByExtension function for OpenAPI 3.1', async () => {
     (detectSpec as jest.Mock).mockReturnValue('oas3_1');
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml'],
       },
-      ConfigFixture as any,
-      'cli-version'
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(writeToFileByExtension).toHaveBeenCalledWith(
       expect.any(Object),
@@ -117,14 +117,14 @@ describe('handleJoin', () => {
 
   it('should call writeToFileByExtension function with custom output file', async () => {
     (detectSpec as jest.Mock).mockReturnValue('oas3_0');
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml'],
         output: 'output.yml',
       },
-      ConfigFixture as any,
-      'cli-version'
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(writeToFileByExtension).toHaveBeenCalledWith(
       expect.any(Object),
@@ -135,13 +135,13 @@ describe('handleJoin', () => {
 
   it('should call writeToFileByExtension function with json file extension', async () => {
     (detectSpec as jest.Mock).mockReturnValue('oas3_0');
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.json', 'second.yaml'],
       },
-      ConfigFixture as any,
-      'cli-version'
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(writeToFileByExtension).toHaveBeenCalledWith(
       expect.any(Object),
@@ -152,13 +152,13 @@ describe('handleJoin', () => {
 
   it('should call skipDecorators and skipPreprocessors', async () => {
     (detectSpec as jest.Mock).mockReturnValue('oas3_0');
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml'],
       },
-      ConfigFixture as any,
-      'cli-version'
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     const config = loadConfig();
     expect(config.styleguide.skipDecorators).toHaveBeenCalled();
@@ -168,15 +168,15 @@ describe('handleJoin', () => {
   it('should handle join with prefix-components-with-info-prop and null values', async () => {
     (detectSpec as jest.Mock).mockReturnValue('oas3_0');
 
-    await handleJoin(
-      {
+    await handleJoin({
+      argv: {
         apis: ['first.yaml', 'second.yaml', 'third.yaml'],
         'prefix-components-with-info-prop': 'title',
         output: 'join-result.yaml',
       },
-      ConfigFixture as any,
-      'cli-version'
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(writeToFileByExtension).toHaveBeenCalledWith(
       {
diff --git a/packages/cli/src/__tests__/commands/push-region.test.ts b/packages/cli/src/__tests__/commands/push-region.test.ts
index 8dd66631..a0e4bb18 100644
--- a/packages/cli/src/__tests__/commands/push-region.test.ts
+++ b/packages/cli/src/__tests__/commands/push-region.test.ts
@@ -28,30 +28,32 @@ describe('push-with-region', () => {
 
   it('should call login with default domain when region is US', async () => {
     redoclyClient.domain = 'redoc.ly';
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'spec.json',
         destination: '@org/my-api@1.0.0',
         branchName: 'test',
       },
-      ConfigFixture as any
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
     expect(mockPromptClientToken).toBeCalledTimes(1);
     expect(mockPromptClientToken).toHaveBeenCalledWith(redoclyClient.domain);
   });
 
   it('should call login with EU domain when region is EU', async () => {
     redoclyClient.domain = 'eu.redocly.com';
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'spec.json',
         destination: '@org/my-api@1.0.0',
         branchName: 'test',
       },
-      ConfigFixture as any
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
     expect(mockPromptClientToken).toBeCalledTimes(1);
     expect(mockPromptClientToken).toHaveBeenCalledWith(redoclyClient.domain);
   });
diff --git a/packages/cli/src/__tests__/commands/push.test.ts b/packages/cli/src/__tests__/commands/push.test.ts
index 9e98d0d6..2fe8c36d 100644
--- a/packages/cli/src/__tests__/commands/push.test.ts
+++ b/packages/cli/src/__tests__/commands/push.test.ts
@@ -25,8 +25,8 @@ describe('push', () => {
   });
 
   it('pushes definition', async () => {
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'spec.json',
         destination: '@org/my-api@1.0.0',
@@ -35,8 +35,9 @@ describe('push', () => {
         'job-id': '123',
         'batch-size': 2,
       },
-      ConfigFixture as any
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(redoclyClient.registryApi.prepareFileUpload).toBeCalledTimes(1);
     expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
@@ -55,8 +56,8 @@ describe('push', () => {
   });
 
   it('fails if jobId value is an empty string', async () => {
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'spec.json',
         destination: '@org/my-api@1.0.0',
@@ -65,15 +66,16 @@ describe('push', () => {
         'job-id': ' ',
         'batch-size': 2,
       },
-      ConfigFixture as any
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toBeCalledTimes(1);
   });
 
   it('fails if batchSize value is less than 2', async () => {
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'spec.json',
         destination: '@org/my-api@1.0.0',
@@ -82,8 +84,9 @@ describe('push', () => {
         'job-id': '123',
         'batch-size': 1,
       },
-      ConfigFixture as any
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toBeCalledTimes(1);
   });
@@ -95,16 +98,17 @@ describe('push', () => {
       return { isDirectory: () => false, size: 10 };
     });
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'spec.json',
         destination: '@org/my-api@1.0.0',
         public: true,
         files: ['./resouces/1.md', './resouces/2.md'],
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(redoclyClient.registryApi.pushApi).toHaveBeenLastCalledWith({
       filePaths: ['filePath', 'filePath', 'filePath'],
@@ -119,8 +123,8 @@ describe('push', () => {
   });
 
   it('push should fail if organization not provided', async () => {
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'spec.json',
         destination: 'test@v1',
@@ -129,8 +133,9 @@ describe('push', () => {
         'job-id': '123',
         'batch-size': 2,
       },
-      ConfigFixture as any
-    );
+      config: ConfigFixture as any,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toBeCalledTimes(1);
     expect(exitWithError).toBeCalledWith(
@@ -140,8 +145,8 @@ describe('push', () => {
 
   it('push should work with organization in config', async () => {
     const mockConfig = { ...ConfigFixture, organization: 'test_org' } as any;
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'spec.json',
         destination: 'my-api@1.0.0',
@@ -150,8 +155,9 @@ describe('push', () => {
         'job-id': '123',
         'batch-size': 2,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
     expect(redoclyClient.registryApi.pushApi).toHaveBeenLastCalledWith({
@@ -175,16 +181,17 @@ describe('push', () => {
       apis: { 'my-api@1.0.0': { root: 'path' } },
     } as any;
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         branchName: 'test',
         public: true,
         'job-id': '123',
         'batch-size': 2,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
   });
@@ -192,16 +199,17 @@ describe('push', () => {
   it('push should fail if apis not provided', async () => {
     const mockConfig = { organization: 'test_org', apis: {} } as any;
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         branchName: 'test',
         public: true,
         'job-id': '123',
         'batch-size': 2,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toBeCalledTimes(1);
     expect(exitWithError).toHaveBeenLastCalledWith(
@@ -212,8 +220,8 @@ describe('push', () => {
   it('push should fail if destination not provided', async () => {
     const mockConfig = { organization: 'test_org', apis: {} } as any;
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         api: 'api.yaml',
         branchName: 'test',
@@ -221,8 +229,9 @@ describe('push', () => {
         'job-id': '123',
         'batch-size': 2,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toBeCalledTimes(1);
     expect(exitWithError).toHaveBeenLastCalledWith(
@@ -233,8 +242,8 @@ describe('push', () => {
   it('push should fail if destination format is not valid', async () => {
     const mockConfig = { organization: 'test_org', apis: {} } as any;
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         destination: 'name/v1',
         branchName: 'test',
@@ -242,8 +251,9 @@ describe('push', () => {
         'job-id': '123',
         'batch-size': 2,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(exitWithError).toHaveBeenCalledWith(
       `Destination argument value is not valid, please use the right format: ${yellow(
@@ -261,8 +271,8 @@ describe('push', () => {
       apis: { 'my test api@v1': { root: 'path' } },
     } as any;
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         upsert: true,
         destination: 'my test api@v1',
         branchName: 'test',
@@ -270,8 +280,9 @@ describe('push', () => {
         'job-id': '123',
         'batch-size': 2,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(encodeURIComponentSpy).toHaveReturnedWith('my%20test%20api');
     expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
@@ -281,130 +292,144 @@ describe('push', () => {
 describe('transformPush', () => {
   it('should adapt the existing syntax', () => {
     const cb = jest.fn();
-    transformPush(cb)(
-      {
+    transformPush(cb)({
+      argv: {
         apis: ['openapi.yaml', '@testing_org/main@v1'],
       },
-      {} as any
-    );
-    expect(cb).toBeCalledWith(
-      {
+      config: {} as any,
+      version: 'cli-version',
+    });
+    expect(cb).toBeCalledWith({
+      argv: {
         api: 'openapi.yaml',
         destination: '@testing_org/main@v1',
       },
-      {}
-    );
+      config: {},
+      version: 'cli-version',
+    });
   });
   it('should adapt the existing syntax (including branchName)', () => {
     const cb = jest.fn();
-    transformPush(cb)(
-      {
+    transformPush(cb)({
+      argv: {
         apis: ['openapi.yaml', '@testing_org/main@v1', 'other'],
       },
-      {} as any
-    );
-    expect(cb).toBeCalledWith(
-      {
+      config: {} as any,
+      version: 'cli-version',
+    });
+    expect(cb).toBeCalledWith({
+      argv: {
         api: 'openapi.yaml',
         destination: '@testing_org/main@v1',
         branchName: 'other',
       },
-      {}
-    );
+      config: {},
+      version: 'cli-version',
+    });
   });
   it('should use --branch option firstly', () => {
     const cb = jest.fn();
-    transformPush(cb)(
-      {
+    transformPush(cb)({
+      argv: {
         apis: ['openapi.yaml', '@testing_org/main@v1', 'other'],
         branch: 'priority-branch',
       },
-      {} as any
-    );
-    expect(cb).toBeCalledWith(
-      {
+      config: {} as any,
+      version: 'cli-version',
+    });
+    expect(cb).toBeCalledWith({
+      argv: {
         api: 'openapi.yaml',
         destination: '@testing_org/main@v1',
         branchName: 'priority-branch',
       },
-      {}
-    );
+      config: {},
+      version: 'cli-version',
+    });
   });
   it('should work for a destination only', () => {
     const cb = jest.fn();
-    transformPush(cb)(
-      {
+    transformPush(cb)({
+      argv: {
         apis: ['main@v1'],
       },
-      {} as any
-    );
-    expect(cb).toBeCalledWith(
-      {
+      config: {} as any,
+      version: 'cli-version',
+    });
+    expect(cb).toBeCalledWith({
+      argv: {
         destination: 'main@v1',
       },
-      {}
-    );
+      config: {},
+      version: 'cli-version',
+    });
   });
   it('should work for a api only', () => {
     const cb = jest.fn();
-    transformPush(cb)(
-      {
+    transformPush(cb)({
+      argv: {
         apis: ['test.yaml'],
       },
-      {} as any
-    );
-    expect(cb).toBeCalledWith(
-      {
+      config: {} as any,
+      version: 'cli-version',
+    });
+    expect(cb).toBeCalledWith({
+      argv: {
         api: 'test.yaml',
       },
-      {}
-    );
+      config: {},
+      version: 'cli-version',
+    });
   });
 
   it('should use destination from option', () => {
     const cb = jest.fn();
-    transformPush(cb)(
-      {
+    transformPush(cb)({
+      argv: {
         apis: ['test.yaml', 'test@v1'],
         destination: 'main@v1',
       },
-      {} as any
-    );
-    expect(cb).toBeCalledWith(
-      {
+      config: {} as any,
+      version: 'cli-version',
+    });
+    expect(cb).toBeCalledWith({
+      argv: {
         destination: 'main@v1',
         api: 'test.yaml',
       },
-      {}
-    );
+      config: {},
+      version: 'cli-version',
+    });
   });
 
   it('should use --job-id option firstly', () => {
     const cb = jest.fn();
-    transformPush(cb)(
-      {
+    transformPush(cb)({
+      argv: {
         'batch-id': 'b-123',
         'job-id': 'j-123',
         apis: ['test'],
         branch: 'test',
         destination: 'main@v1',
       },
-      {} as any
-    );
-    expect(cb).toBeCalledWith(
-      {
+      config: {} as any,
+      version: 'cli-version',
+    });
+    expect(cb).toBeCalledWith({
+      argv: {
         'job-id': 'j-123',
         api: 'test',
         branchName: 'test',
         destination: 'main@v1',
       },
-      {}
-    );
+      config: {},
+      version: 'cli-version',
+    });
   });
   it('should accept no arguments at all', () => {
     const cb = jest.fn();
-    transformPush(cb)({}, {} as any);
-    expect(cb).toBeCalledWith({}, {});
+    transformPush(cb)({ argv: {}, config: {} as any, version: 'cli-version' });
+    expect(cb).toBeCalledWith({ argv: {}, config: {}, version: 'cli-version' });
   });
 });
 
diff --git a/packages/cli/src/__tests__/wrapper.test.ts b/packages/cli/src/__tests__/wrapper.test.ts
index d3554898..e1f85779 100644
--- a/packages/cli/src/__tests__/wrapper.test.ts
+++ b/packages/cli/src/__tests__/wrapper.test.ts
@@ -4,6 +4,7 @@ import { commandWrapper } from '../wrapper';
 import { handleLint } from '../commands/lint';
 import { Arguments } from 'yargs';
 import { handlePush, PushOptions } from '../commands/push';
+import { detectSpec } from '@redocly/openapi-core';
 
 jest.mock('node-fetch');
 jest.mock('../utils/miscellaneous', () => ({
@@ -11,7 +12,9 @@ jest.mock('../utils/miscellaneous', () => ({
   loadConfigAndHandleErrors: jest.fn(),
 }));
 jest.mock('../commands/lint', () => ({
-  handleLint: jest.fn(),
+  handleLint: jest.fn().mockImplementation(({ collectSpecData }) => {
+    collectSpecData({ openapi: '3.1.0' });
+  }),
   lintConfigCallback: jest.fn(),
 }));
 
@@ -20,13 +23,32 @@ describe('commandWrapper', () => {
     (loadConfigAndHandleErrors as jest.Mock).mockImplementation(() => {
       return { telemetry: 'on', styleguide: { recommendedFallback: true } };
     });
+    (detectSpec as jest.Mock).mockImplementationOnce(() => {
+      return 'oas3_1';
+    });
+    process.env.REDOCLY_TELEMETRY = 'on';
+
+    const wrappedHandler = commandWrapper(handleLint);
+    await wrappedHandler({} as any);
+    expect(handleLint).toHaveBeenCalledTimes(1);
+    expect(sendTelemetry).toHaveBeenCalledTimes(1);
+    expect(sendTelemetry).toHaveBeenCalledWith({}, 0, false, 'oas3_1', 'openapi', '3.1.0');
+  });
+
+  it('should not collect spec version if the file is not parsed to json', async () => {
+    (loadConfigAndHandleErrors as jest.Mock).mockImplementation(() => {
+      return { telemetry: 'on', styleguide: { recommendedFallback: true } };
+    });
+    (handleLint as jest.Mock).mockImplementation(({ collectSpecData }) => {
+      collectSpecData();
+    });
     process.env.REDOCLY_TELEMETRY = 'on';
 
     const wrappedHandler = commandWrapper(handleLint);
     await wrappedHandler({} as any);
     expect(handleLint).toHaveBeenCalledTimes(1);
     expect(sendTelemetry).toHaveBeenCalledTimes(1);
-    expect(sendTelemetry).toHaveBeenCalledWith({}, 0, false);
+    expect(sendTelemetry).toHaveBeenCalledWith({}, 0, false, undefined, undefined, undefined);
   });
 
   it('should NOT send telemetry if there is "telemetry: off" in the config', async () => {
diff --git a/packages/cli/src/cms/commands/__tests__/push-status.test.ts b/packages/cli/src/cms/commands/__tests__/push-status.test.ts
index a916485a..8bcd4cfa 100644
--- a/packages/cli/src/cms/commands/__tests__/push-status.test.ts
+++ b/packages/cli/src/cms/commands/__tests__/push-status.test.ts
@@ -85,15 +85,16 @@ describe('handlePushStatus()', () => {
 
   it('should throw error if organization not provided', async () => {
     await expect(
-      handlePushStatus(
-        {
+      handlePushStatus({
+        argv: {
           domain: 'test-domain',
           organization: '',
           project: 'test-project',
           pushId: 'test-push-id',
         },
-        mockConfig
-      )
+        config: mockConfig,
+        version: 'cli-version',
+      })
     ).rejects.toThrowErrorMatchingInlineSnapshot(
       `"No organization provided, please use --organization option or specify the 'organization' field in the config file."`
     );
@@ -108,15 +109,16 @@ describe('handlePushStatus()', () => {
     process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
     remotes.getPush.mockResolvedValueOnce(pushResponseStub);
 
-    await handlePushStatus(
-      {
+    await handlePushStatus({
+      argv: {
         domain: 'test-domain',
         organization: 'test-org',
         project: 'test-project',
         pushId: 'test-push-id',
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
     expect(process.stdout.write).toHaveBeenCalledTimes(1);
     expect(process.stdout.write).toHaveBeenCalledWith(
       '🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
@@ -127,15 +129,16 @@ describe('handlePushStatus()', () => {
     process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
     remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: true });
 
-    await handlePushStatus(
-      {
+    await handlePushStatus({
+      argv: {
         domain: 'test-domain',
         organization: 'test-org',
         project: 'test-project',
         pushId: 'test-push-id',
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
     expect(process.stdout.write).toHaveBeenCalledTimes(2);
     expect(process.stdout.write).toHaveBeenCalledWith(
       '🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
@@ -157,15 +160,16 @@ describe('handlePushStatus()', () => {
     });
 
     await expect(
-      handlePushStatus(
-        {
+      handlePushStatus({
+        argv: {
           domain: 'test-domain',
           organization: 'test-org',
           project: 'test-project',
           pushId: 'test-push-id',
         },
-        mockConfig
-      )
+        config: mockConfig,
+        version: 'cli-version',
+      })
     ).rejects.toThrowErrorMatchingInlineSnapshot(`
       "❌ Preview deploy fail.
       Preview URL: https://preview-test-url"
@@ -197,15 +201,16 @@ describe('handlePushStatus()', () => {
       },
     });
 
-    await handlePushStatus(
-      {
+    await handlePushStatus({
+      argv: {
         domain: 'test-domain',
         organization: 'test-org',
         project: 'test-project',
         pushId: 'test-push-id',
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
     expect(process.stdout.write).toHaveBeenCalledTimes(4);
     expect(process.stdout.write).toHaveBeenCalledWith(
       '🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
@@ -232,16 +237,17 @@ describe('handlePushStatus()', () => {
       },
     });
 
-    await handlePushStatus(
-      {
+    await handlePushStatus({
+      argv: {
         domain: 'test-domain',
         organization: 'test-org',
         project: 'test-project',
         pushId: 'test-push-id',
         wait: true,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(process.stderr.write).toHaveBeenCalledWith(
       'Files not added to your project. Reason: no changes.\n'
@@ -253,15 +259,16 @@ describe('handlePushStatus()', () => {
       process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
       remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: false });
 
-      const result = await handlePushStatus(
-        {
+      const result = await handlePushStatus({
+        argv: {
           domain: 'test-domain',
           organization: 'test-org',
           project: 'test-project',
           pushId: 'test-push-id',
         },
-        mockConfig
-      );
+        config: mockConfig,
+        version: 'cli-version',
+      });
 
       expect(result).toEqual({
         preview: {
@@ -280,15 +287,16 @@ describe('handlePushStatus()', () => {
       process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
       remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: true });
 
-      const result = await handlePushStatus(
-        {
+      const result = await handlePushStatus({
+        argv: {
           domain: 'test-domain',
           organization: 'test-org',
           project: 'test-project',
           pushId: 'test-push-id',
         },
-        mockConfig
-      );
+        config: mockConfig,
+        version: 'cli-version',
+      });
 
       expect(result).toEqual({
         preview: {
@@ -344,8 +352,8 @@ describe('handlePushStatus()', () => {
         },
       });
 
-      const result = await handlePushStatus(
-        {
+      const result = await handlePushStatus({
+        argv: {
           domain: 'test-domain',
           organization: 'test-org',
           project: 'test-project',
@@ -353,8 +361,9 @@ describe('handlePushStatus()', () => {
           'retry-interval': 0.5, // 500 ms
           wait: true,
         },
-        mockConfig
-      );
+        config: mockConfig,
+        version: 'cli-version',
+      });
 
       expect(result).toEqual({
         preview: {
@@ -417,8 +426,8 @@ describe('handlePushStatus()', () => {
         },
       });
 
-      const result = await handlePushStatus(
-        {
+      const result = await handlePushStatus({
+        argv: {
           domain: 'test-domain',
           organization: 'test-org',
           project: 'test-project',
@@ -426,8 +435,9 @@ describe('handlePushStatus()', () => {
           'retry-interval': 0.5, // 500 ms
           wait: true,
         },
-        mockConfig
-      );
+        config: mockConfig,
+        version: 'cli-version',
+      });
 
       expect(result).toEqual({
         preview: {
@@ -458,16 +468,17 @@ describe('handlePushStatus()', () => {
       });
 
       await expect(
-        handlePushStatus(
-          {
+        handlePushStatus({
+          argv: {
             domain: 'test-domain',
             organization: 'test-org',
             project: 'test-project',
             pushId: 'test-push-id',
             'continue-on-deploy-failures': false,
           },
-          mockConfig
-        )
+          config: mockConfig,
+          version: 'cli-version',
+        })
       ).rejects.toThrowErrorMatchingInlineSnapshot(`
         "❌ Preview deploy fail.
         Preview URL: https://preview-test-url"
@@ -488,16 +499,17 @@ describe('handlePushStatus()', () => {
       });
 
       await expect(
-        handlePushStatus(
-          {
+        handlePushStatus({
+          argv: {
             domain: 'test-domain',
             organization: 'test-org',
             project: 'test-project',
             pushId: 'test-push-id',
             'continue-on-deploy-failures': true,
           },
-          mockConfig
-        )
+          config: mockConfig,
+          version: 'cli-version',
+        })
       ).resolves.toStrictEqual({
         preview: {
           deploy: { status: 'failed', url: 'https://preview-test-url' },
@@ -545,8 +557,8 @@ describe('handlePushStatus()', () => {
 
       const onRetrySpy = jest.fn();
 
-      const result = await handlePushStatus(
-        {
+      const result = await handlePushStatus({
+        argv: {
           domain: 'test-domain',
           organization: 'test-org',
           project: 'test-project',
@@ -555,8 +567,9 @@ describe('handlePushStatus()', () => {
           'retry-interval': 0.5, // 500 ms
           onRetry: onRetrySpy,
         },
-        mockConfig
-      );
+        config: mockConfig,
+        version: 'cli-version',
+      });
 
       expect(onRetrySpy).toBeCalledTimes(2);
 
@@ -617,8 +630,8 @@ describe('handlePushStatus()', () => {
       });
 
       await expect(
-        handlePushStatus(
-          {
+        handlePushStatus({
+          argv: {
             domain: 'test-domain',
             organization: 'test-org',
             project: 'test-project',
@@ -627,8 +640,9 @@ describe('handlePushStatus()', () => {
             'max-execution-time': 1, // seconds
             wait: true,
           },
-          mockConfig
-        )
+          config: mockConfig,
+          version: 'cli-version',
+        })
       ).rejects.toThrowErrorMatchingInlineSnapshot(`
         "✗ Failed to get push status. Reason: Timeout exceeded
         "
diff --git a/packages/cli/src/cms/commands/__tests__/push.test.ts b/packages/cli/src/cms/commands/__tests__/push.test.ts
index 940db714..2ac0845d 100644
--- a/packages/cli/src/cms/commands/__tests__/push.test.ts
+++ b/packages/cli/src/cms/commands/__tests__/push.test.ts
@@ -63,8 +63,8 @@ describe('handlePush()', () => {
     pathRelativeSpy.mockImplementationOnce((_, p) => p);
     pathDirnameSpy.mockImplementation((_: string) => '.');
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         domain: 'test-domain',
         'mount-path': 'test-mount-path',
         organization: 'test-org',
@@ -81,8 +81,9 @@ describe('handlePush()', () => {
         files: ['test-file'],
         'max-execution-time': 10,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(remotes.getDefaultBranch).toHaveBeenCalledWith('test-org', 'test-project');
     expect(remotes.upsert).toHaveBeenCalledWith('test-org', 'test-project', {
@@ -132,8 +133,8 @@ describe('handlePush()', () => {
     pathRelativeSpy.mockImplementationOnce((_, p) => p);
     pathDirnameSpy.mockImplementation((_: string) => '.');
 
-    const result = await handlePush(
-      {
+    const result = await handlePush({
+      argv: {
         domain: 'test-domain',
         'mount-path': 'test-mount-path',
         organization: 'test-org',
@@ -150,8 +151,9 @@ describe('handlePush()', () => {
         files: ['test-file'],
         'max-execution-time': 10,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(result).toEqual({ pushId: 'test-id' });
   });
@@ -188,8 +190,8 @@ describe('handlePush()', () => {
       throw new Error('Not a directory');
     });
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         domain: 'test-domain',
         'mount-path': 'test-mount-path',
         organization: 'test-org',
@@ -201,8 +203,9 @@ describe('handlePush()', () => {
         files: ['test-folder'],
         'max-execution-time': 10,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(remotes.push).toHaveBeenCalledWith(
       expect.anything(),
@@ -230,8 +233,8 @@ describe('handlePush()', () => {
     const mockConfig = { apis: {} } as any;
     process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         domain: 'test-domain',
         'mount-path': 'test-mount-path',
         organization: 'test-org',
@@ -243,8 +246,9 @@ describe('handlePush()', () => {
         files: [],
         'max-execution-time': 10,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(remotes.getDefaultBranch).not.toHaveBeenCalled();
     expect(remotes.upsert).not.toHaveBeenCalled();
@@ -265,8 +269,8 @@ describe('handlePush()', () => {
     pathRelativeSpy.mockImplementationOnce((_, p) => p);
     pathDirnameSpy.mockImplementation((_: string) => '.');
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         domain: 'test-domain',
         'mount-path': 'test-mount-path',
         project: 'test-project',
@@ -277,8 +281,9 @@ describe('handlePush()', () => {
         'default-branch': 'main',
         'max-execution-time': 10,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(remotes.getDefaultBranch).toHaveBeenCalledWith(
       'test-org-from-config',
@@ -312,8 +317,8 @@ describe('handlePush()', () => {
     pathRelativeSpy.mockImplementationOnce((_, p) => p);
     pathDirnameSpy.mockImplementation((_: string) => '.');
 
-    await handlePush(
-      {
+    await handlePush({
+      argv: {
         'mount-path': 'test-mount-path',
         project: 'test-project',
         branch: 'test-branch',
@@ -323,8 +328,9 @@ describe('handlePush()', () => {
         files: ['test-file'],
         'max-execution-time': 10,
       },
-      mockConfig
-    );
+      config: mockConfig,
+      version: 'cli-version',
+    });
 
     expect(ReuniteApiClient).toBeCalledWith('test-domain-from-env', 'test-api-key');
   });
diff --git a/packages/cli/src/commands/split/__tests__/index.test.ts b/packages/cli/src/commands/split/__tests__/index.test.ts
index b29e5bc2..88ff1534 100644
--- a/packages/cli/src/commands/split/__tests__/index.test.ts
+++ b/packages/cli/src/commands/split/__tests__/index.test.ts
@@ -3,6 +3,9 @@ import * as path from 'path';
 import * as openapiCore from '@redocly/openapi-core';
 import { ComponentsFiles } from '../types';
 import { blue, green } from 'colorette';
+import { loadConfigAndHandleErrors } from '../../../utils/__mocks__/miscellaneous';
+
+import type { Config } from '@redocly/openapi-core';
 
 const utils = require('../../../utils/miscellaneous');
 
@@ -25,9 +28,13 @@ describe('#split', () => {
     jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
 
     await handleSplit({
-      api: filePath,
-      outDir: openapiDir,
-      separator: '_',
+      argv: {
+        api: filePath,
+        outDir: openapiDir,
+        separator: '_',
+      },
+      config: loadConfigAndHandleErrors() as any as Config,
+      version: 'cli-version',
     });
 
     expect(process.stderr.write).toBeCalledTimes(2);
@@ -46,9 +53,13 @@ describe('#split', () => {
     jest.spyOn(utils, 'pathToFilename').mockImplementation(() => 'newFilePath');
 
     await handleSplit({
-      api: filePath,
-      outDir: openapiDir,
-      separator: '_',
+      argv: {
+        api: filePath,
+        outDir: openapiDir,
+        separator: '_',
+      },
+      config: loadConfigAndHandleErrors() as any as Config,
+      version: 'cli-version',
     });
 
     expect(utils.pathToFilename).toBeCalledWith(expect.anything(), '_');