mirror of
https://github.com/LukeHagar/redocly-cli.git
synced 2025-12-06 04:21:09 +00:00
chore: aggregate data regarding API types and versions usage (#1580)
This commit is contained in:
@@ -16,6 +16,8 @@ When a command is run, the following data is collected:
|
|||||||
- values from `REDOCLY_ENVIRONMENT`
|
- values from `REDOCLY_ENVIRONMENT`
|
||||||
- CLI version
|
- CLI version
|
||||||
- Node.js and NPM versions
|
- 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.
|
Values such as file names, organization IDs, and URLs are removed, replaced by just "URL" or "file", etc.
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ describe('build-docs', () => {
|
|||||||
|
|
||||||
it('should work correctly when calling handlerBuildCommand', async () => {
|
it('should work correctly when calling handlerBuildCommand', async () => {
|
||||||
const processExitMock = jest.spyOn(process, 'exit').mockImplementation();
|
const processExitMock = jest.spyOn(process, 'exit').mockImplementation();
|
||||||
await handlerBuildCommand(
|
await handlerBuildCommand({
|
||||||
{
|
argv: {
|
||||||
o: '',
|
o: '',
|
||||||
title: 'test',
|
title: 'test',
|
||||||
disableGoogleFont: false,
|
disableGoogleFont: false,
|
||||||
@@ -49,8 +49,9 @@ describe('build-docs', () => {
|
|||||||
theme: { openapi: {} },
|
theme: { openapi: {} },
|
||||||
api: '../some-path/openapi.yaml',
|
api: '../some-path/openapi.yaml',
|
||||||
} as BuildDocsArgv,
|
} as BuildDocsArgv,
|
||||||
{} as any
|
config: {} as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
expect(loadAndBundleSpec).toBeCalledTimes(1);
|
expect(loadAndBundleSpec).toBeCalledTimes(1);
|
||||||
expect(getFallbackApisOrExit).toBeCalledTimes(1);
|
expect(getFallbackApisOrExit).toBeCalledTimes(1);
|
||||||
expect(processExitMock).toBeCalledTimes(0);
|
expect(processExitMock).toBeCalledTimes(0);
|
||||||
|
|||||||
@@ -14,21 +14,21 @@ describe('handleJoin', () => {
|
|||||||
colloreteYellowMock.mockImplementation((string: string) => string);
|
colloreteYellowMock.mockImplementation((string: string) => string);
|
||||||
|
|
||||||
it('should call exitWithError because only one entrypoint', async () => {
|
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.`);
|
expect(exitWithError).toHaveBeenCalledWith(`At least 2 apis should be provided.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call exitWithError because passed all 3 options for tags', async () => {
|
it('should call exitWithError because passed all 3 options for tags', async () => {
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.yaml', 'second.yaml'],
|
apis: ['first.yaml', 'second.yaml'],
|
||||||
'prefix-tags-with-info-prop': 'something',
|
'prefix-tags-with-info-prop': 'something',
|
||||||
'without-x-tag-groups': true,
|
'without-x-tag-groups': true,
|
||||||
'prefix-tags-with-filename': true,
|
'prefix-tags-with-filename': true,
|
||||||
},
|
},
|
||||||
{} as any,
|
config: {} as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(exitWithError).toHaveBeenCalledWith(
|
expect(exitWithError).toHaveBeenCalledWith(
|
||||||
`You use prefix-tags-with-filename, prefix-tags-with-info-prop, without-x-tag-groups together.\nPlease choose only one!`
|
`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 () => {
|
it('should call exitWithError because passed all 2 options for tags', async () => {
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.yaml', 'second.yaml'],
|
apis: ['first.yaml', 'second.yaml'],
|
||||||
'without-x-tag-groups': true,
|
'without-x-tag-groups': true,
|
||||||
'prefix-tags-with-filename': true,
|
'prefix-tags-with-filename': true,
|
||||||
},
|
},
|
||||||
{} as any,
|
config: {} as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(exitWithError).toHaveBeenCalledWith(
|
expect(exitWithError).toHaveBeenCalledWith(
|
||||||
`You use prefix-tags-with-filename, without-x-tag-groups together.\nPlease choose only one!`
|
`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 () => {
|
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'],
|
apis: ['first.yaml', 'second.yaml'],
|
||||||
},
|
},
|
||||||
ConfigFixture as any,
|
config: ConfigFixture as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
expect(exitWithError).toHaveBeenCalledWith(
|
expect(exitWithError).toHaveBeenCalledWith(
|
||||||
'Only OpenAPI 3.0 and OpenAPI 3.1 are supported: undefined.'
|
'Only OpenAPI 3.0 and OpenAPI 3.1 are supported: undefined.'
|
||||||
);
|
);
|
||||||
@@ -68,13 +68,13 @@ describe('handleJoin', () => {
|
|||||||
(detectSpec as jest.Mock)
|
(detectSpec as jest.Mock)
|
||||||
.mockImplementationOnce(() => 'oas3_0')
|
.mockImplementationOnce(() => 'oas3_0')
|
||||||
.mockImplementationOnce(() => 'oas3_1');
|
.mockImplementationOnce(() => 'oas3_1');
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.yaml', 'second.yaml'],
|
apis: ['first.yaml', 'second.yaml'],
|
||||||
},
|
},
|
||||||
ConfigFixture as any,
|
config: ConfigFixture as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(exitWithError).toHaveBeenCalledWith(
|
expect(exitWithError).toHaveBeenCalledWith(
|
||||||
'All APIs must use the same OpenAPI version: undefined.'
|
'All APIs must use the same OpenAPI version: undefined.'
|
||||||
@@ -83,13 +83,13 @@ describe('handleJoin', () => {
|
|||||||
|
|
||||||
it('should call writeToFileByExtension function', async () => {
|
it('should call writeToFileByExtension function', async () => {
|
||||||
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.yaml', 'second.yaml'],
|
apis: ['first.yaml', 'second.yaml'],
|
||||||
},
|
},
|
||||||
ConfigFixture as any,
|
config: ConfigFixture as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||||
expect.any(Object),
|
expect.any(Object),
|
||||||
@@ -100,13 +100,13 @@ describe('handleJoin', () => {
|
|||||||
|
|
||||||
it('should call writeToFileByExtension function for OpenAPI 3.1', async () => {
|
it('should call writeToFileByExtension function for OpenAPI 3.1', async () => {
|
||||||
(detectSpec as jest.Mock).mockReturnValue('oas3_1');
|
(detectSpec as jest.Mock).mockReturnValue('oas3_1');
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.yaml', 'second.yaml'],
|
apis: ['first.yaml', 'second.yaml'],
|
||||||
},
|
},
|
||||||
ConfigFixture as any,
|
config: ConfigFixture as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||||
expect.any(Object),
|
expect.any(Object),
|
||||||
@@ -117,14 +117,14 @@ describe('handleJoin', () => {
|
|||||||
|
|
||||||
it('should call writeToFileByExtension function with custom output file', async () => {
|
it('should call writeToFileByExtension function with custom output file', async () => {
|
||||||
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.yaml', 'second.yaml'],
|
apis: ['first.yaml', 'second.yaml'],
|
||||||
output: 'output.yml',
|
output: 'output.yml',
|
||||||
},
|
},
|
||||||
ConfigFixture as any,
|
config: ConfigFixture as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||||
expect.any(Object),
|
expect.any(Object),
|
||||||
@@ -135,13 +135,13 @@ describe('handleJoin', () => {
|
|||||||
|
|
||||||
it('should call writeToFileByExtension function with json file extension', async () => {
|
it('should call writeToFileByExtension function with json file extension', async () => {
|
||||||
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.json', 'second.yaml'],
|
apis: ['first.json', 'second.yaml'],
|
||||||
},
|
},
|
||||||
ConfigFixture as any,
|
config: ConfigFixture as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||||
expect.any(Object),
|
expect.any(Object),
|
||||||
@@ -152,13 +152,13 @@ describe('handleJoin', () => {
|
|||||||
|
|
||||||
it('should call skipDecorators and skipPreprocessors', async () => {
|
it('should call skipDecorators and skipPreprocessors', async () => {
|
||||||
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.yaml', 'second.yaml'],
|
apis: ['first.yaml', 'second.yaml'],
|
||||||
},
|
},
|
||||||
ConfigFixture as any,
|
config: ConfigFixture as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
expect(config.styleguide.skipDecorators).toHaveBeenCalled();
|
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 () => {
|
it('should handle join with prefix-components-with-info-prop and null values', async () => {
|
||||||
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
||||||
|
|
||||||
await handleJoin(
|
await handleJoin({
|
||||||
{
|
argv: {
|
||||||
apis: ['first.yaml', 'second.yaml', 'third.yaml'],
|
apis: ['first.yaml', 'second.yaml', 'third.yaml'],
|
||||||
'prefix-components-with-info-prop': 'title',
|
'prefix-components-with-info-prop': 'title',
|
||||||
output: 'join-result.yaml',
|
output: 'join-result.yaml',
|
||||||
},
|
},
|
||||||
ConfigFixture as any,
|
config: ConfigFixture as any,
|
||||||
'cli-version'
|
version: 'cli-version',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,30 +28,32 @@ describe('push-with-region', () => {
|
|||||||
|
|
||||||
it('should call login with default domain when region is US', async () => {
|
it('should call login with default domain when region is US', async () => {
|
||||||
redoclyClient.domain = 'redoc.ly';
|
redoclyClient.domain = 'redoc.ly';
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'spec.json',
|
api: 'spec.json',
|
||||||
destination: '@org/my-api@1.0.0',
|
destination: '@org/my-api@1.0.0',
|
||||||
branchName: 'test',
|
branchName: 'test',
|
||||||
},
|
},
|
||||||
ConfigFixture as any
|
config: ConfigFixture as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
expect(mockPromptClientToken).toBeCalledTimes(1);
|
expect(mockPromptClientToken).toBeCalledTimes(1);
|
||||||
expect(mockPromptClientToken).toHaveBeenCalledWith(redoclyClient.domain);
|
expect(mockPromptClientToken).toHaveBeenCalledWith(redoclyClient.domain);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call login with EU domain when region is EU', async () => {
|
it('should call login with EU domain when region is EU', async () => {
|
||||||
redoclyClient.domain = 'eu.redocly.com';
|
redoclyClient.domain = 'eu.redocly.com';
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'spec.json',
|
api: 'spec.json',
|
||||||
destination: '@org/my-api@1.0.0',
|
destination: '@org/my-api@1.0.0',
|
||||||
branchName: 'test',
|
branchName: 'test',
|
||||||
},
|
},
|
||||||
ConfigFixture as any
|
config: ConfigFixture as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
expect(mockPromptClientToken).toBeCalledTimes(1);
|
expect(mockPromptClientToken).toBeCalledTimes(1);
|
||||||
expect(mockPromptClientToken).toHaveBeenCalledWith(redoclyClient.domain);
|
expect(mockPromptClientToken).toHaveBeenCalledWith(redoclyClient.domain);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ describe('push', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('pushes definition', async () => {
|
it('pushes definition', async () => {
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'spec.json',
|
api: 'spec.json',
|
||||||
destination: '@org/my-api@1.0.0',
|
destination: '@org/my-api@1.0.0',
|
||||||
@@ -35,8 +35,9 @@ describe('push', () => {
|
|||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
ConfigFixture as any
|
config: ConfigFixture as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(redoclyClient.registryApi.prepareFileUpload).toBeCalledTimes(1);
|
expect(redoclyClient.registryApi.prepareFileUpload).toBeCalledTimes(1);
|
||||||
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
||||||
@@ -55,8 +56,8 @@ describe('push', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('fails if jobId value is an empty string', async () => {
|
it('fails if jobId value is an empty string', async () => {
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'spec.json',
|
api: 'spec.json',
|
||||||
destination: '@org/my-api@1.0.0',
|
destination: '@org/my-api@1.0.0',
|
||||||
@@ -65,15 +66,16 @@ describe('push', () => {
|
|||||||
'job-id': ' ',
|
'job-id': ' ',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
ConfigFixture as any
|
config: ConfigFixture as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(exitWithError).toBeCalledTimes(1);
|
expect(exitWithError).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('fails if batchSize value is less than 2', async () => {
|
it('fails if batchSize value is less than 2', async () => {
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'spec.json',
|
api: 'spec.json',
|
||||||
destination: '@org/my-api@1.0.0',
|
destination: '@org/my-api@1.0.0',
|
||||||
@@ -82,8 +84,9 @@ describe('push', () => {
|
|||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 1,
|
'batch-size': 1,
|
||||||
},
|
},
|
||||||
ConfigFixture as any
|
config: ConfigFixture as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(exitWithError).toBeCalledTimes(1);
|
expect(exitWithError).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
@@ -95,16 +98,17 @@ describe('push', () => {
|
|||||||
return { isDirectory: () => false, size: 10 };
|
return { isDirectory: () => false, size: 10 };
|
||||||
});
|
});
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'spec.json',
|
api: 'spec.json',
|
||||||
destination: '@org/my-api@1.0.0',
|
destination: '@org/my-api@1.0.0',
|
||||||
public: true,
|
public: true,
|
||||||
files: ['./resouces/1.md', './resouces/2.md'],
|
files: ['./resouces/1.md', './resouces/2.md'],
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(redoclyClient.registryApi.pushApi).toHaveBeenLastCalledWith({
|
expect(redoclyClient.registryApi.pushApi).toHaveBeenLastCalledWith({
|
||||||
filePaths: ['filePath', 'filePath', 'filePath'],
|
filePaths: ['filePath', 'filePath', 'filePath'],
|
||||||
@@ -119,8 +123,8 @@ describe('push', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('push should fail if organization not provided', async () => {
|
it('push should fail if organization not provided', async () => {
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'spec.json',
|
api: 'spec.json',
|
||||||
destination: 'test@v1',
|
destination: 'test@v1',
|
||||||
@@ -129,8 +133,9 @@ describe('push', () => {
|
|||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
ConfigFixture as any
|
config: ConfigFixture as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(exitWithError).toBeCalledTimes(1);
|
expect(exitWithError).toBeCalledTimes(1);
|
||||||
expect(exitWithError).toBeCalledWith(
|
expect(exitWithError).toBeCalledWith(
|
||||||
@@ -140,8 +145,8 @@ describe('push', () => {
|
|||||||
|
|
||||||
it('push should work with organization in config', async () => {
|
it('push should work with organization in config', async () => {
|
||||||
const mockConfig = { ...ConfigFixture, organization: 'test_org' } as any;
|
const mockConfig = { ...ConfigFixture, organization: 'test_org' } as any;
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'spec.json',
|
api: 'spec.json',
|
||||||
destination: 'my-api@1.0.0',
|
destination: 'my-api@1.0.0',
|
||||||
@@ -150,8 +155,9 @@ describe('push', () => {
|
|||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
||||||
expect(redoclyClient.registryApi.pushApi).toHaveBeenLastCalledWith({
|
expect(redoclyClient.registryApi.pushApi).toHaveBeenLastCalledWith({
|
||||||
@@ -175,16 +181,17 @@ describe('push', () => {
|
|||||||
apis: { 'my-api@1.0.0': { root: 'path' } },
|
apis: { 'my-api@1.0.0': { root: 'path' } },
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
branchName: 'test',
|
branchName: 'test',
|
||||||
public: true,
|
public: true,
|
||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
@@ -192,16 +199,17 @@ describe('push', () => {
|
|||||||
it('push should fail if apis not provided', async () => {
|
it('push should fail if apis not provided', async () => {
|
||||||
const mockConfig = { organization: 'test_org', apis: {} } as any;
|
const mockConfig = { organization: 'test_org', apis: {} } as any;
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
branchName: 'test',
|
branchName: 'test',
|
||||||
public: true,
|
public: true,
|
||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(exitWithError).toBeCalledTimes(1);
|
expect(exitWithError).toBeCalledTimes(1);
|
||||||
expect(exitWithError).toHaveBeenLastCalledWith(
|
expect(exitWithError).toHaveBeenLastCalledWith(
|
||||||
@@ -212,8 +220,8 @@ describe('push', () => {
|
|||||||
it('push should fail if destination not provided', async () => {
|
it('push should fail if destination not provided', async () => {
|
||||||
const mockConfig = { organization: 'test_org', apis: {} } as any;
|
const mockConfig = { organization: 'test_org', apis: {} } as any;
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
api: 'api.yaml',
|
api: 'api.yaml',
|
||||||
branchName: 'test',
|
branchName: 'test',
|
||||||
@@ -221,8 +229,9 @@ describe('push', () => {
|
|||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(exitWithError).toBeCalledTimes(1);
|
expect(exitWithError).toBeCalledTimes(1);
|
||||||
expect(exitWithError).toHaveBeenLastCalledWith(
|
expect(exitWithError).toHaveBeenLastCalledWith(
|
||||||
@@ -233,8 +242,8 @@ describe('push', () => {
|
|||||||
it('push should fail if destination format is not valid', async () => {
|
it('push should fail if destination format is not valid', async () => {
|
||||||
const mockConfig = { organization: 'test_org', apis: {} } as any;
|
const mockConfig = { organization: 'test_org', apis: {} } as any;
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
destination: 'name/v1',
|
destination: 'name/v1',
|
||||||
branchName: 'test',
|
branchName: 'test',
|
||||||
@@ -242,8 +251,9 @@ describe('push', () => {
|
|||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(exitWithError).toHaveBeenCalledWith(
|
expect(exitWithError).toHaveBeenCalledWith(
|
||||||
`Destination argument value is not valid, please use the right format: ${yellow(
|
`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' } },
|
apis: { 'my test api@v1': { root: 'path' } },
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
upsert: true,
|
upsert: true,
|
||||||
destination: 'my test api@v1',
|
destination: 'my test api@v1',
|
||||||
branchName: 'test',
|
branchName: 'test',
|
||||||
@@ -270,8 +280,9 @@ describe('push', () => {
|
|||||||
'job-id': '123',
|
'job-id': '123',
|
||||||
'batch-size': 2,
|
'batch-size': 2,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(encodeURIComponentSpy).toHaveReturnedWith('my%20test%20api');
|
expect(encodeURIComponentSpy).toHaveReturnedWith('my%20test%20api');
|
||||||
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
||||||
@@ -281,130 +292,144 @@ describe('push', () => {
|
|||||||
describe('transformPush', () => {
|
describe('transformPush', () => {
|
||||||
it('should adapt the existing syntax', () => {
|
it('should adapt the existing syntax', () => {
|
||||||
const cb = jest.fn();
|
const cb = jest.fn();
|
||||||
transformPush(cb)(
|
transformPush(cb)({
|
||||||
{
|
argv: {
|
||||||
apis: ['openapi.yaml', '@testing_org/main@v1'],
|
apis: ['openapi.yaml', '@testing_org/main@v1'],
|
||||||
},
|
},
|
||||||
{} as any
|
config: {} as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
expect(cb).toBeCalledWith(
|
});
|
||||||
{
|
expect(cb).toBeCalledWith({
|
||||||
|
argv: {
|
||||||
api: 'openapi.yaml',
|
api: 'openapi.yaml',
|
||||||
destination: '@testing_org/main@v1',
|
destination: '@testing_org/main@v1',
|
||||||
},
|
},
|
||||||
{}
|
config: {},
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should adapt the existing syntax (including branchName)', () => {
|
it('should adapt the existing syntax (including branchName)', () => {
|
||||||
const cb = jest.fn();
|
const cb = jest.fn();
|
||||||
transformPush(cb)(
|
transformPush(cb)({
|
||||||
{
|
argv: {
|
||||||
apis: ['openapi.yaml', '@testing_org/main@v1', 'other'],
|
apis: ['openapi.yaml', '@testing_org/main@v1', 'other'],
|
||||||
},
|
},
|
||||||
{} as any
|
config: {} as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
expect(cb).toBeCalledWith(
|
});
|
||||||
{
|
expect(cb).toBeCalledWith({
|
||||||
|
argv: {
|
||||||
api: 'openapi.yaml',
|
api: 'openapi.yaml',
|
||||||
destination: '@testing_org/main@v1',
|
destination: '@testing_org/main@v1',
|
||||||
branchName: 'other',
|
branchName: 'other',
|
||||||
},
|
},
|
||||||
{}
|
config: {},
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should use --branch option firstly', () => {
|
it('should use --branch option firstly', () => {
|
||||||
const cb = jest.fn();
|
const cb = jest.fn();
|
||||||
transformPush(cb)(
|
transformPush(cb)({
|
||||||
{
|
argv: {
|
||||||
apis: ['openapi.yaml', '@testing_org/main@v1', 'other'],
|
apis: ['openapi.yaml', '@testing_org/main@v1', 'other'],
|
||||||
branch: 'priority-branch',
|
branch: 'priority-branch',
|
||||||
},
|
},
|
||||||
{} as any
|
config: {} as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
expect(cb).toBeCalledWith(
|
});
|
||||||
{
|
expect(cb).toBeCalledWith({
|
||||||
|
argv: {
|
||||||
api: 'openapi.yaml',
|
api: 'openapi.yaml',
|
||||||
destination: '@testing_org/main@v1',
|
destination: '@testing_org/main@v1',
|
||||||
branchName: 'priority-branch',
|
branchName: 'priority-branch',
|
||||||
},
|
},
|
||||||
{}
|
config: {},
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should work for a destination only', () => {
|
it('should work for a destination only', () => {
|
||||||
const cb = jest.fn();
|
const cb = jest.fn();
|
||||||
transformPush(cb)(
|
transformPush(cb)({
|
||||||
{
|
argv: {
|
||||||
apis: ['main@v1'],
|
apis: ['main@v1'],
|
||||||
},
|
},
|
||||||
{} as any
|
config: {} as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
expect(cb).toBeCalledWith(
|
});
|
||||||
{
|
expect(cb).toBeCalledWith({
|
||||||
|
argv: {
|
||||||
destination: 'main@v1',
|
destination: 'main@v1',
|
||||||
},
|
},
|
||||||
{}
|
config: {},
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should work for a api only', () => {
|
it('should work for a api only', () => {
|
||||||
const cb = jest.fn();
|
const cb = jest.fn();
|
||||||
transformPush(cb)(
|
transformPush(cb)({
|
||||||
{
|
argv: {
|
||||||
apis: ['test.yaml'],
|
apis: ['test.yaml'],
|
||||||
},
|
},
|
||||||
{} as any
|
config: {} as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
expect(cb).toBeCalledWith(
|
});
|
||||||
{
|
expect(cb).toBeCalledWith({
|
||||||
|
argv: {
|
||||||
api: 'test.yaml',
|
api: 'test.yaml',
|
||||||
},
|
},
|
||||||
{}
|
config: {},
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use destination from option', () => {
|
it('should use destination from option', () => {
|
||||||
const cb = jest.fn();
|
const cb = jest.fn();
|
||||||
transformPush(cb)(
|
transformPush(cb)({
|
||||||
{
|
argv: {
|
||||||
apis: ['test.yaml', 'test@v1'],
|
apis: ['test.yaml', 'test@v1'],
|
||||||
destination: 'main@v1',
|
destination: 'main@v1',
|
||||||
},
|
},
|
||||||
{} as any
|
config: {} as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
expect(cb).toBeCalledWith(
|
});
|
||||||
{
|
expect(cb).toBeCalledWith({
|
||||||
|
argv: {
|
||||||
destination: 'main@v1',
|
destination: 'main@v1',
|
||||||
api: 'test.yaml',
|
api: 'test.yaml',
|
||||||
},
|
},
|
||||||
{}
|
config: {},
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use --job-id option firstly', () => {
|
it('should use --job-id option firstly', () => {
|
||||||
const cb = jest.fn();
|
const cb = jest.fn();
|
||||||
transformPush(cb)(
|
transformPush(cb)({
|
||||||
{
|
argv: {
|
||||||
'batch-id': 'b-123',
|
'batch-id': 'b-123',
|
||||||
'job-id': 'j-123',
|
'job-id': 'j-123',
|
||||||
apis: ['test'],
|
apis: ['test'],
|
||||||
branch: 'test',
|
branch: 'test',
|
||||||
destination: 'main@v1',
|
destination: 'main@v1',
|
||||||
},
|
},
|
||||||
{} as any
|
config: {} as any,
|
||||||
);
|
version: 'cli-version',
|
||||||
expect(cb).toBeCalledWith(
|
});
|
||||||
{
|
expect(cb).toBeCalledWith({
|
||||||
|
argv: {
|
||||||
'job-id': 'j-123',
|
'job-id': 'j-123',
|
||||||
api: 'test',
|
api: 'test',
|
||||||
branchName: 'test',
|
branchName: 'test',
|
||||||
destination: 'main@v1',
|
destination: 'main@v1',
|
||||||
},
|
},
|
||||||
{}
|
config: {},
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should accept no arguments at all', () => {
|
it('should accept no arguments at all', () => {
|
||||||
const cb = jest.fn();
|
const cb = jest.fn();
|
||||||
transformPush(cb)({}, {} as any);
|
transformPush(cb)({ argv: {}, config: {} as any, version: 'cli-version' });
|
||||||
expect(cb).toBeCalledWith({}, {});
|
expect(cb).toBeCalledWith({ argv: {}, config: {}, version: 'cli-version' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { commandWrapper } from '../wrapper';
|
|||||||
import { handleLint } from '../commands/lint';
|
import { handleLint } from '../commands/lint';
|
||||||
import { Arguments } from 'yargs';
|
import { Arguments } from 'yargs';
|
||||||
import { handlePush, PushOptions } from '../commands/push';
|
import { handlePush, PushOptions } from '../commands/push';
|
||||||
|
import { detectSpec } from '@redocly/openapi-core';
|
||||||
|
|
||||||
jest.mock('node-fetch');
|
jest.mock('node-fetch');
|
||||||
jest.mock('../utils/miscellaneous', () => ({
|
jest.mock('../utils/miscellaneous', () => ({
|
||||||
@@ -11,7 +12,9 @@ jest.mock('../utils/miscellaneous', () => ({
|
|||||||
loadConfigAndHandleErrors: jest.fn(),
|
loadConfigAndHandleErrors: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('../commands/lint', () => ({
|
jest.mock('../commands/lint', () => ({
|
||||||
handleLint: jest.fn(),
|
handleLint: jest.fn().mockImplementation(({ collectSpecData }) => {
|
||||||
|
collectSpecData({ openapi: '3.1.0' });
|
||||||
|
}),
|
||||||
lintConfigCallback: jest.fn(),
|
lintConfigCallback: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -20,13 +23,32 @@ describe('commandWrapper', () => {
|
|||||||
(loadConfigAndHandleErrors as jest.Mock).mockImplementation(() => {
|
(loadConfigAndHandleErrors as jest.Mock).mockImplementation(() => {
|
||||||
return { telemetry: 'on', styleguide: { recommendedFallback: true } };
|
return { telemetry: 'on', styleguide: { recommendedFallback: true } };
|
||||||
});
|
});
|
||||||
|
(detectSpec as jest.Mock).mockImplementationOnce(() => {
|
||||||
|
return 'oas3_1';
|
||||||
|
});
|
||||||
process.env.REDOCLY_TELEMETRY = 'on';
|
process.env.REDOCLY_TELEMETRY = 'on';
|
||||||
|
|
||||||
const wrappedHandler = commandWrapper(handleLint);
|
const wrappedHandler = commandWrapper(handleLint);
|
||||||
await wrappedHandler({} as any);
|
await wrappedHandler({} as any);
|
||||||
expect(handleLint).toHaveBeenCalledTimes(1);
|
expect(handleLint).toHaveBeenCalledTimes(1);
|
||||||
expect(sendTelemetry).toHaveBeenCalledTimes(1);
|
expect(sendTelemetry).toHaveBeenCalledTimes(1);
|
||||||
expect(sendTelemetry).toHaveBeenCalledWith({}, 0, false);
|
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, undefined, undefined, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT send telemetry if there is "telemetry: off" in the config', async () => {
|
it('should NOT send telemetry if there is "telemetry: off" in the config', async () => {
|
||||||
|
|||||||
@@ -85,15 +85,16 @@ describe('handlePushStatus()', () => {
|
|||||||
|
|
||||||
it('should throw error if organization not provided', async () => {
|
it('should throw error if organization not provided', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
handlePushStatus(
|
handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: '',
|
organization: '',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
)
|
version: 'cli-version',
|
||||||
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||||
`"No organization provided, please use --organization option or specify the 'organization' field in the config file."`
|
`"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';
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
||||||
remotes.getPush.mockResolvedValueOnce(pushResponseStub);
|
remotes.getPush.mockResolvedValueOnce(pushResponseStub);
|
||||||
|
|
||||||
await handlePushStatus(
|
await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
expect(process.stdout.write).toHaveBeenCalledTimes(1);
|
expect(process.stdout.write).toHaveBeenCalledTimes(1);
|
||||||
expect(process.stdout.write).toHaveBeenCalledWith(
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
||||||
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
||||||
@@ -127,15 +129,16 @@ describe('handlePushStatus()', () => {
|
|||||||
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
||||||
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: true });
|
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: true });
|
||||||
|
|
||||||
await handlePushStatus(
|
await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
expect(process.stdout.write).toHaveBeenCalledTimes(2);
|
expect(process.stdout.write).toHaveBeenCalledTimes(2);
|
||||||
expect(process.stdout.write).toHaveBeenCalledWith(
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
||||||
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
||||||
@@ -157,15 +160,16 @@ describe('handlePushStatus()', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
handlePushStatus(
|
handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
)
|
version: 'cli-version',
|
||||||
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"❌ Preview deploy fail.
|
"❌ Preview deploy fail.
|
||||||
Preview URL: https://preview-test-url"
|
Preview URL: https://preview-test-url"
|
||||||
@@ -197,15 +201,16 @@ describe('handlePushStatus()', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await handlePushStatus(
|
await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
expect(process.stdout.write).toHaveBeenCalledTimes(4);
|
expect(process.stdout.write).toHaveBeenCalledTimes(4);
|
||||||
expect(process.stdout.write).toHaveBeenCalledWith(
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
||||||
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
||||||
@@ -232,16 +237,17 @@ describe('handlePushStatus()', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await handlePushStatus(
|
await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
wait: true,
|
wait: true,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(process.stderr.write).toHaveBeenCalledWith(
|
expect(process.stderr.write).toHaveBeenCalledWith(
|
||||||
'Files not added to your project. Reason: no changes.\n'
|
'Files not added to your project. Reason: no changes.\n'
|
||||||
@@ -253,15 +259,16 @@ describe('handlePushStatus()', () => {
|
|||||||
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
||||||
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: false });
|
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: false });
|
||||||
|
|
||||||
const result = await handlePushStatus(
|
const result = await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
preview: {
|
preview: {
|
||||||
@@ -280,15 +287,16 @@ describe('handlePushStatus()', () => {
|
|||||||
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
||||||
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: true });
|
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: true });
|
||||||
|
|
||||||
const result = await handlePushStatus(
|
const result = await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
preview: {
|
preview: {
|
||||||
@@ -344,8 +352,8 @@ describe('handlePushStatus()', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await handlePushStatus(
|
const result = await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
@@ -353,8 +361,9 @@ describe('handlePushStatus()', () => {
|
|||||||
'retry-interval': 0.5, // 500 ms
|
'retry-interval': 0.5, // 500 ms
|
||||||
wait: true,
|
wait: true,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
preview: {
|
preview: {
|
||||||
@@ -417,8 +426,8 @@ describe('handlePushStatus()', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await handlePushStatus(
|
const result = await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
@@ -426,8 +435,9 @@ describe('handlePushStatus()', () => {
|
|||||||
'retry-interval': 0.5, // 500 ms
|
'retry-interval': 0.5, // 500 ms
|
||||||
wait: true,
|
wait: true,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
preview: {
|
preview: {
|
||||||
@@ -458,16 +468,17 @@ describe('handlePushStatus()', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
handlePushStatus(
|
handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
'continue-on-deploy-failures': false,
|
'continue-on-deploy-failures': false,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
)
|
version: 'cli-version',
|
||||||
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"❌ Preview deploy fail.
|
"❌ Preview deploy fail.
|
||||||
Preview URL: https://preview-test-url"
|
Preview URL: https://preview-test-url"
|
||||||
@@ -488,16 +499,17 @@ describe('handlePushStatus()', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
handlePushStatus(
|
handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
pushId: 'test-push-id',
|
pushId: 'test-push-id',
|
||||||
'continue-on-deploy-failures': true,
|
'continue-on-deploy-failures': true,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
)
|
version: 'cli-version',
|
||||||
|
})
|
||||||
).resolves.toStrictEqual({
|
).resolves.toStrictEqual({
|
||||||
preview: {
|
preview: {
|
||||||
deploy: { status: 'failed', url: 'https://preview-test-url' },
|
deploy: { status: 'failed', url: 'https://preview-test-url' },
|
||||||
@@ -545,8 +557,8 @@ describe('handlePushStatus()', () => {
|
|||||||
|
|
||||||
const onRetrySpy = jest.fn();
|
const onRetrySpy = jest.fn();
|
||||||
|
|
||||||
const result = await handlePushStatus(
|
const result = await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
@@ -555,8 +567,9 @@ describe('handlePushStatus()', () => {
|
|||||||
'retry-interval': 0.5, // 500 ms
|
'retry-interval': 0.5, // 500 ms
|
||||||
onRetry: onRetrySpy,
|
onRetry: onRetrySpy,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(onRetrySpy).toBeCalledTimes(2);
|
expect(onRetrySpy).toBeCalledTimes(2);
|
||||||
|
|
||||||
@@ -617,8 +630,8 @@ describe('handlePushStatus()', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
handlePushStatus(
|
handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
@@ -627,8 +640,9 @@ describe('handlePushStatus()', () => {
|
|||||||
'max-execution-time': 1, // seconds
|
'max-execution-time': 1, // seconds
|
||||||
wait: true,
|
wait: true,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
)
|
version: 'cli-version',
|
||||||
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"✗ Failed to get push status. Reason: Timeout exceeded
|
"✗ Failed to get push status. Reason: Timeout exceeded
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ describe('handlePush()', () => {
|
|||||||
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
||||||
pathDirnameSpy.mockImplementation((_: string) => '.');
|
pathDirnameSpy.mockImplementation((_: string) => '.');
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
'mount-path': 'test-mount-path',
|
'mount-path': 'test-mount-path',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
@@ -81,8 +81,9 @@ describe('handlePush()', () => {
|
|||||||
files: ['test-file'],
|
files: ['test-file'],
|
||||||
'max-execution-time': 10,
|
'max-execution-time': 10,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(remotes.getDefaultBranch).toHaveBeenCalledWith('test-org', 'test-project');
|
expect(remotes.getDefaultBranch).toHaveBeenCalledWith('test-org', 'test-project');
|
||||||
expect(remotes.upsert).toHaveBeenCalledWith('test-org', 'test-project', {
|
expect(remotes.upsert).toHaveBeenCalledWith('test-org', 'test-project', {
|
||||||
@@ -132,8 +133,8 @@ describe('handlePush()', () => {
|
|||||||
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
||||||
pathDirnameSpy.mockImplementation((_: string) => '.');
|
pathDirnameSpy.mockImplementation((_: string) => '.');
|
||||||
|
|
||||||
const result = await handlePush(
|
const result = await handlePush({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
'mount-path': 'test-mount-path',
|
'mount-path': 'test-mount-path',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
@@ -150,8 +151,9 @@ describe('handlePush()', () => {
|
|||||||
files: ['test-file'],
|
files: ['test-file'],
|
||||||
'max-execution-time': 10,
|
'max-execution-time': 10,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(result).toEqual({ pushId: 'test-id' });
|
expect(result).toEqual({ pushId: 'test-id' });
|
||||||
});
|
});
|
||||||
@@ -188,8 +190,8 @@ describe('handlePush()', () => {
|
|||||||
throw new Error('Not a directory');
|
throw new Error('Not a directory');
|
||||||
});
|
});
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
'mount-path': 'test-mount-path',
|
'mount-path': 'test-mount-path',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
@@ -201,8 +203,9 @@ describe('handlePush()', () => {
|
|||||||
files: ['test-folder'],
|
files: ['test-folder'],
|
||||||
'max-execution-time': 10,
|
'max-execution-time': 10,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(remotes.push).toHaveBeenCalledWith(
|
expect(remotes.push).toHaveBeenCalledWith(
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
@@ -230,8 +233,8 @@ describe('handlePush()', () => {
|
|||||||
const mockConfig = { apis: {} } as any;
|
const mockConfig = { apis: {} } as any;
|
||||||
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
'mount-path': 'test-mount-path',
|
'mount-path': 'test-mount-path',
|
||||||
organization: 'test-org',
|
organization: 'test-org',
|
||||||
@@ -243,8 +246,9 @@ describe('handlePush()', () => {
|
|||||||
files: [],
|
files: [],
|
||||||
'max-execution-time': 10,
|
'max-execution-time': 10,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(remotes.getDefaultBranch).not.toHaveBeenCalled();
|
expect(remotes.getDefaultBranch).not.toHaveBeenCalled();
|
||||||
expect(remotes.upsert).not.toHaveBeenCalled();
|
expect(remotes.upsert).not.toHaveBeenCalled();
|
||||||
@@ -265,8 +269,8 @@ describe('handlePush()', () => {
|
|||||||
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
||||||
pathDirnameSpy.mockImplementation((_: string) => '.');
|
pathDirnameSpy.mockImplementation((_: string) => '.');
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
domain: 'test-domain',
|
domain: 'test-domain',
|
||||||
'mount-path': 'test-mount-path',
|
'mount-path': 'test-mount-path',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
@@ -277,8 +281,9 @@ describe('handlePush()', () => {
|
|||||||
'default-branch': 'main',
|
'default-branch': 'main',
|
||||||
'max-execution-time': 10,
|
'max-execution-time': 10,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(remotes.getDefaultBranch).toHaveBeenCalledWith(
|
expect(remotes.getDefaultBranch).toHaveBeenCalledWith(
|
||||||
'test-org-from-config',
|
'test-org-from-config',
|
||||||
@@ -312,8 +317,8 @@ describe('handlePush()', () => {
|
|||||||
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
||||||
pathDirnameSpy.mockImplementation((_: string) => '.');
|
pathDirnameSpy.mockImplementation((_: string) => '.');
|
||||||
|
|
||||||
await handlePush(
|
await handlePush({
|
||||||
{
|
argv: {
|
||||||
'mount-path': 'test-mount-path',
|
'mount-path': 'test-mount-path',
|
||||||
project: 'test-project',
|
project: 'test-project',
|
||||||
branch: 'test-branch',
|
branch: 'test-branch',
|
||||||
@@ -323,8 +328,9 @@ describe('handlePush()', () => {
|
|||||||
files: ['test-file'],
|
files: ['test-file'],
|
||||||
'max-execution-time': 10,
|
'max-execution-time': 10,
|
||||||
},
|
},
|
||||||
mockConfig
|
config: mockConfig,
|
||||||
);
|
version: 'cli-version',
|
||||||
|
});
|
||||||
|
|
||||||
expect(ReuniteApiClient).toBeCalledWith('test-domain-from-env', 'test-api-key');
|
expect(ReuniteApiClient).toBeCalledWith('test-domain-from-env', 'test-api-key');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
import * as colors from 'colorette';
|
import * as colors from 'colorette';
|
||||||
import type { Config, OutputFormat } from '@redocly/openapi-core';
|
|
||||||
|
|
||||||
import { exitWithError, printExecutionTime } from '../../utils/miscellaneous';
|
import { exitWithError, printExecutionTime } from '../../utils/miscellaneous';
|
||||||
import { Spinner } from '../../utils/spinner';
|
import { Spinner } from '../../utils/spinner';
|
||||||
import { DeploymentError } from '../utils';
|
import { DeploymentError } from '../utils';
|
||||||
import { ReuniteApiClient, getApiKeys, getDomain } from '../api';
|
import { ReuniteApiClient, getApiKeys, getDomain } from '../api';
|
||||||
import { capitalize } from '../../utils/js-utils';
|
import { capitalize } from '../../utils/js-utils';
|
||||||
|
import { retryUntilConditionMet } from './utils';
|
||||||
|
|
||||||
|
import type { OutputFormat } from '@redocly/openapi-core';
|
||||||
|
import type { CommandArgs } from '../../wrapper';
|
||||||
import type {
|
import type {
|
||||||
DeploymentStatus,
|
DeploymentStatus,
|
||||||
DeploymentStatusResponse,
|
DeploymentStatusResponse,
|
||||||
PushResponse,
|
PushResponse,
|
||||||
ScorecardItem,
|
ScorecardItem,
|
||||||
} from '../api/types';
|
} from '../api/types';
|
||||||
import { retryUntilConditionMet } from './utils';
|
|
||||||
|
|
||||||
const RETRY_INTERVAL_MS = 5000; // 5 sec
|
const RETRY_INTERVAL_MS = 5000; // 5 sec
|
||||||
|
|
||||||
@@ -37,10 +38,10 @@ export interface PushStatusSummary {
|
|||||||
commit: PushResponse['commit'];
|
commit: PushResponse['commit'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handlePushStatus(
|
export async function handlePushStatus({
|
||||||
argv: PushStatusOptions,
|
argv,
|
||||||
config: Config
|
config,
|
||||||
): Promise<PushStatusSummary | undefined> {
|
}: CommandArgs<PushStatusOptions>): Promise<PushStatusSummary | undefined> {
|
||||||
const startedAt = performance.now();
|
const startedAt = performance.now();
|
||||||
const spinner = new Spinner();
|
const spinner = new Spinner();
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import {
|
|||||||
import { handlePushStatus } from './push-status';
|
import { handlePushStatus } from './push-status';
|
||||||
import { ReuniteApiClient, getDomain, getApiKeys } from '../api';
|
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 = {
|
export type PushOptions = {
|
||||||
apis?: string[];
|
apis?: string[];
|
||||||
@@ -42,10 +43,11 @@ export type PushOptions = {
|
|||||||
|
|
||||||
type FileToUpload = { name: string; path: string };
|
type FileToUpload = { name: string; path: string };
|
||||||
|
|
||||||
export async function handlePush(
|
export async function handlePush({
|
||||||
argv: PushOptions,
|
argv,
|
||||||
config: Config
|
config,
|
||||||
): Promise<{ pushId: string } | void> {
|
version,
|
||||||
|
}: CommandArgs<PushOptions>): Promise<{ pushId: string } | void> {
|
||||||
const startedAt = performance.now(); // for printing execution time
|
const startedAt = performance.now(); // for printing execution time
|
||||||
const startTime = Date.now(); // for push-status command
|
const startTime = Date.now(); // for push-status command
|
||||||
|
|
||||||
@@ -131,8 +133,8 @@ export async function handlePush(
|
|||||||
if (waitForDeployment) {
|
if (waitForDeployment) {
|
||||||
process.stdout.write('\n');
|
process.stdout.write('\n');
|
||||||
|
|
||||||
await handlePushStatus(
|
await handlePushStatus({
|
||||||
{
|
argv: {
|
||||||
organization: orgId,
|
organization: orgId,
|
||||||
project: projectId,
|
project: projectId,
|
||||||
pushId: id,
|
pushId: id,
|
||||||
@@ -142,8 +144,9 @@ export async function handlePush(
|
|||||||
'start-time': startTime,
|
'start-time': startTime,
|
||||||
'continue-on-deploy-failures': argv['continue-on-deploy-failures'],
|
'continue-on-deploy-failures': argv['continue-on-deploy-failures'],
|
||||||
},
|
},
|
||||||
config
|
config,
|
||||||
);
|
version,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
verbose &&
|
verbose &&
|
||||||
printExecutionTime(
|
printExecutionTime(
|
||||||
|
|||||||
@@ -2,17 +2,21 @@ import { loadAndBundleSpec } from 'redoc';
|
|||||||
import { dirname, resolve } from 'path';
|
import { dirname, resolve } from 'path';
|
||||||
import { writeFileSync, mkdirSync } from 'fs';
|
import { writeFileSync, mkdirSync } from 'fs';
|
||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
|
import { getMergedConfig, isAbsoluteUrl } from '@redocly/openapi-core';
|
||||||
import { getObjectOrJSON, getPageHTML } from './utils';
|
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';
|
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 startedAt = performance.now();
|
||||||
|
|
||||||
const config = getMergedConfig(configFromFile, argv.api);
|
const config = getMergedConfig(configFromFile, argv.api);
|
||||||
|
|
||||||
const apis = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
|
const apis = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
|
||||||
const { path: pathToApi } = apis[0];
|
const { path: pathToApi } = apis[0];
|
||||||
|
|
||||||
@@ -31,6 +35,7 @@ export const handlerBuildCommand = async (argv: BuildDocsArgv, configFromFile: C
|
|||||||
const elapsed = getExecutionTime(startedAt);
|
const elapsed = getExecutionTime(startedAt);
|
||||||
|
|
||||||
const api = await loadAndBundleSpec(isAbsoluteUrl(pathToApi) ? pathToApi : resolve(pathToApi));
|
const api = await loadAndBundleSpec(isAbsoluteUrl(pathToApi) ? pathToApi : resolve(pathToApi));
|
||||||
|
collectSpecData?.(api);
|
||||||
const pageHTML = await getPageHTML(
|
const pageHTML = await getPageHTML(
|
||||||
api,
|
api,
|
||||||
pathToApi,
|
pathToApi,
|
||||||
|
|||||||
@@ -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 {
|
import {
|
||||||
dumpBundle,
|
dumpBundle,
|
||||||
getExecutionTime,
|
getExecutionTime,
|
||||||
@@ -8,12 +11,11 @@ import {
|
|||||||
printUnusedWarnings,
|
printUnusedWarnings,
|
||||||
saveBundle,
|
saveBundle,
|
||||||
sortTopLevelKeysForOas,
|
sortTopLevelKeysForOas,
|
||||||
|
checkForDeprecatedOptions,
|
||||||
} from '../utils/miscellaneous';
|
} from '../utils/miscellaneous';
|
||||||
|
|
||||||
import type { OutputExtensions, Skips, Totals } from '../types';
|
import type { OutputExtensions, Skips, Totals } from '../types';
|
||||||
import { performance } from 'perf_hooks';
|
import type { CommandArgs } from '../wrapper';
|
||||||
import { blue, gray, green, yellow } from 'colorette';
|
|
||||||
import { writeFileSync } from 'fs';
|
|
||||||
import { checkForDeprecatedOptions } from '../utils/miscellaneous';
|
|
||||||
|
|
||||||
export type BundleOptions = {
|
export type BundleOptions = {
|
||||||
apis?: string[];
|
apis?: string[];
|
||||||
@@ -28,7 +30,12 @@ export type BundleOptions = {
|
|||||||
'keep-url-references'?: boolean;
|
'keep-url-references'?: boolean;
|
||||||
} & Skips;
|
} & Skips;
|
||||||
|
|
||||||
export async function handleBundle(argv: BundleOptions, config: Config, version: string) {
|
export async function handleBundle({
|
||||||
|
argv,
|
||||||
|
config,
|
||||||
|
version,
|
||||||
|
collectSpecData,
|
||||||
|
}: CommandArgs<BundleOptions>) {
|
||||||
const removeUnusedComponents =
|
const removeUnusedComponents =
|
||||||
argv['remove-unused-components'] ||
|
argv['remove-unused-components'] ||
|
||||||
config.rawConfig?.styleguide?.decorators?.hasOwnProperty('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,
|
dereference: argv.dereferenced,
|
||||||
removeUnusedComponents,
|
removeUnusedComponents,
|
||||||
keepUrlRefs: argv['keep-url-references'],
|
keepUrlRefs: argv['keep-url-references'],
|
||||||
|
collectSpecData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fileTotals = getTotals(problems);
|
const fileTotals = getTotals(problems);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import * as path from 'path';
|
|||||||
import { red, blue, yellow, green } from 'colorette';
|
import { red, blue, yellow, green } from 'colorette';
|
||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import {
|
import {
|
||||||
Config,
|
|
||||||
SpecVersion,
|
SpecVersion,
|
||||||
BaseResolver,
|
BaseResolver,
|
||||||
formatProblems,
|
formatProblems,
|
||||||
@@ -38,6 +37,7 @@ import type {
|
|||||||
Oas3Server,
|
Oas3Server,
|
||||||
Oas3_1Definition,
|
Oas3_1Definition,
|
||||||
} from '@redocly/openapi-core/lib/typings/openapi';
|
} from '@redocly/openapi-core/lib/typings/openapi';
|
||||||
|
import type { CommandArgs } from '../wrapper';
|
||||||
|
|
||||||
const Tags = 'tags';
|
const Tags = 'tags';
|
||||||
const xTagGroups = 'x-tagGroups';
|
const xTagGroups = 'x-tagGroups';
|
||||||
@@ -64,7 +64,11 @@ export type JoinOptions = {
|
|||||||
'lint-config'?: RuleSeverity;
|
'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();
|
const startedAt = performance.now();
|
||||||
|
|
||||||
if (argv.apis.length < 2) {
|
if (argv.apis.length < 2) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { blue, gray } from 'colorette';
|
import { blue, gray } from 'colorette';
|
||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import {
|
import {
|
||||||
Config,
|
|
||||||
formatProblems,
|
formatProblems,
|
||||||
getMergedConfig,
|
getMergedConfig,
|
||||||
getTotals,
|
getTotals,
|
||||||
@@ -23,10 +22,11 @@ import {
|
|||||||
} from '../utils/miscellaneous';
|
} from '../utils/miscellaneous';
|
||||||
import { getCommandNameFromArgs } from '../utils/getCommandNameFromArgs';
|
import { getCommandNameFromArgs } from '../utils/getCommandNameFromArgs';
|
||||||
|
|
||||||
|
import type { Arguments } from 'yargs';
|
||||||
import type { OutputFormat, ProblemSeverity, RuleSeverity } from '@redocly/openapi-core';
|
import type { OutputFormat, ProblemSeverity, RuleSeverity } from '@redocly/openapi-core';
|
||||||
import type { RawConfigProcessor } from '@redocly/openapi-core/lib/config';
|
import type { RawConfigProcessor } from '@redocly/openapi-core/lib/config';
|
||||||
import type { CommandOptions, Skips, Totals } from '../types';
|
import type { CommandOptions, Skips, Totals } from '../types';
|
||||||
import type { Arguments } from 'yargs';
|
import type { CommandArgs } from '../wrapper';
|
||||||
|
|
||||||
export type LintOptions = {
|
export type LintOptions = {
|
||||||
apis?: string[];
|
apis?: string[];
|
||||||
@@ -38,7 +38,12 @@ export type LintOptions = {
|
|||||||
'lint-config'?: RuleSeverity;
|
'lint-config'?: RuleSeverity;
|
||||||
} & Omit<Skips, 'skip-decorator'>;
|
} & 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);
|
const apis = await getFallbackApisOrExit(argv.apis, config);
|
||||||
|
|
||||||
if (!apis.length) {
|
if (!apis.length) {
|
||||||
@@ -74,6 +79,7 @@ export async function handleLint(argv: LintOptions, config: Config, version: str
|
|||||||
const results = await lint({
|
const results = await lint({
|
||||||
ref: path,
|
ref: path,
|
||||||
config: resolvedConfig,
|
config: resolvedConfig,
|
||||||
|
collectSpecData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fileTotals = getTotals(results);
|
const fileTotals = getTotals(results);
|
||||||
|
|||||||
@@ -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 { blue, green, gray } from 'colorette';
|
||||||
import { promptUser } from '../utils/miscellaneous';
|
import { promptUser } from '../utils/miscellaneous';
|
||||||
|
|
||||||
|
import type { CommandArgs } from '../wrapper';
|
||||||
|
|
||||||
export function promptClientToken(domain: string) {
|
export function promptClientToken(domain: string) {
|
||||||
return promptUser(
|
return promptUser(
|
||||||
green(
|
green(
|
||||||
@@ -17,7 +19,7 @@ export type LoginOptions = {
|
|||||||
config?: string;
|
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 region = argv.region || config.region;
|
||||||
const client = new RedoclyClient(region);
|
const client = new RedoclyClient(region);
|
||||||
const clientToken = await promptClientToken(client.domain);
|
const clientToken = await promptClientToken(client.domain);
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import {
|
|||||||
loadConfigAndHandleErrors,
|
loadConfigAndHandleErrors,
|
||||||
} from '../../utils/miscellaneous';
|
} from '../../utils/miscellaneous';
|
||||||
import startPreviewServer from './preview-server/preview-server';
|
import startPreviewServer from './preview-server/preview-server';
|
||||||
|
|
||||||
import type { Skips } from '../../types';
|
import type { Skips } from '../../types';
|
||||||
|
import type { CommandArgs } from '../../wrapper';
|
||||||
|
|
||||||
export type PreviewDocsOptions = {
|
export type PreviewDocsOptions = {
|
||||||
port: number;
|
port: number;
|
||||||
@@ -18,7 +20,10 @@ export type PreviewDocsOptions = {
|
|||||||
force?: boolean;
|
force?: boolean;
|
||||||
} & Omit<Skips, 'skip-rule'>;
|
} & 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 isAuthorizedWithRedocly = false;
|
||||||
let redocOptions: any = {};
|
let redocOptions: any = {};
|
||||||
let config = await reloadConfig(configFromFile);
|
let config = await reloadConfig(configFromFile);
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ import { spawn } from 'child_process';
|
|||||||
import { PRODUCT_NAMES, PRODUCT_PACKAGES } from './constants';
|
import { PRODUCT_NAMES, PRODUCT_PACKAGES } from './constants';
|
||||||
|
|
||||||
import type { PreviewProjectOptions, Product } from './types';
|
import type { PreviewProjectOptions, Product } from './types';
|
||||||
|
import type { CommandArgs } from '../../wrapper';
|
||||||
|
|
||||||
export const previewProject = async (args: PreviewProjectOptions) => {
|
export const previewProject = async ({ argv }: CommandArgs<PreviewProjectOptions>) => {
|
||||||
const { plan, port } = args;
|
const { plan, port } = argv;
|
||||||
const projectDir = args['source-dir'];
|
const projectDir = argv['source-dir'];
|
||||||
|
|
||||||
const product = args.product || tryGetProductFromPackageJson(projectDir);
|
const product = argv.product || tryGetProductFromPackageJson(projectDir);
|
||||||
|
|
||||||
if (!isValidProduct(product)) {
|
if (!isValidProduct(product)) {
|
||||||
process.stderr.write(`Invalid product ${product}`);
|
process.stderr.write(`Invalid product ${product}`);
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import {
|
|||||||
import { promptClientToken } from './login';
|
import { promptClientToken } from './login';
|
||||||
import { handlePush as handleCMSPush } from '../cms/commands/push';
|
import { handlePush as handleCMSPush } from '../cms/commands/push';
|
||||||
|
|
||||||
|
import type { CommandArgs } from '../wrapper';
|
||||||
|
|
||||||
const DEFAULT_VERSION = 'latest';
|
const DEFAULT_VERSION = 'latest';
|
||||||
|
|
||||||
export const DESTINATION_REGEX =
|
export const DESTINATION_REGEX =
|
||||||
@@ -59,7 +61,7 @@ export function commonPushHandler({
|
|||||||
return transformPush(handlePush);
|
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 client = new RedoclyClient(config.region);
|
||||||
const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
|
const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
|
||||||
if (!isAuthorized) {
|
if (!isAuthorized) {
|
||||||
@@ -366,16 +368,11 @@ type BarePushArgs = Omit<PushOptions, 'destination' | 'branchName'> & {
|
|||||||
|
|
||||||
export const transformPush =
|
export const transformPush =
|
||||||
(callback: typeof handlePush) =>
|
(callback: typeof handlePush) =>
|
||||||
(
|
({
|
||||||
{
|
argv: { apis, branch, 'batch-id': batchId, 'job-id': jobId, ...rest },
|
||||||
apis,
|
config,
|
||||||
branch,
|
version,
|
||||||
'batch-id': batchId,
|
}: CommandArgs<BarePushArgs & { 'batch-id'?: string }>) => {
|
||||||
'job-id': jobId,
|
|
||||||
...rest
|
|
||||||
}: BarePushArgs & { 'batch-id'?: string },
|
|
||||||
config: Config
|
|
||||||
) => {
|
|
||||||
const [maybeApiOrDestination, maybeDestination, maybeBranchName] = apis || [];
|
const [maybeApiOrDestination, maybeDestination, maybeBranchName] = apis || [];
|
||||||
|
|
||||||
if (batchId) {
|
if (batchId) {
|
||||||
@@ -414,16 +411,17 @@ export const transformPush =
|
|||||||
apiFile = maybeApiOrDestination;
|
apiFile = maybeApiOrDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
return callback(
|
return callback({
|
||||||
{
|
argv: {
|
||||||
...rest,
|
...rest,
|
||||||
destination: rest.destination ?? destination,
|
destination: rest.destination ?? destination,
|
||||||
api: apiFile,
|
api: apiFile,
|
||||||
branchName: branch ?? maybeBranchName,
|
branchName: branch ?? maybeBranchName,
|
||||||
'job-id': jobId || batchId,
|
'job-id': jobId || batchId,
|
||||||
},
|
},
|
||||||
config
|
config,
|
||||||
);
|
version,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getApiRoot({
|
export function getApiRoot({
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import * as path from 'path';
|
|||||||
import * as openapiCore from '@redocly/openapi-core';
|
import * as openapiCore from '@redocly/openapi-core';
|
||||||
import { ComponentsFiles } from '../types';
|
import { ComponentsFiles } from '../types';
|
||||||
import { blue, green } from 'colorette';
|
import { blue, green } from 'colorette';
|
||||||
|
import { loadConfigAndHandleErrors } from '../../../utils/__mocks__/miscellaneous';
|
||||||
|
|
||||||
|
import type { Config } from '@redocly/openapi-core';
|
||||||
|
|
||||||
const utils = require('../../../utils/miscellaneous');
|
const utils = require('../../../utils/miscellaneous');
|
||||||
|
|
||||||
@@ -25,9 +28,13 @@ describe('#split', () => {
|
|||||||
jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
||||||
|
|
||||||
await handleSplit({
|
await handleSplit({
|
||||||
api: filePath,
|
argv: {
|
||||||
outDir: openapiDir,
|
api: filePath,
|
||||||
separator: '_',
|
outDir: openapiDir,
|
||||||
|
separator: '_',
|
||||||
|
},
|
||||||
|
config: loadConfigAndHandleErrors() as any as Config,
|
||||||
|
version: 'cli-version',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(process.stderr.write).toBeCalledTimes(2);
|
expect(process.stderr.write).toBeCalledTimes(2);
|
||||||
@@ -46,9 +53,13 @@ describe('#split', () => {
|
|||||||
jest.spyOn(utils, 'pathToFilename').mockImplementation(() => 'newFilePath');
|
jest.spyOn(utils, 'pathToFilename').mockImplementation(() => 'newFilePath');
|
||||||
|
|
||||||
await handleSplit({
|
await handleSplit({
|
||||||
api: filePath,
|
argv: {
|
||||||
outDir: openapiDir,
|
api: filePath,
|
||||||
separator: '_',
|
outDir: openapiDir,
|
||||||
|
separator: '_',
|
||||||
|
},
|
||||||
|
config: loadConfigAndHandleErrors() as any as Config,
|
||||||
|
version: 'cli-version',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(utils.pathToFilename).toBeCalledWith(expect.anything(), '_');
|
expect(utils.pathToFilename).toBeCalledWith(expect.anything(), '_');
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import type {
|
|||||||
Oas3PathItem,
|
Oas3PathItem,
|
||||||
Referenced,
|
Referenced,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
import type { CommandArgs } from '../../wrapper';
|
||||||
|
|
||||||
export type SplitOptions = {
|
export type SplitOptions = {
|
||||||
api: string;
|
api: string;
|
||||||
@@ -44,12 +45,13 @@ export type SplitOptions = {
|
|||||||
config?: string;
|
config?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function handleSplit(argv: SplitOptions) {
|
export async function handleSplit({ argv, collectSpecData }: CommandArgs<SplitOptions>) {
|
||||||
const startedAt = performance.now();
|
const startedAt = performance.now();
|
||||||
const { api, outDir, separator } = argv;
|
const { api, outDir, separator } = argv;
|
||||||
validateDefinitionFileName(api!);
|
validateDefinitionFileName(api!);
|
||||||
const ext = getAndValidateFileExtension(api);
|
const ext = getAndValidateFileExtension(api);
|
||||||
const openapi = readYaml(api!) as Oas3Definition | Oas3_1Definition;
|
const openapi = readYaml(api!) as Oas3Definition | Oas3_1Definition;
|
||||||
|
collectSpecData?.(openapi);
|
||||||
splitDefinition(openapi, outDir, separator, ext);
|
splitDefinition(openapi, outDir, separator, ext);
|
||||||
process.stderr.write(
|
process.stderr.write(
|
||||||
`🪓 Document: ${blue(api!)} ${green('is successfully split')}
|
`🪓 Document: ${blue(api!)} ${green('is successfully split')}
|
||||||
@@ -292,7 +294,7 @@ function iteratePathItems(
|
|||||||
|
|
||||||
for (const pathName of Object.keys(pathItems)) {
|
for (const pathName of Object.keys(pathItems)) {
|
||||||
const pathFile = `${path.join(outDir, pathToFilename(pathName, pathSeparator))}.${ext}`;
|
const pathFile = `${path.join(outDir, pathToFilename(pathName, pathSeparator))}.${ext}`;
|
||||||
const pathData = pathItems[pathName] as Oas3PathItem;
|
const pathData = pathItems[pathName];
|
||||||
|
|
||||||
if (isRef(pathData)) continue;
|
if (isRef(pathData)) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import * as colors from 'colorette';
|
import * as colors from 'colorette';
|
||||||
import {
|
import {
|
||||||
Config,
|
|
||||||
StyleguideConfig,
|
StyleguideConfig,
|
||||||
normalizeTypes,
|
normalizeTypes,
|
||||||
BaseResolver,
|
BaseResolver,
|
||||||
@@ -15,7 +14,9 @@ import {
|
|||||||
} from '@redocly/openapi-core';
|
} from '@redocly/openapi-core';
|
||||||
import { getFallbackApisOrExit } from '../utils/miscellaneous';
|
import { getFallbackApisOrExit } from '../utils/miscellaneous';
|
||||||
import { printExecutionTime } from '../utils/miscellaneous';
|
import { printExecutionTime } from '../utils/miscellaneous';
|
||||||
|
|
||||||
import type { StatsAccumulator, StatsName, WalkContext, OutputFormat } from '@redocly/openapi-core';
|
import type { StatsAccumulator, StatsName, WalkContext, OutputFormat } from '@redocly/openapi-core';
|
||||||
|
import type { CommandArgs } from '../wrapper';
|
||||||
|
|
||||||
const statsAccumulator: StatsAccumulator = {
|
const statsAccumulator: StatsAccumulator = {
|
||||||
refs: { metric: '🚗 References', total: 0, color: 'red', items: new Set() },
|
refs: { metric: '🚗 References', total: 0, color: 'red', items: new Set() },
|
||||||
@@ -86,10 +87,11 @@ export type StatsOptions = {
|
|||||||
config?: string;
|
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 [{ path }] = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
|
||||||
const externalRefResolver = new BaseResolver(config.resolve);
|
const externalRefResolver = new BaseResolver(config.resolve);
|
||||||
const { bundle: document } = await bundle({ config, ref: path });
|
const { bundle: document } = await bundle({ config, ref: path });
|
||||||
|
collectSpecData?.(document.parsed);
|
||||||
const lintConfig: StyleguideConfig = config.styleguide;
|
const lintConfig: StyleguideConfig = config.styleguide;
|
||||||
const specVersion = detectSpec(document.parsed);
|
const specVersion = detectSpec(document.parsed);
|
||||||
const types = normalizeTypes(
|
const types = normalizeTypes(
|
||||||
|
|||||||
@@ -541,7 +541,10 @@ export function cleanColors(input: string): string {
|
|||||||
export async function sendTelemetry(
|
export async function sendTelemetry(
|
||||||
argv: Arguments | undefined,
|
argv: Arguments | undefined,
|
||||||
exit_code: ExitCode,
|
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> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
if (!argv) {
|
if (!argv) {
|
||||||
@@ -569,6 +572,9 @@ export async function sendTelemetry(
|
|||||||
environment_ci: process.env.CI,
|
environment_ci: process.env.CI,
|
||||||
raw_input: cleanRawInput(process.argv.slice(2)),
|
raw_input: cleanRawInput(process.argv.slice(2)),
|
||||||
has_config,
|
has_config,
|
||||||
|
spec_version,
|
||||||
|
spec_keyword,
|
||||||
|
spec_full_version,
|
||||||
};
|
};
|
||||||
await fetch(`https://api.redocly.com/registry/telemetry/cli`, {
|
await fetch(`https://api.redocly.com/registry/telemetry/cli`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -598,6 +604,9 @@ export type Analytics = {
|
|||||||
environment_ci?: string;
|
environment_ci?: string;
|
||||||
raw_input: string;
|
raw_input: string;
|
||||||
has_config?: boolean;
|
has_config?: boolean;
|
||||||
|
spec_version?: string;
|
||||||
|
spec_keyword?: string;
|
||||||
|
spec_full_version?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function isFile(value: string) {
|
function isFile(value: string) {
|
||||||
|
|||||||
@@ -1,22 +1,48 @@
|
|||||||
import { Config, Region, doesYamlFileExist } from '@redocly/openapi-core';
|
import { detectSpec, doesYamlFileExist } from '@redocly/openapi-core';
|
||||||
import type { Arguments } from 'yargs';
|
import { isPlainObject } from '@redocly/openapi-core/lib/utils';
|
||||||
import { version } from './utils/update-version-notifier';
|
import { version } from './utils/update-version-notifier';
|
||||||
import {
|
import { exitWithError, loadConfigAndHandleErrors, sendTelemetry } from './utils/miscellaneous';
|
||||||
ExitCode,
|
|
||||||
exitWithError,
|
|
||||||
loadConfigAndHandleErrors,
|
|
||||||
sendTelemetry,
|
|
||||||
} from './utils/miscellaneous';
|
|
||||||
import { lintConfigCallback } from './commands/lint';
|
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';
|
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>(
|
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>) => {
|
return async (argv: Arguments<T>) => {
|
||||||
let code: ExitCode = 2;
|
let code: ExitCode = 2;
|
||||||
let hasConfig;
|
let hasConfig;
|
||||||
let telemetry;
|
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 {
|
try {
|
||||||
if (argv.config && !doesYamlFileExist(argv.config)) {
|
if (argv.config && !doesYamlFileExist(argv.config)) {
|
||||||
exitWithError('Please provide a valid path to the configuration file.');
|
exitWithError('Please provide a valid path to the configuration file.');
|
||||||
@@ -32,14 +58,14 @@ export function commandWrapper<T extends CommandOptions>(
|
|||||||
hasConfig = !config.styleguide.recommendedFallback;
|
hasConfig = !config.styleguide.recommendedFallback;
|
||||||
code = 1;
|
code = 1;
|
||||||
if (typeof commandHandler === 'function') {
|
if (typeof commandHandler === 'function') {
|
||||||
await commandHandler(argv, config, version);
|
await commandHandler({ argv, config, version, collectSpecData });
|
||||||
}
|
}
|
||||||
code = 0;
|
code = 0;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} finally {
|
} finally {
|
||||||
if (process.env.REDOCLY_TELEMETRY !== 'off' && telemetry !== 'off') {
|
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.once('beforeExit', () => {
|
||||||
process.exit(code);
|
process.exit(code);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import type { WalkContext, UserContext, ResolveResult, NormalizedProblem } from
|
|||||||
import type { Config, StyleguideConfig } from './config';
|
import type { Config, StyleguideConfig } from './config';
|
||||||
import type { OasRef } from './typings/openapi';
|
import type { OasRef } from './typings/openapi';
|
||||||
import type { Document, ResolvedRefMap } from './resolve';
|
import type { Document, ResolvedRefMap } from './resolve';
|
||||||
|
import type { CollectFn } from './utils';
|
||||||
|
|
||||||
export enum OasVersion {
|
export enum OasVersion {
|
||||||
Version2 = 'oas2',
|
Version2 = 'oas2',
|
||||||
@@ -82,6 +83,7 @@ export async function bundle(
|
|||||||
opts: {
|
opts: {
|
||||||
ref?: string;
|
ref?: string;
|
||||||
doc?: Document;
|
doc?: Document;
|
||||||
|
collectSpecData?: CollectFn;
|
||||||
} & BundleOptions
|
} & BundleOptions
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
@@ -100,6 +102,7 @@ export async function bundle(
|
|||||||
if (document instanceof Error) {
|
if (document instanceof Error) {
|
||||||
throw document;
|
throw document;
|
||||||
}
|
}
|
||||||
|
opts.collectSpecData?.(document.parsed);
|
||||||
|
|
||||||
return bundleDocument({
|
return bundleDocument({
|
||||||
document,
|
document,
|
||||||
|
|||||||
@@ -22,14 +22,17 @@ import type {
|
|||||||
Oas3Visitor,
|
Oas3Visitor,
|
||||||
RuleInstanceConfig,
|
RuleInstanceConfig,
|
||||||
} from './visitors';
|
} from './visitors';
|
||||||
|
import type { CollectFn } from './utils';
|
||||||
|
|
||||||
export async function lint(opts: {
|
export async function lint(opts: {
|
||||||
ref: string;
|
ref: string;
|
||||||
config: Config;
|
config: Config;
|
||||||
externalRefResolver?: BaseResolver;
|
externalRefResolver?: BaseResolver;
|
||||||
|
collectSpecData?: CollectFn;
|
||||||
}) {
|
}) {
|
||||||
const { ref, externalRefResolver = new BaseResolver(opts.config.resolve) } = opts;
|
const { ref, externalRefResolver = new BaseResolver(opts.config.resolve) } = opts;
|
||||||
const document = (await externalRefResolver.resolveDocument(null, ref, true)) as Document;
|
const document = (await externalRefResolver.resolveDocument(null, ref, true)) as Document;
|
||||||
|
opts.collectSpecData?.(document.parsed);
|
||||||
|
|
||||||
return lintDocument({
|
return lintDocument({
|
||||||
document,
|
document,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {
|
import type {
|
||||||
Oas3Rule,
|
Oas3Rule,
|
||||||
Oas3Preprocessor,
|
Oas3Preprocessor,
|
||||||
Oas2Rule,
|
Oas2Rule,
|
||||||
@@ -16,7 +16,7 @@ import { Oas3_1Types } from './types/oas3_1';
|
|||||||
import { AsyncApi2Types } from './types/asyncapi2';
|
import { AsyncApi2Types } from './types/asyncapi2';
|
||||||
import { AsyncApi3Types } from './types/asyncapi3';
|
import { AsyncApi3Types } from './types/asyncapi3';
|
||||||
import { ArazzoTypes } from './types/arazzo';
|
import { ArazzoTypes } from './types/arazzo';
|
||||||
import {
|
import type {
|
||||||
BuiltInAsync2RuleId,
|
BuiltInAsync2RuleId,
|
||||||
BuiltInAsync3RuleId,
|
BuiltInAsync3RuleId,
|
||||||
BuiltInCommonOASRuleId,
|
BuiltInCommonOASRuleId,
|
||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
BuiltInOAS2RuleId,
|
BuiltInOAS2RuleId,
|
||||||
BuiltInOAS3RuleId,
|
BuiltInOAS3RuleId,
|
||||||
} from './types/redocly-yaml';
|
} from './types/redocly-yaml';
|
||||||
|
import { isPlainObject } from './utils';
|
||||||
|
|
||||||
export enum SpecVersion {
|
export enum SpecVersion {
|
||||||
OAS2 = 'oas2',
|
OAS2 = 'oas2',
|
||||||
@@ -93,8 +94,8 @@ export type Async2DecoratorsSet = Record<string, Async2Preprocessor>;
|
|||||||
export type Async3DecoratorsSet = Record<string, Async3Preprocessor>;
|
export type Async3DecoratorsSet = Record<string, Async3Preprocessor>;
|
||||||
export type ArazzoDecoratorsSet = Record<string, ArazzoPreprocessor>;
|
export type ArazzoDecoratorsSet = Record<string, ArazzoPreprocessor>;
|
||||||
|
|
||||||
export function detectSpec(root: any): SpecVersion {
|
export function detectSpec(root: unknown): SpecVersion {
|
||||||
if (typeof root !== 'object') {
|
if (!isPlainObject(root)) {
|
||||||
throw new Error(`Document must be JSON object, got ${typeof 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}"`);
|
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;
|
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;
|
return SpecVersion.OAS3_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,16 +115,15 @@ export function detectSpec(root: any): SpecVersion {
|
|||||||
return SpecVersion.OAS2;
|
return SpecVersion.OAS2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not detected yet
|
|
||||||
if (root.openapi || root.swagger) {
|
if (root.openapi || root.swagger) {
|
||||||
throw new Error(`Unsupported OpenAPI version: ${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;
|
return SpecVersion.Async2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root.asyncapi && root.asyncapi.startsWith('3.')) {
|
if (typeof root.asyncapi === 'string' && root.asyncapi.startsWith('3.')) {
|
||||||
return SpecVersion.Async3;
|
return SpecVersion.Async3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ export function detectSpec(root: any): SpecVersion {
|
|||||||
throw new Error(`Unsupported AsyncAPI version: ${root.asyncapi}`);
|
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;
|
return SpecVersion.Arazzo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,15 +38,15 @@ export function isDefined<T>(x: T | undefined): x is T {
|
|||||||
return x !== undefined;
|
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);
|
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;
|
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;
|
return Array.isArray(value) && value.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,3 +317,5 @@ export function dequal(foo: any, bar: any): boolean {
|
|||||||
|
|
||||||
return foo !== foo && bar !== bar;
|
return foo !== foo && bar !== bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CollectFn = (value: unknown) => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user