diff --git a/README.md b/README.md index b80acb92a..20f550819 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,8 @@ If you want to bypass the prompt to create or update an API definition, you can rdme openapi [path-to-file.json] --version={project-version} --create ``` +This command also has a dry run mode, which can be useful for initial setup and debugging. You can perform a dry run by supplying the `--dryRun` flag. + #### Editing (Re-Syncing) an Existing API Definition This will edit (re-sync) an existing API definition (identified by `--id`) within your ReadMe project. **This is the recommended approach for usage in CI environments.** @@ -150,6 +152,8 @@ You can add `--update` to the command so if there's only one API definition for rdme openapi [path-to-file.json] --version={project-version} --update ``` +This command also has a dry run mode, which can be useful for initial setup and debugging. You can perform a dry run by supplying the `--dryRun` flag. + #### Omitting the File Path If you run `rdme` within a directory that contains your OpenAPI or Swagger definition, you can omit the file path. `rdme` will then look for JSON or YAML files (including in sub-directories) that contain a top-level [`openapi`](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#fixed-fields) or [`swagger`](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#fixed-fields) property. diff --git a/__tests__/__snapshots__/index.test.ts.snap b/__tests__/__snapshots__/index.test.ts.snap index 221435808..1237c294a 100644 --- a/__tests__/__snapshots__/index.test.ts.snap +++ b/__tests__/__snapshots__/index.test.ts.snap @@ -24,6 +24,8 @@ Options --create Bypasses the create/update prompt and creates a new API definition. --update Automatically update an existing API definition in ReadMe if it's the only one associated with the current version. + --dryRun Runs the command without creating/updating any API Definitions in + ReadMe. Useful for debugging. -h, --help Display this usage guide Related commands @@ -57,6 +59,8 @@ Options --create Bypasses the create/update prompt and creates a new API definition. --update Automatically update an existing API definition in ReadMe if it's the only one associated with the current version. + --dryRun Runs the command without creating/updating any API Definitions in + ReadMe. Useful for debugging. -h, --help Display this usage guide Related commands @@ -90,6 +94,8 @@ Options --create Bypasses the create/update prompt and creates a new API definition. --update Automatically update an existing API definition in ReadMe if it's the only one associated with the current version. + --dryRun Runs the command without creating/updating any API Definitions in + ReadMe. Useful for debugging. -h, --help Display this usage guide Related commands diff --git a/__tests__/cmds/openapi/index.test.ts b/__tests__/cmds/openapi/index.test.ts index efa87f85b..1348e7494 100644 --- a/__tests__/cmds/openapi/index.test.ts +++ b/__tests__/cmds/openapi/index.test.ts @@ -368,6 +368,41 @@ describe('rdme openapi', () => { return mock.done(); }); + it('should return spec create info for dry run', async () => { + const registryUUID = getRandomRegistryId(); + + const mock = getAPIMock() + .get(`/api/v1/version/${version}`) + .basicAuth({ user: key }) + .reply(200, { version }) + .post('/api/v1/api-registry', body => body.match('form-data; name="spec"')) + .reply(201, { registryUUID, spec: { openapi: '3.0.0' } }); + + const mockWithHeader = getAPIMockWithVersionHeader(version) + .get('/api/v1/api-specification') + .basicAuth({ user: key }) + .reply(200, []); + + await expect( + openapi.run({ + key, + version, + dryRun: true, + workingDirectory: './__tests__/__fixtures__/relative-ref-oas', + }) + ).resolves.toMatch( + '🎭 dry run! The API Definition located at petstore.json will be created for this project version: 1.0.0' + ); + + const output = getCommandOutput(); + expect(output).toMatch( + chalk.yellow('🎭 dry run option detected! No API definitions will be created or updated in ReadMe.') + ); + + mockWithHeader.done(); + return mock.done(); + }); + describe('CI spec selection', () => { beforeEach(() => { process.env.TEST_CI = 'true'; @@ -488,6 +523,40 @@ describe('rdme openapi', () => { return mock.done(); }); + it('should return spec update info for dry run', async () => { + prompts.inject(['update', 'spec2']); + const registryUUID = getRandomRegistryId(); + + const mock = getAPIMock() + .get(`/api/v1/version/${version}`) + .basicAuth({ user: key }) + .reply(200, { version }) + .post('/api/v1/api-registry', body => body.match('form-data; name="spec"')) + .reply(201, { registryUUID, spec: { openapi: '3.0.0' } }); + + const mockWithHeader = getAPIMockWithVersionHeader(version) + .get('/api/v1/api-specification') + .basicAuth({ user: key }) + .reply(200, [ + { _id: 'spec1', title: 'spec1_title' }, + { _id: 'spec2', title: 'spec2_title' }, + ]); + + const spec = './__tests__/__fixtures__/ref-oas/petstore.json'; + + await expect( + openapi.run({ + key, + version, + spec, + dryRun: true, + }) + ).resolves.toMatch(`dry run! The API Definition located at ${spec} will update this API Definition ID: spec2`); + + mockWithHeader.done(); + return mock.done(); + }); + describe('--update', () => { it("should update a spec file without prompts if providing `update` and it's the one spec available", async () => { const registryUUID = getRandomRegistryId(); diff --git a/src/cmds/openapi/index.ts b/src/cmds/openapi/index.ts index 2a922c6f9..f9ac8d23d 100644 --- a/src/cmds/openapi/index.ts +++ b/src/cmds/openapi/index.ts @@ -26,6 +26,7 @@ export type Options = { useSpecVersion?: boolean; workingDirectory?: string; update?: boolean; + dryRun?: boolean; }; export default class OpenAPICommand extends Command { @@ -81,13 +82,18 @@ export default class OpenAPICommand extends Command { description: "Automatically update an existing API definition in ReadMe if it's the only one associated with the current version.", }, + { + name: 'dryRun', + type: Boolean, + description: 'Runs the command without creating/updating any API Definitions in ReadMe. Useful for debugging.', + }, ]; } async run(opts: CommandOptions) { super.run(opts); - const { key, id, spec, create, raw, useSpecVersion, version, workingDirectory, update } = opts; + const { dryRun, key, id, spec, create, raw, useSpecVersion, version, workingDirectory, update } = opts; let selectedVersion = version; let isUpdate: boolean; @@ -98,6 +104,10 @@ export default class OpenAPICommand extends Command { */ const ignoredGHAParameters: Options = { version: undefined, update: undefined }; + if (dryRun) { + Command.warn('🎭 dry run option detected! No API definitions will be created or updated in ReadMe.'); + } + if (create && update) { throw new Error( 'The `--create` and `--update` options cannot be used simultaneously. Please use one or the other!' @@ -224,6 +234,10 @@ export default class OpenAPICommand extends Command { }; function createSpec() { + if (dryRun) { + return `🎭 dry run! The API Definition located at ${specPath} will be created for this project version: ${selectedVersion}`; + } + options.method = 'post'; spinner.start('Creating your API docs in ReadMe...'); return fetch(`${config.get('host')}/api/v1/api-specification`, options).then(res => { @@ -237,6 +251,10 @@ export default class OpenAPICommand extends Command { } function updateSpec(specId: string) { + if (dryRun) { + return `🎭 dry run! The API Definition located at ${specPath} will update this API Definition ID: ${specId}`; + } + isUpdate = true; options.method = 'put'; spinner.start('Updating your API docs in ReadMe...');