@redocly/cli 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/lib/__tests__/commands/build-docs.test.js +3 -3
  3. package/lib/__tests__/commands/bundle.test.js +5 -5
  4. package/lib/__tests__/commands/join.test.js +11 -11
  5. package/lib/__tests__/commands/lint.test.js +14 -14
  6. package/lib/__tests__/commands/push-region.test.js +1 -1
  7. package/lib/__tests__/commands/push.test.js +11 -11
  8. package/lib/__tests__/fetch-with-timeout.test.js +4 -13
  9. package/lib/__tests__/spinner.test.js +43 -0
  10. package/lib/__tests__/utils.test.js +36 -36
  11. package/lib/__tests__/wrapper.test.js +8 -8
  12. package/lib/cms/api/__tests__/api-keys.test.d.ts +1 -0
  13. package/lib/cms/api/__tests__/api-keys.test.js +26 -0
  14. package/lib/cms/api/__tests__/api.client.test.d.ts +1 -0
  15. package/lib/cms/api/__tests__/api.client.test.js +217 -0
  16. package/lib/cms/api/__tests__/domains.test.d.ts +1 -0
  17. package/lib/cms/api/__tests__/domains.test.js +13 -0
  18. package/lib/cms/api/api-client.d.ts +50 -0
  19. package/lib/cms/api/api-client.js +148 -0
  20. package/lib/cms/api/api-keys.d.ts +1 -0
  21. package/lib/cms/api/api-keys.js +24 -0
  22. package/lib/cms/api/domains.d.ts +1 -0
  23. package/lib/cms/api/domains.js +12 -0
  24. package/lib/cms/api/index.d.ts +3 -0
  25. package/lib/cms/api/index.js +19 -0
  26. package/lib/cms/api/types.d.ts +91 -0
  27. package/lib/cms/api/types.js +2 -0
  28. package/lib/cms/commands/__tests__/push-status.test.d.ts +1 -0
  29. package/lib/cms/commands/__tests__/push-status.test.js +164 -0
  30. package/lib/cms/commands/__tests__/push.test.d.ts +1 -0
  31. package/lib/cms/commands/__tests__/push.test.js +226 -0
  32. package/lib/cms/commands/push-status.d.ts +12 -0
  33. package/lib/cms/commands/push-status.js +150 -0
  34. package/lib/cms/commands/push.d.ts +23 -0
  35. package/lib/cms/commands/push.js +142 -0
  36. package/lib/cms/utils.d.ts +2 -0
  37. package/lib/cms/utils.js +6 -0
  38. package/lib/commands/build-docs/index.js +4 -4
  39. package/lib/commands/build-docs/utils.js +2 -2
  40. package/lib/commands/bundle.js +13 -13
  41. package/lib/commands/join.js +25 -25
  42. package/lib/commands/lint.js +10 -10
  43. package/lib/commands/login.js +2 -2
  44. package/lib/commands/preview-docs/index.js +4 -4
  45. package/lib/commands/preview-docs/preview-server/preview-server.js +2 -2
  46. package/lib/commands/preview-project/types.d.ts +1 -1
  47. package/lib/commands/push.d.ts +5 -0
  48. package/lib/commands/push.js +25 -17
  49. package/lib/commands/split/__tests__/index.test.js +2 -2
  50. package/lib/commands/split/index.js +17 -17
  51. package/lib/commands/stats.js +4 -4
  52. package/lib/index.d.ts +1 -1
  53. package/lib/index.js +130 -17
  54. package/lib/types.d.ts +8 -1
  55. package/lib/{__mocks__/utils.js → utils/__mocks__/miscellaneous.js} +1 -1
  56. package/lib/utils/assert-node-version.d.ts +1 -0
  57. package/lib/{fetch-with-timeout.js → utils/fetch-with-timeout.js} +2 -7
  58. package/lib/{utils.d.ts → utils/miscellaneous.d.ts} +1 -1
  59. package/lib/{utils.js → utils/miscellaneous.js} +2 -2
  60. package/lib/utils/spinner.d.ts +10 -0
  61. package/lib/utils/spinner.js +42 -0
  62. package/lib/{update-version-notifier.js → utils/update-version-notifier.js} +4 -4
  63. package/lib/wrapper.js +5 -5
  64. package/package.json +5 -3
  65. package/src/__tests__/commands/build-docs.test.ts +2 -2
  66. package/src/__tests__/commands/bundle.test.ts +2 -2
  67. package/src/__tests__/commands/join.test.ts +2 -2
  68. package/src/__tests__/commands/lint.test.ts +3 -3
  69. package/src/__tests__/commands/push-region.test.ts +1 -1
  70. package/src/__tests__/commands/push.test.ts +2 -2
  71. package/src/__tests__/fetch-with-timeout.test.ts +4 -16
  72. package/src/__tests__/spinner.test.ts +51 -0
  73. package/src/__tests__/utils.test.ts +2 -5
  74. package/src/__tests__/wrapper.test.ts +2 -2
  75. package/src/cms/api/__tests__/api-keys.test.ts +37 -0
  76. package/src/cms/api/__tests__/api.client.test.ts +275 -0
  77. package/src/cms/api/__tests__/domains.test.ts +15 -0
  78. package/src/cms/api/api-client.ts +199 -0
  79. package/src/cms/api/api-keys.ts +26 -0
  80. package/src/cms/api/domains.ts +11 -0
  81. package/src/cms/api/index.ts +3 -0
  82. package/src/cms/api/types.ts +101 -0
  83. package/src/cms/commands/__tests__/push-status.test.ts +212 -0
  84. package/src/cms/commands/__tests__/push.test.ts +293 -0
  85. package/src/cms/commands/push-status.ts +203 -0
  86. package/src/cms/commands/push.ts +215 -0
  87. package/src/cms/utils.ts +1 -0
  88. package/src/commands/build-docs/index.ts +1 -1
  89. package/src/commands/build-docs/utils.ts +1 -1
  90. package/src/commands/bundle.ts +2 -2
  91. package/src/commands/join.ts +2 -2
  92. package/src/commands/lint.ts +1 -1
  93. package/src/commands/login.ts +1 -1
  94. package/src/commands/preview-docs/index.ts +5 -1
  95. package/src/commands/preview-docs/preview-server/preview-server.ts +1 -1
  96. package/src/commands/preview-project/types.ts +1 -1
  97. package/src/commands/push.ts +15 -1
  98. package/src/commands/split/__tests__/index.test.ts +3 -4
  99. package/src/commands/split/index.ts +2 -2
  100. package/src/commands/stats.ts +2 -2
  101. package/src/index.ts +138 -20
  102. package/src/types.ts +8 -0
  103. package/src/{__mocks__/utils.ts → utils/__mocks__/miscellaneous.ts} +1 -1
  104. package/src/{fetch-with-timeout.ts → utils/fetch-with-timeout.ts} +1 -6
  105. package/src/{utils.ts → utils/miscellaneous.ts} +2 -2
  106. package/src/utils/spinner.ts +50 -0
  107. package/src/{update-version-notifier.ts → utils/update-version-notifier.ts} +2 -2
  108. package/src/wrapper.ts +7 -2
  109. package/tsconfig.tsbuildinfo +1 -1
  110. /package/lib/{assert-node-version.d.ts → __tests__/spinner.test.d.ts} +0 -0
  111. /package/lib/{__mocks__/utils.d.ts → utils/__mocks__/miscellaneous.d.ts} +0 -0
  112. /package/lib/{assert-node-version.js → utils/assert-node-version.js} +0 -0
  113. /package/lib/{fetch-with-timeout.d.ts → utils/fetch-with-timeout.d.ts} +0 -0
  114. /package/lib/{js-utils.d.ts → utils/js-utils.d.ts} +0 -0
  115. /package/lib/{js-utils.js → utils/js-utils.js} +0 -0
  116. /package/lib/{update-version-notifier.d.ts → utils/update-version-notifier.d.ts} +0 -0
  117. /package/src/{assert-node-version.ts → utils/assert-node-version.ts} +0 -0
  118. /package/src/{js-utils.ts → utils/js-utils.ts} +0 -0
@@ -0,0 +1,203 @@
1
+ import * as colors from 'colorette';
2
+ import { Config } from '@redocly/openapi-core';
3
+ import { exitWithError, printExecutionTime } from '../../utils/miscellaneous';
4
+ import { Spinner } from '../../utils/spinner';
5
+ import { DeploymentError } from '../utils';
6
+ import { yellow } from 'colorette';
7
+ import { ReuniteApiClient, getApiKeys, getDomain } from '../api';
8
+
9
+ import type { DeploymentStatus, PushResponse, ScorecardItem } from '../api/types';
10
+
11
+ const INTERVAL = 5000;
12
+
13
+ export type PushStatusOptions = {
14
+ organization: string;
15
+ project: string;
16
+ pushId: string;
17
+ domain?: string;
18
+ config?: string;
19
+ format?: 'stylish' | 'json';
20
+ wait?: boolean;
21
+ 'max-execution-time': number;
22
+ };
23
+
24
+ export async function handlePushStatus(argv: PushStatusOptions, config: Config) {
25
+ const startedAt = performance.now();
26
+ const spinner = new Spinner();
27
+
28
+ const { organization, project: projectId, pushId, wait } = argv;
29
+
30
+ const orgId = organization || config.organization;
31
+
32
+ if (!orgId) {
33
+ return exitWithError(
34
+ `No organization provided, please use --organization option or specify the 'organization' field in the config file.`
35
+ );
36
+ }
37
+
38
+ const domain = argv.domain || getDomain();
39
+
40
+ if (!domain) {
41
+ return exitWithError(
42
+ `No domain provided, please use --domain option or environment variable REDOCLY_DOMAIN.`
43
+ );
44
+ }
45
+
46
+ const maxExecutionTime = argv['max-execution-time'] || 600;
47
+
48
+ try {
49
+ const apiKey = getApiKeys(domain);
50
+ const client = new ReuniteApiClient(domain, apiKey);
51
+
52
+ if (wait) {
53
+ const push = await waitForDeployment(client, 'preview');
54
+
55
+ if (push.isMainBranch && push.status.preview.deploy.status === 'success') {
56
+ await waitForDeployment(client, 'production');
57
+ }
58
+
59
+ printPushStatusInfo();
60
+ return;
61
+ }
62
+
63
+ const pushPreview = await getAndPrintPushStatus(client, 'preview');
64
+ printScorecard(pushPreview.status.preview.scorecard);
65
+
66
+ if (pushPreview.isMainBranch) {
67
+ await getAndPrintPushStatus(client, 'production');
68
+ printScorecard(pushPreview.status.production.scorecard);
69
+ }
70
+
71
+ printPushStatusInfo();
72
+ } catch (err) {
73
+ const message =
74
+ err instanceof DeploymentError
75
+ ? err.message
76
+ : `✗ Failed to get push status. Reason: ${err.message}\n`;
77
+ exitWithError(message);
78
+ }
79
+
80
+ function printPushStatusInfo() {
81
+ process.stderr.write(
82
+ `\nProcessed push-status for ${colors.yellow(orgId!)}, ${colors.yellow(
83
+ projectId
84
+ )} and pushID ${colors.yellow(pushId)}.\n`
85
+ );
86
+ printExecutionTime('push-status', startedAt, 'Finished');
87
+ }
88
+
89
+ async function waitForDeployment(
90
+ client: ReuniteApiClient,
91
+ buildType: 'preview' | 'production'
92
+ ): Promise<PushResponse> {
93
+ return new Promise((resolve, reject) => {
94
+ if (performance.now() - startedAt > maxExecutionTime * 1000) {
95
+ spinner.stop();
96
+ reject(new Error(`Time limit exceeded.`));
97
+ }
98
+
99
+ getAndPrintPushStatus(client, buildType)
100
+ .then((push) => {
101
+ if (!['pending', 'running'].includes(push.status[buildType].deploy.status)) {
102
+ printScorecard(push.status[buildType].scorecard);
103
+ resolve(push);
104
+ return;
105
+ }
106
+
107
+ setTimeout(async () => {
108
+ try {
109
+ const pushResponse = await waitForDeployment(client, buildType);
110
+ resolve(pushResponse);
111
+ } catch (e) {
112
+ reject(e);
113
+ }
114
+ }, INTERVAL);
115
+ })
116
+ .catch(reject);
117
+ });
118
+ }
119
+
120
+ async function getAndPrintPushStatus(
121
+ client: ReuniteApiClient,
122
+ buildType: 'preview' | 'production'
123
+ ) {
124
+ const push = await client.remotes.getPush({
125
+ organizationId: orgId!,
126
+ projectId,
127
+ pushId,
128
+ });
129
+
130
+ if (push.isOutdated || !push.hasChanges) {
131
+ process.stderr.write(
132
+ yellow(`Files not uploaded. Reason: ${push.isOutdated ? 'outdated' : 'no changes'}.\n`)
133
+ );
134
+ } else {
135
+ displayDeploymentAndBuildStatus({
136
+ status: push.status[buildType].deploy.status,
137
+ previewUrl: push.status[buildType].deploy.url,
138
+ buildType,
139
+ spinner,
140
+ wait,
141
+ });
142
+ }
143
+
144
+ return push;
145
+ }
146
+ }
147
+
148
+ function printScorecard(scorecard: ScorecardItem[]) {
149
+ if (!scorecard.length) {
150
+ return;
151
+ }
152
+ process.stdout.write(`\n${colors.magenta('Scorecard')}:`);
153
+ for (const scorecardItem of scorecard) {
154
+ process.stdout.write(`
155
+ ${colors.magenta('Name')}: ${scorecardItem.name}
156
+ ${colors.magenta('Status')}: ${scorecardItem.status}
157
+ ${colors.magenta('URL')}: ${colors.cyan(scorecardItem.url)}
158
+ ${colors.magenta('Description')}: ${scorecardItem.description}\n`);
159
+ }
160
+ process.stdout.write(`\n`);
161
+ }
162
+
163
+ function displayDeploymentAndBuildStatus({
164
+ status,
165
+ previewUrl,
166
+ spinner,
167
+ buildType,
168
+ wait,
169
+ }: {
170
+ status: DeploymentStatus;
171
+ previewUrl: string | null;
172
+ spinner: Spinner;
173
+ buildType: 'preview' | 'production';
174
+ wait?: boolean;
175
+ }) {
176
+ switch (status) {
177
+ case 'success':
178
+ spinner.stop();
179
+ return process.stdout.write(
180
+ `${colors.green(
181
+ `🚀 ${buildType.toLocaleUpperCase()} deployment succeeded.`
182
+ )}\n${colors.magenta('Preview URL')}: ${colors.cyan(previewUrl!)}\n`
183
+ );
184
+ case 'failed':
185
+ spinner.stop();
186
+ throw new DeploymentError(
187
+ `${colors.red(`❌ ${buildType.toLocaleUpperCase()} deployment failed.`)}\n${colors.magenta(
188
+ 'Preview URL'
189
+ )}: ${colors.cyan(previewUrl!)}`
190
+ );
191
+ case 'pending':
192
+ return wait
193
+ ? spinner.start(`${colors.yellow(`Pending ${buildType}`)}`)
194
+ : process.stdout.write(`Status: ${colors.yellow(`Pending ${buildType}`)}\n`);
195
+ case 'skipped':
196
+ spinner.stop();
197
+ return process.stdout.write(`${colors.yellow(`Skipped ${buildType}`)}\n`);
198
+ case 'running':
199
+ return wait
200
+ ? spinner.start(`${colors.yellow(`Running ${buildType}`)}`)
201
+ : process.stdout.write(`Status: ${colors.yellow(`Running ${buildType}`)}\n`);
202
+ }
203
+ }
@@ -0,0 +1,215 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { Config, slash } from '@redocly/openapi-core';
4
+ import { exitWithError, HandledError, printExecutionTime } from '../../utils/miscellaneous';
5
+ import { green, yellow } from 'colorette';
6
+ import pluralize = require('pluralize');
7
+ import { handlePushStatus } from './push-status';
8
+ import { ReuniteApiClient, getDomain, getApiKeys } from '../api';
9
+
10
+ export type PushOptions = {
11
+ apis?: string[];
12
+ organization?: string;
13
+ project: string;
14
+ 'mount-path': string;
15
+
16
+ branch: string;
17
+ author: string;
18
+ message: string;
19
+ 'commit-sha'?: string;
20
+ 'commit-url'?: string;
21
+ namespace?: string;
22
+ repository?: string;
23
+ 'created-at'?: string;
24
+
25
+ files: string[];
26
+
27
+ 'default-branch': string;
28
+ domain?: string;
29
+ config?: string;
30
+ 'wait-for-deployment'?: boolean;
31
+ 'max-execution-time': number;
32
+ verbose?: boolean;
33
+ };
34
+
35
+ type FileToUpload = { name: string; path: string };
36
+
37
+ export async function handlePush(argv: PushOptions, config: Config) {
38
+ const startedAt = performance.now();
39
+ const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
40
+
41
+ const orgId = organization || config.organization;
42
+
43
+ if (!argv.message || !argv.author || !argv.branch) {
44
+ exitWithError('Error: message, author and branch are required for push to the CMS');
45
+ }
46
+
47
+ if (!orgId) {
48
+ return exitWithError(
49
+ `No organization provided, please use --organization option or specify the 'organization' field in the config file.`
50
+ );
51
+ }
52
+
53
+ const domain = argv.domain || getDomain();
54
+
55
+ if (!domain) {
56
+ return exitWithError(
57
+ `No domain provided, please use --domain option or environment variable REDOCLY_AUTHORIZATION.`
58
+ );
59
+ }
60
+
61
+ try {
62
+ const {
63
+ 'commit-sha': commitSha,
64
+ 'commit-url': commitUrl,
65
+ 'default-branch': defaultBranch,
66
+ 'wait-for-deployment': waitForDeployment,
67
+ 'max-execution-time': maxExecutionTime,
68
+ } = argv;
69
+ const author = parseCommitAuthor(argv.author);
70
+ const apiKey = getApiKeys(domain);
71
+ const filesToUpload = collectFilesToPush(argv.files || argv.apis);
72
+
73
+ if (!filesToUpload.length) {
74
+ return printExecutionTime('push', startedAt, `No files to upload`);
75
+ }
76
+
77
+ const client = new ReuniteApiClient(domain, apiKey);
78
+ const projectDefaultBranch = await client.remotes.getDefaultBranch(orgId, projectId);
79
+ const remote = await client.remotes.upsert(orgId, projectId, {
80
+ mountBranchName: projectDefaultBranch,
81
+ mountPath,
82
+ });
83
+
84
+ process.stderr.write(
85
+ `Uploading to ${remote.mountPath} ${filesToUpload.length} ${pluralize(
86
+ 'file',
87
+ filesToUpload.length
88
+ )}:\n`
89
+ );
90
+
91
+ const { id } = await client.remotes.push(
92
+ orgId,
93
+ projectId,
94
+ {
95
+ remoteId: remote.id,
96
+ commit: {
97
+ message: argv.message,
98
+ branchName: argv.branch,
99
+ sha: commitSha,
100
+ url: commitUrl,
101
+ createdAt: argv['created-at'],
102
+ namespace: argv.namespace,
103
+ repository: argv.repository,
104
+ author,
105
+ },
106
+ isMainBranch: defaultBranch === argv.branch,
107
+ },
108
+ filesToUpload.map((f) => ({ path: slash(f.name), stream: fs.createReadStream(f.path) }))
109
+ );
110
+
111
+ filesToUpload.forEach((f) => {
112
+ process.stderr.write(green(`✓ ${f.name}\n`));
113
+ });
114
+ process.stdout.write('\n');
115
+
116
+ process.stdout.write(`Push ID: ${id}\n`);
117
+
118
+ if (waitForDeployment) {
119
+ process.stdout.write('\n');
120
+
121
+ await handlePushStatus(
122
+ {
123
+ organization: orgId,
124
+ project: projectId,
125
+ pushId: id,
126
+ wait: true,
127
+ domain,
128
+ 'max-execution-time': maxExecutionTime,
129
+ },
130
+ config
131
+ );
132
+ }
133
+ verbose &&
134
+ printExecutionTime(
135
+ 'push',
136
+ startedAt,
137
+ `${pluralize(
138
+ 'file',
139
+ filesToUpload.length
140
+ )} uploaded to organization ${orgId}, project ${projectId}. Push ID: ${id}.`
141
+ );
142
+ } catch (err) {
143
+ const message =
144
+ err instanceof HandledError ? '' : `✗ File upload failed. Reason: ${err.message}`;
145
+ exitWithError(message);
146
+ }
147
+ }
148
+
149
+ function parseCommitAuthor(author: string): { name: string; email: string } {
150
+ // Author Name <author@email.com>
151
+ const reg = /^.+\s<[^<>]+>$/;
152
+
153
+ if (!reg.test(author)) {
154
+ throw new Error('Invalid author format. Use "Author Name <author@email.com>"');
155
+ }
156
+
157
+ const [name, email] = author.split('<');
158
+
159
+ return {
160
+ name: name.trim(),
161
+ email: email.replace('>', '').trim(),
162
+ };
163
+ }
164
+
165
+ function collectFilesToPush(files: string[]): FileToUpload[] {
166
+ const collectedFiles: Record<string, string> = {};
167
+
168
+ for (const file of files) {
169
+ if (fs.statSync(file).isDirectory()) {
170
+ const dir = file;
171
+ const fileList = getFilesList(dir, []);
172
+
173
+ fileList.forEach((f) => addFile(f, dir));
174
+ } else {
175
+ addFile(file, path.dirname(file));
176
+ }
177
+ }
178
+
179
+ function addFile(filePath: string, fileDir: string) {
180
+ const fileName = path.relative(fileDir, filePath);
181
+
182
+ if (collectedFiles[fileName]) {
183
+ process.stdout.write(
184
+ yellow(`File ${collectedFiles[fileName]} is overwritten by ${filePath}\n`)
185
+ );
186
+ }
187
+
188
+ collectedFiles[fileName] = filePath;
189
+ }
190
+
191
+ return Object.entries(collectedFiles).map(([name, filePath]) => getFileEntry(name, filePath));
192
+ }
193
+
194
+ function getFileEntry(name: string, filePath: string): FileToUpload {
195
+ return {
196
+ name,
197
+ path: path.resolve(filePath),
198
+ };
199
+ }
200
+
201
+ function getFilesList(dir: string, files: string[]): string[] {
202
+ const filesAndDirs = fs.readdirSync(dir);
203
+
204
+ for (const name of filesAndDirs) {
205
+ const currentPath = path.join(dir, name);
206
+
207
+ if (fs.statSync(currentPath).isDirectory()) {
208
+ files = getFilesList(currentPath, files);
209
+ } else {
210
+ files.push(currentPath);
211
+ }
212
+ }
213
+
214
+ return files;
215
+ }
@@ -0,0 +1 @@
1
+ export class DeploymentError extends Error {}
@@ -6,7 +6,7 @@ import { performance } from 'perf_hooks';
6
6
  import { getObjectOrJSON, getPageHTML } from './utils';
7
7
  import type { BuildDocsArgv } from './types';
8
8
  import { Config, getMergedConfig, isAbsoluteUrl } from '@redocly/openapi-core';
9
- import { exitWithError, getExecutionTime, getFallbackApisOrExit } from '../../utils';
9
+ import { exitWithError, getExecutionTime, getFallbackApisOrExit } from '../../utils/miscellaneous';
10
10
 
11
11
  export const handlerBuildCommand = async (argv: BuildDocsArgv, configFromFile: Config) => {
12
12
  const startedAt = performance.now();
@@ -10,7 +10,7 @@ import { existsSync, lstatSync, readFileSync } from 'fs';
10
10
 
11
11
  import type { BuildDocsOptions } from './types';
12
12
  import { red } from 'colorette';
13
- import { exitWithError } from '../../utils';
13
+ import { exitWithError } from '../../utils/miscellaneous';
14
14
 
15
15
  export function getObjectOrJSON(
16
16
  openapiOptions: string | Record<string, unknown>,
@@ -18,12 +18,12 @@ import {
18
18
  printLintTotals,
19
19
  checkIfRulesetExist,
20
20
  sortTopLevelKeysForOas,
21
- } from '../utils';
21
+ } from '../utils/miscellaneous';
22
22
  import type { OutputExtensions, Skips, Totals } from '../types';
23
23
  import { performance } from 'perf_hooks';
24
24
  import { blue, gray, green, yellow } from 'colorette';
25
25
  import { writeFileSync } from 'fs';
26
- import { checkForDeprecatedOptions } from '../utils';
26
+ import { checkForDeprecatedOptions } from '../utils/miscellaneous';
27
27
 
28
28
  export type BundleOptions = {
29
29
  apis?: string[];
@@ -30,8 +30,8 @@ import {
30
30
  getAndValidateFileExtension,
31
31
  writeToFileByExtension,
32
32
  checkForDeprecatedOptions,
33
- } from '../utils';
34
- import { isObject, isString, keysOf } from '../js-utils';
33
+ } from '../utils/miscellaneous';
34
+ import { isObject, isString, keysOf } from '../utils/js-utils';
35
35
  import {
36
36
  Oas3Parameter,
37
37
  Oas3PathItem,
@@ -17,7 +17,7 @@ import {
17
17
  printConfigLintTotals,
18
18
  printLintTotals,
19
19
  printUnusedWarnings,
20
- } from '../utils';
20
+ } from '../utils/miscellaneous';
21
21
  import { blue, gray } from 'colorette';
22
22
  import { performance } from 'perf_hooks';
23
23
 
@@ -1,6 +1,6 @@
1
1
  import { Region, RedoclyClient, Config } from '@redocly/openapi-core';
2
2
  import { blue, green, gray } from 'colorette';
3
- import { promptUser } from '../utils';
3
+ import { promptUser } from '../utils/miscellaneous';
4
4
 
5
5
  export function promptClientToken(domain: string) {
6
6
  return promptUser(
@@ -1,7 +1,11 @@
1
1
  import * as colorette from 'colorette';
2
2
  import * as chockidar from 'chokidar';
3
3
  import { bundle, RedoclyClient, getTotals, getMergedConfig, Config } from '@redocly/openapi-core';
4
- import { getFallbackApisOrExit, handleError, loadConfigAndHandleErrors } from '../../utils';
4
+ import {
5
+ getFallbackApisOrExit,
6
+ handleError,
7
+ loadConfigAndHandleErrors,
8
+ } from '../../utils/miscellaneous';
5
9
  import startPreviewServer from './preview-server/preview-server';
6
10
  import type { Skips } from '../../types';
7
11
 
@@ -6,7 +6,7 @@ import * as path from 'path';
6
6
 
7
7
  import { startHttpServer, startWsServer, respondWithGzip, mimeTypes } from './server';
8
8
  import type { IncomingMessage } from 'http';
9
- import { isSubdir } from '../../../utils';
9
+ import { isSubdir } from '../../../utils/miscellaneous';
10
10
 
11
11
  function getPageHTML(
12
12
  htmlTemplate: string,
@@ -8,5 +8,5 @@ export type PreviewProjectOptions = {
8
8
  plan: ProductPlan | string;
9
9
  port?: number;
10
10
  'source-dir': string;
11
- config: string | undefined;
11
+ config?: string;
12
12
  };
@@ -21,8 +21,9 @@ import {
21
21
  getFallbackApisOrExit,
22
22
  pluralize,
23
23
  dumpBundle,
24
- } from '../utils';
24
+ } from '../utils/miscellaneous';
25
25
  import { promptClientToken } from './login';
26
+ import { handlePush as handleCMSPush } from '../cms/commands/push';
26
27
 
27
28
  const DEFAULT_VERSION = 'latest';
28
29
 
@@ -44,6 +45,19 @@ export type PushOptions = {
44
45
  config?: string;
45
46
  };
46
47
 
48
+ export function commonPushHandler({
49
+ project,
50
+ 'mount-path': mountPath,
51
+ }: {
52
+ project?: string;
53
+ 'mount-path'?: string;
54
+ }) {
55
+ if (project && mountPath) {
56
+ return handleCMSPush;
57
+ }
58
+ return handlePush;
59
+ }
60
+
47
61
  export async function handlePush(argv: PushOptions, config: Config): Promise<void> {
48
62
  const client = new RedoclyClient(config.region);
49
63
  const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
@@ -3,12 +3,11 @@ import * as path from 'path';
3
3
  import * as openapiCore from '@redocly/openapi-core';
4
4
  import { ComponentsFiles } from '../types';
5
5
  import { blue, green } from 'colorette';
6
- import { writeToFileByExtension } from '../../../utils';
7
6
 
8
- const utils = require('../../../utils');
7
+ const utils = require('../../../utils/miscellaneous');
9
8
 
10
- jest.mock('../../../utils', () => ({
11
- ...jest.requireActual('../../../utils'),
9
+ jest.mock('../../../utils/miscellaneous', () => ({
10
+ ...jest.requireActual('../../../utils/miscellaneous'),
12
11
  writeToFileByExtension: jest.fn(),
13
12
  }));
14
13
 
@@ -15,8 +15,8 @@ import {
15
15
  langToExt,
16
16
  writeToFileByExtension,
17
17
  getAndValidateFileExtension,
18
- } from '../../utils';
19
- import { isString, isObject, isEmptyObject } from '../../js-utils';
18
+ } from '../../utils/miscellaneous';
19
+ import { isString, isObject, isEmptyObject } from '../../utils/js-utils';
20
20
  import {
21
21
  Definition,
22
22
  Oas2Definition,
@@ -13,8 +13,8 @@ import {
13
13
  Stats,
14
14
  bundle,
15
15
  } from '@redocly/openapi-core';
16
- import { getFallbackApisOrExit } from '../utils';
17
- import { printExecutionTime } from '../utils';
16
+ import { getFallbackApisOrExit } from '../utils/miscellaneous';
17
+ import { printExecutionTime } from '../utils/miscellaneous';
18
18
  import type { StatsAccumulator, StatsName, WalkContext, OutputFormat } from '@redocly/openapi-core';
19
19
 
20
20
  const statsAccumulator: StatsAccumulator = {