From 7552501049264112096e5d9125af16df35ff46f4 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Thu, 27 Oct 2022 16:38:26 -0400 Subject: [PATCH] feat(docs): consolidate `single` commands (#642) * chore: remove JSDoc types * refactor(changelogs): remove single command * chore: clean up comment * test(changelogs): fix tests * refactor: file/func name, param order also adding JSDocs * refactor: another small thing * fix: whoops * test(changelogs): small cleanup * feat: consolidate custompage commands * docs(changelog/custompages): updates * chore: rename files * test: small naming convention fix * feat: consolidate docs commands * refactor: consolidate function * chore: whooops * docs: cleanup --- README.md | 44 +------ __tests__/cmds/changelogs/index.test.ts | 32 ++--- __tests__/cmds/changelogs/single.test.ts | 48 ++++--- __tests__/cmds/custompages/index.test.ts | 32 ++--- __tests__/cmds/custompages/single.test.ts | 52 ++++---- __tests__/cmds/docs/index.test.ts | 46 ++++--- __tests__/cmds/docs/single.test.ts | 56 ++++---- __tests__/index.test.ts | 22 ++-- .../lib/__snapshots__/commands.test.ts.snap | 24 +--- .../lib/__snapshots__/createGHA.test.ts.snap | 122 +++++++++--------- __tests__/lib/commands.test.ts | 4 +- __tests__/lib/createGHA.test.ts | 15 +-- src/cmds/changelogs.ts | 48 +++++++ src/cmds/changelogs/index.ts | 72 ----------- src/cmds/changelogs/single.ts | 60 --------- src/cmds/custompages.ts | 48 +++++++ src/cmds/custompages/index.ts | 75 ----------- src/cmds/custompages/single.ts | 65 ---------- src/cmds/docs/index.ts | 44 ++----- src/cmds/docs/single.ts | 70 ---------- src/cmds/index.ts | 7 - src/lib/{pushDoc.ts => syncDocsPath.ts} | 94 ++++++++++++-- 22 files changed, 419 insertions(+), 661 deletions(-) create mode 100644 src/cmds/changelogs.ts delete mode 100644 src/cmds/changelogs/index.ts delete mode 100644 src/cmds/changelogs/single.ts create mode 100644 src/cmds/custompages.ts delete mode 100644 src/cmds/custompages/index.ts delete mode 100644 src/cmds/custompages/single.ts delete mode 100644 src/cmds/docs/single.ts rename src/lib/{pushDoc.ts => syncDocsPath.ts} (56%) diff --git a/README.md b/README.md index 326d8d817..9c4effd99 100644 --- a/README.md +++ b/README.md @@ -195,14 +195,12 @@ The command will ask you a couple questions about how you wish to reduce the fil ### Docs -#### Syncing a Folder of Markdown Docs to ReadMe - The Markdown files will require YAML front matter with certain ReadMe documentation attributes. Check out [our docs](https://docs.readme.com/docs/rdme#markdown-file-setup) for more info on setting up your front matter. -Passing in a path to a directory will also sync any Markdown files that are located in subdirectories. +Passing in a path to a directory will also sync any Markdown files that are located in subdirectories. The path input can also be individual Markdown files. ```sh -rdme docs path-to-markdown-files --version={project-version} +rdme docs [path] --version={project-version} ``` This command also has a dry run mode, which can be useful for initial setup and debugging. You can read more about dry run mode [in our docs](https://docs.readme.com/docs/rdme#dry-run-mode). @@ -212,61 +210,33 @@ This command also has a dry run mode, which can be useful for initial setup and If you wish to delete documents from ReadMe that are no longer present in your local directory: ```sh -rdme docs:prune path-to-markdown-files -``` - -#### Edit a Single ReadMe Doc on Your Local Machine - -```sh -rdme docs:edit --version={project-version} -``` - -#### Syncing a Single Markdown File to ReadMe - -```sh -rdme docs:single path-to-markdown-file --version={project-version} +rdme docs:prune path-to-directory-of-markdown ``` ### Changelogs -#### Syncing a Folder of Markdown to ReadMe - The Markdown files will require YAML front matter with certain ReadMe documentation attributes. Check out [our docs](https://docs.readme.com/docs/rdme#markdown-file-setup) for more info on setting up your front matter. -Passing in a path to a directory will also sync any Markdown files that are located in subdirectories. +Passing in a path to a directory will also sync any Markdown files that are located in subdirectories. The path input can also be individual Markdown files. ```sh -rdme changelogs path-to-markdown-files +rdme changelogs [path] ``` This command also has a dry run mode, which can be useful for initial setup and debugging. You can read more about dry run mode [in our docs](https://docs.readme.com/docs/rdme#dry-run-mode). -#### Syncing a Single Markdown File to ReadMe - -```sh -rdme changelogs:single path-to-markdown-file -``` - ### Custom Pages -#### Syncing a Folder of Custom Pages to ReadMe - Custom Pages has support for both Markdown and HTML files. These files will require YAML front matter with certain ReadMe documentation attributes. Check out [our docs](https://docs.readme.com/docs/rdme#markdown-file-setup) for more info on setting up your front matter. -Passing in a path to a directory will also sync any HTML/Markdown files that are located in subdirectories. +Passing in a path to a directory will also sync any HTML/Markdown files that are located in subdirectories. The path input can also be individual HTML/Markdown files. ```sh -rdme custompages path-to-markdown-files +rdme custompages [path] ``` This command also has a dry run mode, which can be useful for initial setup and debugging. You can read more about dry run mode [in our docs](https://docs.readme.com/docs/rdme#dry-run-mode). -#### Syncing a Single Custom Page to ReadMe - -```sh -rdme custompages:single path-to-markdown-file -``` - ### Versions #### Get All Versions Associated With Your Project diff --git a/__tests__/cmds/changelogs/index.test.ts b/__tests__/cmds/changelogs/index.test.ts index 1640db25c..b655ba02d 100644 --- a/__tests__/cmds/changelogs/index.test.ts +++ b/__tests__/cmds/changelogs/index.test.ts @@ -37,21 +37,23 @@ describe('rdme changelogs', () => { delete process.env.TEST_CI; }); - it('should error if no folder provided', () => { - return expect(changelogs.run({ key })).rejects.toThrow( - 'No folder provided. Usage `rdme changelogs [options]`.' + it('should error if no path provided', () => { + return expect(changelogs.run({ key })).rejects.toStrictEqual( + new Error('No path provided. Usage `rdme changelogs [options]`.') ); }); it('should error if the argument is not a folder', () => { - return expect(changelogs.run({ key, folder: 'not-a-folder' })).rejects.toThrow( - "ENOENT: no such file or directory, scandir 'not-a-folder'" + return expect(changelogs.run({ key, filePath: 'not-a-folder' })).rejects.toStrictEqual( + new Error("Oops! We couldn't locate a file or directory at the path you provided.") ); }); it('should error if the folder contains no markdown files', () => { - return expect(changelogs.run({ key, folder: '.github/workflows' })).rejects.toThrow( - 'We were unable to locate Markdown files in .github/workflows.' + return expect(changelogs.run({ key, filePath: '.github/workflows' })).rejects.toStrictEqual( + new Error( + "The directory you provided (.github/workflows) doesn't contain any of the following required files: .markdown, .md." + ) ); }); @@ -107,7 +109,7 @@ describe('rdme changelogs', () => { .basicAuth({ user: key }) .reply(200, { slug: anotherDoc.slug, body: anotherDoc.doc.content }); - return changelogs.run({ folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key }).then(updatedDocs => { + return changelogs.run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key }).then(updatedDocs => { // All changelogs should have been updated because their hashes from the GET request were different from what they // are currently. expect(updatedDocs).toBe( @@ -134,7 +136,7 @@ describe('rdme changelogs', () => { .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: 'anOldHash' }); return changelogs - .run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key }) + .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key }) .then(updatedDocs => { // All changelogs should have been updated because their hashes from the GET request were different from what they // are currently. @@ -164,7 +166,7 @@ describe('rdme changelogs', () => { .basicAuth({ user: key }) .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: anotherDoc.hash }); - return changelogs.run({ folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key }).then(skippedDocs => { + return changelogs.run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key }).then(skippedDocs => { expect(skippedDocs).toBe( [ '`simple-doc` was not updated because there were no changes.', @@ -188,7 +190,7 @@ describe('rdme changelogs', () => { .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: anotherDoc.hash }); return changelogs - .run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key }) + .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key }) .then(skippedDocs => { expect(skippedDocs).toBe( [ @@ -224,7 +226,7 @@ describe('rdme changelogs', () => { .basicAuth({ user: key }) .reply(201, { slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash }); - await expect(changelogs.run({ folder: `./__tests__/${fixturesBaseDir}/new-docs`, key })).resolves.toBe( + await expect(changelogs.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key })).resolves.toBe( `🌱 successfully created 'new-doc' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md` ); @@ -247,7 +249,7 @@ describe('rdme changelogs', () => { }); await expect( - changelogs.run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/new-docs`, key }) + changelogs.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key }) ).resolves.toBe( `🎭 dry run! This will create 'new-doc' with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md with the following metadata: ${JSON.stringify( doc.data @@ -313,7 +315,7 @@ describe('rdme changelogs', () => { message: `Error uploading ${chalk.underline(`${fullDirectory}/${slug}.md`)}:\n\n${errorObject.message}`, }; - await expect(changelogs.run({ folder: `./${fullDirectory}`, key })).rejects.toStrictEqual( + await expect(changelogs.run({ filePath: `./${fullDirectory}`, key })).rejects.toStrictEqual( new APIError(formattedErrorObject) ); @@ -344,7 +346,7 @@ describe('rdme changelogs', () => { .basicAuth({ user: key }) .reply(201, { slug: doc.data.slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash }); - await expect(changelogs.run({ folder: `./__tests__/${fixturesBaseDir}/slug-docs`, key })).resolves.toBe( + await expect(changelogs.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs`, key })).resolves.toBe( `🌱 successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md` ); diff --git a/__tests__/cmds/changelogs/single.test.ts b/__tests__/cmds/changelogs/single.test.ts index d20541e80..83f883f6c 100644 --- a/__tests__/cmds/changelogs/single.test.ts +++ b/__tests__/cmds/changelogs/single.test.ts @@ -6,18 +6,18 @@ import frontMatter from 'gray-matter'; import nock from 'nock'; import prompts from 'prompts'; -import SingleChangelogCommand from '../../../src/cmds/changelogs/single'; +import ChangelogsCommand from '../../../src/cmds/changelogs'; import APIError from '../../../src/lib/apiError'; import getAPIMock from '../../helpers/get-api-mock'; import hashFileContents from '../../helpers/hash-file-contents'; -const changelogsSingle = new SingleChangelogCommand(); +const changelogs = new ChangelogsCommand(); const fixturesBaseDir = '__fixtures__/changelogs'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; const key = 'API_KEY'; -describe('rdme changelogs:single', () => { +describe('rdme changelogs (single)', () => { beforeAll(() => nock.disableNetConnect()); afterAll(() => nock.cleanAll()); @@ -25,33 +25,33 @@ describe('rdme changelogs:single', () => { it('should prompt for login if no API key provided', async () => { const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(); prompts.inject(['this-is-not-an-email', 'password', 'subdomain']); - await expect(changelogsSingle.run({})).rejects.toStrictEqual(new Error('You must provide a valid email address.')); + await expect(changelogs.run({})).rejects.toStrictEqual(new Error('You must provide a valid email address.')); consoleInfoSpy.mockRestore(); }); it('should error in CI if no API key provided', async () => { process.env.TEST_CI = 'true'; - await expect(changelogsSingle.run({})).rejects.toStrictEqual( + await expect(changelogs.run({})).rejects.toStrictEqual( new Error('No project API key provided. Please use `--key`.') ); delete process.env.TEST_CI; }); it('should error if no file path provided', () => { - return expect(changelogsSingle.run({ key })).rejects.toThrow( - 'No file path provided. Usage `rdme changelogs:single [options]`.' + return expect(changelogs.run({ key })).rejects.toStrictEqual( + new Error('No path provided. Usage `rdme changelogs [options]`.') ); }); - it('should error if the argument is not a Markdown file', async () => { - await expect(changelogsSingle.run({ key, filePath: 'not-a-markdown-file' })).rejects.toThrow( - 'The file path specified is not a Markdown file.' + it('should error if the argument is not a Markdown file', () => { + return expect(changelogs.run({ key, filePath: 'package.json' })).rejects.toStrictEqual( + new Error('Invalid file extension (.json). Must be one of the following: .markdown, .md') ); }); - it('should support .markdown files but error if file path cannot be found', async () => { - await expect(changelogsSingle.run({ key, filePath: 'non-existent-file.markdown' })).rejects.toThrow( - 'ENOENT: no such file or directory' + it('should support .markdown files but error if file path cannot be found', () => { + return expect(changelogs.run({ key, filePath: 'non-existent-file.markdown' })).rejects.toStrictEqual( + new Error("Oops! We couldn't locate a file or directory at the path you provided.") ); }); @@ -78,7 +78,7 @@ describe('rdme changelogs:single', () => { .reply(201, { slug, _id: id, body: doc.content, ...doc.data }); await expect( - changelogsSingle.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key }) + changelogs.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key }) ).resolves.toBe( `🌱 successfully created 'new-doc' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md` ); @@ -102,7 +102,7 @@ describe('rdme changelogs:single', () => { }); await expect( - changelogsSingle.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key }) + changelogs.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key }) ).resolves.toBe( `🎭 dry run! This will create 'new-doc' with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md with the following metadata: ${JSON.stringify( doc.data @@ -150,9 +150,7 @@ describe('rdme changelogs:single', () => { message: `Error uploading ${chalk.underline(`${filePath}`)}:\n\n${errorObject.message}`, }; - await expect(changelogsSingle.run({ filePath: `${filePath}`, key })).rejects.toStrictEqual( - new APIError(formattedErrorObject) - ); + await expect(changelogs.run({ filePath, key })).rejects.toStrictEqual(new APIError(formattedErrorObject)); getMock.done(); postMock.done(); @@ -177,9 +175,7 @@ describe('rdme changelogs:single', () => { message: `Error uploading ${chalk.underline(`${filePath}`)}:\n\n${errorObject.message}`, }; - await expect(changelogsSingle.run({ filePath: `${filePath}`, key })).rejects.toStrictEqual( - new APIError(formattedErrorObject) - ); + await expect(changelogs.run({ filePath, key })).rejects.toStrictEqual(new APIError(formattedErrorObject)); getMock.done(); }); @@ -208,7 +204,7 @@ describe('rdme changelogs:single', () => { .reply(201, { slug: doc.data.slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash }); await expect( - changelogsSingle.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`, key }) + changelogs.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`, key }) ).resolves.toBe( `🌱 successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md` ); @@ -249,7 +245,7 @@ describe('rdme changelogs:single', () => { body: simpleDoc.doc.content, }); - return changelogsSingle + return changelogs .run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key }) .then(updatedDocs => { expect(updatedDocs).toBe( @@ -269,7 +265,7 @@ describe('rdme changelogs:single', () => { .basicAuth({ user: key }) .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' }); - return changelogsSingle + return changelogs .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key }) .then(updatedDocs => { // All changelogs should have been updated because their hashes from the GET request were different from what they @@ -294,7 +290,7 @@ describe('rdme changelogs:single', () => { .basicAuth({ user: key }) .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash }); - return changelogsSingle + return changelogs .run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key }) .then(skippedDocs => { expect(skippedDocs).toBe('`simple-doc` was not updated because there were no changes.'); @@ -309,7 +305,7 @@ describe('rdme changelogs:single', () => { .basicAuth({ user: key }) .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash }); - return changelogsSingle + return changelogs .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key }) .then(skippedDocs => { expect(skippedDocs).toBe('🎭 dry run! `simple-doc` will not be updated because there were no changes.'); diff --git a/__tests__/cmds/custompages/index.test.ts b/__tests__/cmds/custompages/index.test.ts index c1541e7c8..abdb5dc1a 100644 --- a/__tests__/cmds/custompages/index.test.ts +++ b/__tests__/cmds/custompages/index.test.ts @@ -37,21 +37,23 @@ describe('rdme custompages', () => { delete process.env.TEST_CI; }); - it('should error if no folder provided', () => { + it('should error if no path provided', () => { return expect(custompages.run({ key })).rejects.toStrictEqual( - new Error('No folder provided. Usage `rdme custompages [options]`.') + new Error('No path provided. Usage `rdme custompages [options]`.') ); }); it('should error if the argument is not a folder', () => { - return expect(custompages.run({ key, version: '1.0.0', folder: 'not-a-folder' })).rejects.toThrow( - "ENOENT: no such file or directory, scandir 'not-a-folder'" + return expect(custompages.run({ key, filePath: 'not-a-folder' })).rejects.toStrictEqual( + new Error("Oops! We couldn't locate a file or directory at the path you provided.") ); }); it('should error if the folder contains no markdown nor HTML files', () => { - return expect(custompages.run({ key, folder: '.github/workflows' })).rejects.toStrictEqual( - new Error('We were unable to locate Markdown or HTML files in .github/workflows.') + return expect(custompages.run({ key, filePath: '.github/workflows' })).rejects.toStrictEqual( + new Error( + "The directory you provided (.github/workflows) doesn't contain any of the following required files: .html, .markdown, .md." + ) ); }); @@ -110,7 +112,7 @@ describe('rdme custompages', () => { .basicAuth({ user: key }) .reply(200, { slug: anotherDoc.slug, body: anotherDoc.doc.content, htmlmode: false }); - return custompages.run({ folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key }).then(updatedDocs => { + return custompages.run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key }).then(updatedDocs => { // All custompages should have been updated because their hashes from the GET request were different from what they // are currently. expect(updatedDocs).toBe( @@ -137,7 +139,7 @@ describe('rdme custompages', () => { .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: 'anOldHash' }); return custompages - .run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key }) + .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key }) .then(updatedDocs => { // All custompages should have been updated because their hashes from the GET request were different from what they // are currently. @@ -167,7 +169,7 @@ describe('rdme custompages', () => { .basicAuth({ user: key }) .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: anotherDoc.hash }); - return custompages.run({ folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key }).then(skippedDocs => { + return custompages.run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key }).then(skippedDocs => { expect(skippedDocs).toBe( [ '`simple-doc` was not updated because there were no changes.', @@ -191,7 +193,7 @@ describe('rdme custompages', () => { .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: anotherDoc.hash }); return custompages - .run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key }) + .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key }) .then(skippedDocs => { expect(skippedDocs).toBe( [ @@ -227,7 +229,7 @@ describe('rdme custompages', () => { .basicAuth({ user: key }) .reply(201, { slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash }); - await expect(custompages.run({ folder: `./__tests__/${fixturesBaseDir}/new-docs`, key })).resolves.toBe( + await expect(custompages.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key })).resolves.toBe( `🌱 successfully created 'new-doc' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md` ); @@ -256,7 +258,7 @@ describe('rdme custompages', () => { .basicAuth({ user: key }) .reply(201, { slug, _id: id, html: doc.content, htmlmode: true, ...doc.data, lastUpdatedHash: hash }); - await expect(custompages.run({ folder: `./__tests__/${fixturesBaseDir}/new-docs-html`, key })).resolves.toBe( + await expect(custompages.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs-html`, key })).resolves.toBe( `🌱 successfully created 'new-doc' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/new-docs-html/new-doc.html` ); @@ -279,7 +281,7 @@ describe('rdme custompages', () => { }); await expect( - custompages.run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/new-docs`, key }) + custompages.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key }) ).resolves.toBe( `🎭 dry run! This will create 'new-doc' with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md with the following metadata: ${JSON.stringify( doc.data @@ -351,7 +353,7 @@ describe('rdme custompages', () => { message: `Error uploading ${chalk.underline(`${fullDirectory}/${slug}.md`)}:\n\n${errorObject.message}`, }; - await expect(custompages.run({ folder: `./${fullDirectory}`, key })).rejects.toStrictEqual( + await expect(custompages.run({ filePath: `./${fullDirectory}`, key })).rejects.toStrictEqual( new APIError(formattedErrorObject) ); @@ -382,7 +384,7 @@ describe('rdme custompages', () => { .basicAuth({ user: key }) .reply(201, { slug: doc.data.slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash }); - await expect(custompages.run({ folder: `./__tests__/${fixturesBaseDir}/slug-docs`, key })).resolves.toBe( + await expect(custompages.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs`, key })).resolves.toBe( `🌱 successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md` ); diff --git a/__tests__/cmds/custompages/single.test.ts b/__tests__/cmds/custompages/single.test.ts index 27dbb55df..2456d70fa 100644 --- a/__tests__/cmds/custompages/single.test.ts +++ b/__tests__/cmds/custompages/single.test.ts @@ -6,18 +6,18 @@ import frontMatter from 'gray-matter'; import nock from 'nock'; import prompts from 'prompts'; -import SingleCustomPageCommand from '../../../src/cmds/custompages/single'; +import CustomPagesCommand from '../../../src/cmds/custompages'; import APIError from '../../../src/lib/apiError'; import getAPIMock from '../../helpers/get-api-mock'; import hashFileContents from '../../helpers/hash-file-contents'; -const customPagesSingle = new SingleCustomPageCommand(); +const custompages = new CustomPagesCommand(); const fixturesBaseDir = '__fixtures__/custompages'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; const key = 'API_KEY'; -describe('rdme custompages:single', () => { +describe('rdme custompages (single)', () => { beforeAll(() => nock.disableNetConnect()); afterAll(() => nock.cleanAll()); @@ -25,34 +25,34 @@ describe('rdme custompages:single', () => { it('should prompt for login if no API key provided', async () => { const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(); prompts.inject(['this-is-not-an-email', 'password', 'subdomain']); - await expect(customPagesSingle.run({})).rejects.toStrictEqual(new Error('You must provide a valid email address.')); + await expect(custompages.run({})).rejects.toStrictEqual(new Error('You must provide a valid email address.')); consoleInfoSpy.mockRestore(); }); it('should error in CI if no API key provided', async () => { process.env.TEST_CI = 'true'; - await expect(customPagesSingle.run({})).rejects.toStrictEqual( + await expect(custompages.run({})).rejects.toStrictEqual( new Error('No project API key provided. Please use `--key`.') ); delete process.env.TEST_CI; }); it('should error if no file path provided', () => { - return expect(customPagesSingle.run({ key })).rejects.toStrictEqual( - new Error('No file path provided. Usage `rdme custompages:single [options]`.') + return expect(custompages.run({ key })).rejects.toStrictEqual( + new Error('No path provided. Usage `rdme custompages [options]`.') ); }); - it('should error if the argument is not a Markdown file', async () => { - await expect(customPagesSingle.run({ key, filePath: 'not-a-markdown-file' })).rejects.toStrictEqual( - new Error('The file path specified is not a Markdown or HTML file.') + it('should error if the argument is not a Markdown/HTML file', () => { + return expect(custompages.run({ key, filePath: 'package.json' })).rejects.toStrictEqual( + new Error('Invalid file extension (.json). Must be one of the following: .html, .markdown, .md') ); }); - it('should error if file path cannot be found', async () => { - await expect( - customPagesSingle.run({ key, version: '1.0.0', filePath: 'non-existent-file.markdown' }) - ).rejects.toThrow('ENOENT: no such file or directory'); + it('should error if file path cannot be found', () => { + return expect( + custompages.run({ key, version: '1.0.0', filePath: 'non-existent-file.markdown' }) + ).rejects.toStrictEqual(new Error("Oops! We couldn't locate a file or directory at the path you provided.")); }); describe('new custompages', () => { @@ -78,7 +78,7 @@ describe('rdme custompages:single', () => { .reply(201, { slug, _id: id, body: doc.content, ...doc.data }); await expect( - customPagesSingle.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key }) + custompages.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key }) ).resolves.toBe( `🌱 successfully created 'new-doc' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md` ); @@ -109,7 +109,7 @@ describe('rdme custompages:single', () => { .reply(201, { slug, _id: id, html: doc.content, htmlmode: true, ...doc.data }); await expect( - customPagesSingle.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs-html/new-doc.html`, key }) + custompages.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs-html/new-doc.html`, key }) ).resolves.toBe( `🌱 successfully created 'new-doc' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/new-docs-html/new-doc.html` ); @@ -133,7 +133,7 @@ describe('rdme custompages:single', () => { }); await expect( - customPagesSingle.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key }) + custompages.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key }) ).resolves.toBe( `🎭 dry run! This will create 'new-doc' with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md with the following metadata: ${JSON.stringify( doc.data @@ -181,9 +181,7 @@ describe('rdme custompages:single', () => { message: `Error uploading ${chalk.underline(`${filePath}`)}:\n\n${errorObject.message}`, }; - await expect(customPagesSingle.run({ filePath: `${filePath}`, key })).rejects.toStrictEqual( - new APIError(formattedErrorObject) - ); + await expect(custompages.run({ filePath, key })).rejects.toStrictEqual(new APIError(formattedErrorObject)); getMock.done(); postMock.done(); @@ -208,9 +206,7 @@ describe('rdme custompages:single', () => { message: `Error uploading ${chalk.underline(`${filePath}`)}:\n\n${errorObject.message}`, }; - await expect(customPagesSingle.run({ filePath: `${filePath}`, key })).rejects.toStrictEqual( - new APIError(formattedErrorObject) - ); + await expect(custompages.run({ filePath, key })).rejects.toStrictEqual(new APIError(formattedErrorObject)); getMock.done(); }); @@ -239,7 +235,7 @@ describe('rdme custompages:single', () => { .reply(201, { slug: doc.data.slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash }); await expect( - customPagesSingle.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`, key }) + custompages.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`, key }) ).resolves.toBe( `🌱 successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md` ); @@ -282,7 +278,7 @@ describe('rdme custompages:single', () => { htmlmode: false, }); - return customPagesSingle + return custompages .run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key }) .then(updatedDocs => { expect(updatedDocs).toBe( @@ -302,7 +298,7 @@ describe('rdme custompages:single', () => { .basicAuth({ user: key }) .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' }); - return customPagesSingle + return custompages .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key }) .then(updatedDocs => { // All custompages should have been updated because their hashes from the GET request were different from what they @@ -327,7 +323,7 @@ describe('rdme custompages:single', () => { .basicAuth({ user: key }) .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash }); - return customPagesSingle + return custompages .run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key }) .then(skippedDocs => { expect(skippedDocs).toBe('`simple-doc` was not updated because there were no changes.'); @@ -342,7 +338,7 @@ describe('rdme custompages:single', () => { .basicAuth({ user: key }) .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash }); - return customPagesSingle + return custompages .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key }) .then(skippedDocs => { expect(skippedDocs).toBe('🎭 dry run! `simple-doc` will not be updated because there were no changes.'); diff --git a/__tests__/cmds/docs/index.test.ts b/__tests__/cmds/docs/index.test.ts index ae265eea6..497baafdb 100644 --- a/__tests__/cmds/docs/index.test.ts +++ b/__tests__/cmds/docs/index.test.ts @@ -43,17 +43,21 @@ describe('rdme docs', () => { delete process.env.TEST_CI; }); - it('should error if no folder provided', () => { - return expect(docs.run({ key, version: '1.0.0' })).rejects.toThrow( - 'No folder provided. Usage `rdme docs [options]`.' + it('should error if no path provided', async () => { + const versionMock = getAPIMock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); + + await expect(docs.run({ key, version: '1.0.0' })).rejects.toStrictEqual( + new Error('No path provided. Usage `rdme docs [options]`.') ); + + versionMock.done(); }); it('should error if the argument is not a folder', async () => { const versionMock = getAPIMock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); - await expect(docs.run({ key, version: '1.0.0', folder: 'not-a-folder' })).rejects.toThrow( - "ENOENT: no such file or directory, scandir 'not-a-folder'" + await expect(docs.run({ key, version: '1.0.0', filePath: 'not-a-folder' })).rejects.toStrictEqual( + new Error("Oops! We couldn't locate a file or directory at the path you provided.") ); versionMock.done(); @@ -62,8 +66,10 @@ describe('rdme docs', () => { it('should error if the folder contains no markdown files', async () => { const versionMock = getAPIMock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); - await expect(docs.run({ key, version: '1.0.0', folder: '.github/workflows' })).rejects.toThrow( - 'We were unable to locate Markdown files in .github/workflows.' + await expect(docs.run({ key, version: '1.0.0', filePath: '.github/workflows' })).rejects.toStrictEqual( + new Error( + "The directory you provided (.github/workflows) doesn't contain any of the following required files: .markdown, .md." + ) ); versionMock.done(); @@ -129,7 +135,7 @@ describe('rdme docs', () => { .basicAuth({ user: key }) .reply(200, { version }); - return docs.run({ folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key, version }).then(updatedDocs => { + return docs.run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key, version }).then(updatedDocs => { // All docs should have been updated because their hashes from the GET request were different from what they // are currently. expect(updatedDocs).toBe( @@ -162,7 +168,7 @@ describe('rdme docs', () => { .reply(200, { version }); return docs - .run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key, version }) + .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key, version }) .then(updatedDocs => { // All docs should have been updated because their hashes from the GET request were different from what they // are currently. @@ -198,7 +204,7 @@ describe('rdme docs', () => { .basicAuth({ user: key }) .reply(200, { version }); - return docs.run({ folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key, version }).then(skippedDocs => { + return docs.run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key, version }).then(skippedDocs => { expect(skippedDocs).toBe( [ '`simple-doc` was not updated because there were no changes.', @@ -228,7 +234,7 @@ describe('rdme docs', () => { .reply(200, { version }); return docs - .run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/existing-docs`, key, version }) + .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs`, key, version }) .then(skippedDocs => { expect(skippedDocs).toBe( [ @@ -270,7 +276,7 @@ describe('rdme docs', () => { .basicAuth({ user: key }) .reply(200, { version }); - await expect(docs.run({ folder: `./__tests__/${fixturesBaseDir}/new-docs`, key, version })).resolves.toBe( + await expect(docs.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key, version })).resolves.toBe( `🌱 successfully created 'new-doc' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md` ); @@ -299,7 +305,7 @@ describe('rdme docs', () => { .reply(200, { version }); await expect( - docs.run({ dryRun: true, folder: `./__tests__/${fixturesBaseDir}/new-docs`, key, version }) + docs.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key, version }) ).resolves.toBe( `🎭 dry run! This will create 'new-doc' with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md with the following metadata: ${JSON.stringify( doc.data @@ -379,7 +385,7 @@ describe('rdme docs', () => { message: `Error uploading ${chalk.underline(`${fullDirectory}/${slug}.md`)}:\n\n${errorObject.message}`, }; - await expect(docs.run({ folder: `./${fullDirectory}`, key, version })).rejects.toStrictEqual( + await expect(docs.run({ filePath: `./${fullDirectory}`, key, version })).rejects.toStrictEqual( new APIError(formattedErrorObject) ); @@ -416,7 +422,7 @@ describe('rdme docs', () => { .basicAuth({ user: key }) .reply(200, { version }); - await expect(docs.run({ folder: `./__tests__/${fixturesBaseDir}/slug-docs`, key, version })).resolves.toBe( + await expect(docs.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs`, key, version })).resolves.toBe( `🌱 successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md` ); @@ -481,7 +487,7 @@ describe('rdme docs', () => { const fileName = 'docs-test-file'; prompts.inject([altVersion, true, 'docs-test-branch', fileName]); - await expect(docs.run({ folder: `./__tests__/${fixturesBaseDir}/new-docs`, key })).resolves.toMatchSnapshot(); + await expect(docs.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key })).resolves.toMatchSnapshot(); expect(yamlOutput).toMatchSnapshot(); expect(fs.writeFileSync).toHaveBeenCalledWith(`.github/workflows/${fileName}.yml`, expect.any(String)); @@ -526,7 +532,7 @@ describe('rdme docs', () => { prompts.inject([true, 'docs-test-branch', fileName]); await expect( - docs.run({ folder: `./__tests__/${fixturesBaseDir}/new-docs`, key, version }) + docs.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key, version }) ).resolves.toMatchSnapshot(); expect(yamlOutput).toMatchSnapshot(); @@ -568,7 +574,7 @@ describe('rdme docs', () => { prompts.inject(['docs-test-branch-github-flag', fileName]); await expect( - docs.run({ folder: `./__tests__/${fixturesBaseDir}/new-docs`, github: true, key, version }) + docs.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs`, github: true, key, version }) ).resolves.toMatchSnapshot(); expect(yamlOutput).toMatchSnapshot(); @@ -606,7 +612,9 @@ describe('rdme docs', () => { prompts.inject([false]); - await expect(docs.run({ folder: `./__tests__/${fixturesBaseDir}/new-docs`, key, version })).rejects.toStrictEqual( + await expect( + docs.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs`, key, version }) + ).rejects.toStrictEqual( new Error( 'GitHub Actions workflow creation cancelled. If you ever change your mind, you can run this command again with the `--github` flag.' ) diff --git a/__tests__/cmds/docs/single.test.ts b/__tests__/cmds/docs/single.test.ts index 4e6878662..8e37368db 100644 --- a/__tests__/cmds/docs/single.test.ts +++ b/__tests__/cmds/docs/single.test.ts @@ -6,12 +6,12 @@ import frontMatter from 'gray-matter'; import nock from 'nock'; import prompts from 'prompts'; -import DocsSingleCommand from '../../../src/cmds/docs/single'; +import DocsCommand from '../../../src/cmds/docs'; import APIError from '../../../src/lib/apiError'; import getAPIMock, { getAPIMockWithVersionHeader } from '../../helpers/get-api-mock'; import hashFileContents from '../../helpers/hash-file-contents'; -const docsSingle = new DocsSingleCommand(); +const docs = new DocsCommand(); const fixturesBaseDir = '__fixtures__/docs'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; @@ -20,7 +20,7 @@ const key = 'API_KEY'; const version = '1.0.0'; const category = 'CATEGORY_ID'; -describe('rdme docs:single', () => { +describe('rdme docs (single)', () => { beforeAll(() => nock.disableNetConnect()); afterAll(() => nock.cleanAll()); @@ -28,34 +28,40 @@ describe('rdme docs:single', () => { it('should prompt for login if no API key provided', async () => { const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(); prompts.inject(['this-is-not-an-email', 'password', 'subdomain']); - await expect(docsSingle.run({})).rejects.toStrictEqual(new Error('You must provide a valid email address.')); + await expect(docs.run({})).rejects.toStrictEqual(new Error('You must provide a valid email address.')); consoleInfoSpy.mockRestore(); }); it('should error in CI if no API key provided', async () => { process.env.TEST_CI = 'true'; - await expect(docsSingle.run({})).rejects.toStrictEqual( - new Error('No project API key provided. Please use `--key`.') - ); + await expect(docs.run({})).rejects.toStrictEqual(new Error('No project API key provided. Please use `--key`.')); delete process.env.TEST_CI; }); - it('should error if no file path provided', () => { - return expect(docsSingle.run({ key, version: '1.0.0' })).rejects.toThrow( - 'No file path provided. Usage `rdme docs:single [options]`.' + it('should error if no file path provided', async () => { + const versionMock = getAPIMock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); + + await expect(docs.run({ key, version })).rejects.toStrictEqual( + new Error('No path provided. Usage `rdme docs [options]`.') ); + + versionMock.done(); }); it('should error if the argument is not a Markdown file', async () => { - await expect(docsSingle.run({ key, version: '1.0.0', filePath: 'not-a-markdown-file' })).rejects.toThrow( - 'The file path specified is not a Markdown file.' + const versionMock = getAPIMock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); + + await expect(docs.run({ key, version, filePath: 'not-a-markdown-file' })).rejects.toStrictEqual( + new Error("Oops! We couldn't locate a file or directory at the path you provided.") ); + + versionMock.done(); }); it('should support .markdown files but error if file path cannot be found', async () => { const versionMock = getAPIMock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); - await expect(docsSingle.run({ key, version: '1.0.0', filePath: 'non-existent-file.markdown' })).rejects.toThrow( - 'ENOENT: no such file or directory' + await expect(docs.run({ key, version, filePath: 'non-existent-file.markdown' })).rejects.toStrictEqual( + new Error("Oops! We couldn't locate a file or directory at the path you provided.") ); versionMock.done(); }); @@ -88,7 +94,7 @@ describe('rdme docs:single', () => { .reply(200, { version }); await expect( - docsSingle.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key, version }) + docs.run({ filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key, version }) ).resolves.toBe( `🌱 successfully created 'new-doc' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md` ); @@ -118,7 +124,7 @@ describe('rdme docs:single', () => { .reply(200, { version }); await expect( - docsSingle.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key, version }) + docs.run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, key, version }) ).resolves.toBe( `🎭 dry run! This will create 'new-doc' with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md with the following metadata: ${JSON.stringify( doc.data @@ -169,9 +175,7 @@ describe('rdme docs:single', () => { message: `Error uploading ${chalk.underline(`${filePath}`)}:\n\n${errorObject.message}`, }; - await expect(docsSingle.run({ filePath, key, version })).rejects.toStrictEqual( - new APIError(formattedErrorObject) - ); + await expect(docs.run({ filePath, key, version })).rejects.toStrictEqual(new APIError(formattedErrorObject)); getMock.done(); postMock.done(); @@ -205,9 +209,7 @@ describe('rdme docs:single', () => { message: `Error uploading ${chalk.underline(`${filePath}`)}:\n\n${errorObject.message}`, }; - await expect(docsSingle.run({ filePath, key, version })).rejects.toStrictEqual( - new APIError(formattedErrorObject) - ); + await expect(docs.run({ filePath, key, version })).rejects.toStrictEqual(new APIError(formattedErrorObject)); getMock.done(); versionMock.done(); @@ -242,7 +244,7 @@ describe('rdme docs:single', () => { .reply(200, { version }); await expect( - docsSingle.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`, key, version }) + docs.run({ filePath: `./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`, key, version }) ).resolves.toBe( `🌱 successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md` ); @@ -291,7 +293,7 @@ describe('rdme docs:single', () => { .basicAuth({ user: key }) .reply(200, { version }); - return docsSingle + return docs .run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key, version }) .then(updatedDocs => { expect(updatedDocs).toBe( @@ -317,7 +319,7 @@ describe('rdme docs:single', () => { .basicAuth({ user: key }) .reply(200, { version }); - return docsSingle + return docs .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key, version }) .then(updatedDocs => { // All docs should have been updated because their hashes from the GET request were different from what they @@ -348,7 +350,7 @@ describe('rdme docs:single', () => { .basicAuth({ user: key }) .reply(200, { version }); - return docsSingle + return docs .run({ filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key, version }) .then(skippedDocs => { expect(skippedDocs).toBe('`simple-doc` was not updated because there were no changes.'); @@ -369,7 +371,7 @@ describe('rdme docs:single', () => { .basicAuth({ user: key }) .reply(200, { version }); - return docsSingle + return docs .run({ dryRun: true, filePath: `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, key, version }) .then(skippedDocs => { expect(skippedDocs).toBe('🎭 dry run! `simple-doc` will not be updated because there were no changes.'); diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index bce1f7482..353a36f8e 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -1,6 +1,6 @@ import prompts from 'prompts'; -import { version } from '../package.json'; +import { version as pkgVersion } from '../package.json'; import cli from '../src'; import conf from '../src/lib/configstore'; @@ -14,15 +14,15 @@ describe('cli', () => { describe('--version', () => { it('should return version from package.json', async () => { - await expect(cli(['--version'])).resolves.toBe(version); + await expect(cli(['--version'])).resolves.toBe(pkgVersion); }); it('should return version if the `-V` alias is supplied', async () => { - await expect(cli(['-V'])).resolves.toBe(version); + await expect(cli(['-V'])).resolves.toBe(pkgVersion); }); it('should return version from package.json for help command', async () => { - await expect(cli(['help', '--version'])).resolves.toBe(version); + await expect(cli(['help', '--version'])).resolves.toBe(pkgVersion); }); // This is necessary because we use --version for other commands like `docs` @@ -94,10 +94,18 @@ describe('cli', () => { it('should add stored apiKey to opts', async () => { expect.assertions(1); - conf.set('apiKey', '123456'); + const key = '123456'; + const version = '1.0.0'; + conf.set('apiKey', key); + + const versionMock = getAPIMock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); + + await expect(cli(['docs', `--version=${version}`])).rejects.toStrictEqual( + new Error('No path provided. Usage `rdme docs [options]`.') + ); - await expect(cli(['docs'])).rejects.toThrow('No folder provided. Usage `rdme docs [options]`.'); conf.clear(); + versionMock.done(); }); it('should error with `rdme oas` arguments passed in', async () => { @@ -125,9 +133,7 @@ describe('cli', () => { it.each([ ['changelogs', 'changelogs', ''], - ['changelogs:single', 'changelogs', `${slug}.md`], ['custompages', 'custompages', ''], - ['custompages:single', 'custompages', `${slug}.md`], ])('should run GHA workflow for the %s command', async (cmd, type, file) => { expect.assertions(3); prompts.inject([false]); diff --git a/__tests__/lib/__snapshots__/commands.test.ts.snap b/__tests__/lib/__snapshots__/commands.test.ts.snap index 37a04763d..c93ea51c1 100644 --- a/__tests__/lib/__snapshots__/commands.test.ts.snap +++ b/__tests__/lib/__snapshots__/commands.test.ts.snap @@ -80,41 +80,29 @@ exports[`utils #listByCategory should list commands by category 1`] = ` "changelogs": { "commands": [ { - "description": "Sync a folder of Markdown files to your ReadMe project as Changelog posts.", + "description": "Sync Markdown files to your ReadMe project as Changelog posts. Can either be a path to a directory or a single Markdown file.", "hidden": false, "name": "changelogs", "position": 1, }, - { - "description": "Sync a single Markdown file to your ReadMe project as a Changelog post.", - "hidden": false, - "name": "changelogs:single", - "position": 2, - }, ], "description": "Changelog", }, "custompages": { "commands": [ { - "description": "Sync a folder of Markdown files to your ReadMe project as Custom Pages.", + "description": "Sync Markdown/HTML files to your ReadMe project as Custom Pages. Can either be a path to a directory or a single Markdown/HTML file.", "hidden": false, "name": "custompages", "position": 1, }, - { - "description": "Sync a single Markdown file to your ReadMe project as a Custom Page.", - "hidden": false, - "name": "custompages:single", - "position": 2, - }, ], "description": "Custom Pages", }, "docs": { "commands": [ { - "description": "Sync a folder of Markdown files to your ReadMe project.", + "description": "Sync Markdown files to your ReadMe project as Guides. Can either be a path to a directory or a single Markdown file.", "hidden": false, "name": "docs", "position": 1, @@ -131,12 +119,6 @@ exports[`utils #listByCategory should list commands by category 1`] = ` "name": "docs:edit", "position": 3, }, - { - "description": "Sync a single Markdown file to your ReadMe project.", - "hidden": false, - "name": "docs:single", - "position": 3, - }, ], "description": "Documentation", }, diff --git a/__tests__/lib/__snapshots__/createGHA.test.ts.snap b/__tests__/lib/__snapshots__/createGHA.test.ts.snap index 67f6ae514..72e235c30 100644 --- a/__tests__/lib/__snapshots__/createGHA.test.ts.snap +++ b/__tests__/lib/__snapshots__/createGHA.test.ts.snap @@ -41,12 +41,12 @@ jobs: " `; -exports[`#createGHA command inputs changelogs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs changelogs should run GHA creation workflow and generate valid workflow file 3`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-changelogs-with-github-flag.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-changelogs.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -55,7 +55,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs changelogs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs changelogs should run GHA creation workflow and generate valid workflow file 4`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -63,10 +63,10 @@ name: ReadMe GitHub Action 🦉 on: push: branches: - # This workflow will run every time you push code to the following branch: \`another-branch\` + # This workflow will run every time you push code to the following branch: \`some-branch\` # Check out GitHub's docs for more info on configuring this: # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows - - another-branch + - some-branch jobs: rdme-changelogs: @@ -78,16 +78,16 @@ jobs: - name: Run \`changelogs\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: changelogs ./changelogs --key=\${{ secrets.README_API_KEY }} + rdme: changelogs ./changelogs/rdme.md --key=\${{ secrets.README_API_KEY }} " `; -exports[`#createGHA command inputs changelogs:single should run GHA creation workflow and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs changelogs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-changelogs-single.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-changelogs-with-github-flag.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -96,7 +96,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs changelogs:single should run GHA creation workflow and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs changelogs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -104,31 +104,31 @@ name: ReadMe GitHub Action 🦉 on: push: branches: - # This workflow will run every time you push code to the following branch: \`some-branch\` + # This workflow will run every time you push code to the following branch: \`another-branch\` # Check out GitHub's docs for more info on configuring this: # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows - - some-branch + - another-branch jobs: - rdme-changelogs-single: + rdme-changelogs: runs-on: ubuntu-latest steps: - name: Check out repo 📚 uses: actions/checkout@v3 - - name: Run \`changelogs:single\` command 🚀 + - name: Run \`changelogs\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: changelogs:single ./changelogs/rdme.md --key=\${{ secrets.README_API_KEY }} + rdme: changelogs ./changelogs --key=\${{ secrets.README_API_KEY }} " `; -exports[`#createGHA command inputs changelogs:single should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs changelogs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 3`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-changelogs-single-with-github-flag.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-changelogs-with-github-flag.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -137,7 +137,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs changelogs:single should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs changelogs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 4`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -151,16 +151,16 @@ on: - another-branch jobs: - rdme-changelogs-single: + rdme-changelogs: runs-on: ubuntu-latest steps: - name: Check out repo 📚 uses: actions/checkout@v3 - - name: Run \`changelogs:single\` command 🚀 + - name: Run \`changelogs\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: changelogs:single ./changelogs/rdme.md --key=\${{ secrets.README_API_KEY }} + rdme: changelogs ./changelogs/rdme.md --key=\${{ secrets.README_API_KEY }} " `; @@ -205,12 +205,12 @@ jobs: " `; -exports[`#createGHA command inputs custompages should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs custompages should run GHA creation workflow and generate valid workflow file 3`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-custompages-with-github-flag.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-custompages.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -219,7 +219,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs custompages should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs custompages should run GHA creation workflow and generate valid workflow file 4`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -227,10 +227,10 @@ name: ReadMe GitHub Action 🦉 on: push: branches: - # This workflow will run every time you push code to the following branch: \`another-branch\` + # This workflow will run every time you push code to the following branch: \`some-branch\` # Check out GitHub's docs for more info on configuring this: # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows - - another-branch + - some-branch jobs: rdme-custompages: @@ -242,16 +242,16 @@ jobs: - name: Run \`custompages\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: custompages ./custompages --key=\${{ secrets.README_API_KEY }} + rdme: custompages ./custompages/rdme.md --key=\${{ secrets.README_API_KEY }} " `; -exports[`#createGHA command inputs custompages:single should run GHA creation workflow and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs custompages should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-custompages-single.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-custompages-with-github-flag.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -260,7 +260,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs custompages:single should run GHA creation workflow and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs custompages should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -268,31 +268,31 @@ name: ReadMe GitHub Action 🦉 on: push: branches: - # This workflow will run every time you push code to the following branch: \`some-branch\` + # This workflow will run every time you push code to the following branch: \`another-branch\` # Check out GitHub's docs for more info on configuring this: # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows - - some-branch + - another-branch jobs: - rdme-custompages-single: + rdme-custompages: runs-on: ubuntu-latest steps: - name: Check out repo 📚 uses: actions/checkout@v3 - - name: Run \`custompages:single\` command 🚀 + - name: Run \`custompages\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: custompages:single ./custompages/rdme.md --key=\${{ secrets.README_API_KEY }} + rdme: custompages ./custompages --key=\${{ secrets.README_API_KEY }} " `; -exports[`#createGHA command inputs custompages:single should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs custompages should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 3`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-custompages-single-with-github-flag.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-custompages-with-github-flag.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -301,7 +301,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs custompages:single should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs custompages should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 4`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -315,16 +315,16 @@ on: - another-branch jobs: - rdme-custompages-single: + rdme-custompages: runs-on: ubuntu-latest steps: - name: Check out repo 📚 uses: actions/checkout@v3 - - name: Run \`custompages:single\` command 🚀 + - name: Run \`custompages\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: custompages:single ./custompages/rdme.md --key=\${{ secrets.README_API_KEY }} + rdme: custompages ./custompages/rdme.md --key=\${{ secrets.README_API_KEY }} " `; @@ -365,16 +365,16 @@ jobs: - name: Run \`docs\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: docs ./docs --key=\${{ secrets.README_API_KEY }} --version=1.0.0 + rdme: docs --key=\${{ secrets.README_API_KEY }} --version=1.0.0 " `; -exports[`#createGHA command inputs docs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs docs should run GHA creation workflow and generate valid workflow file 3`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-docs-with-github-flag.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-docs.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -383,7 +383,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs docs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs docs should run GHA creation workflow and generate valid workflow file 4`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -391,10 +391,10 @@ name: ReadMe GitHub Action 🦉 on: push: branches: - # This workflow will run every time you push code to the following branch: \`another-branch\` + # This workflow will run every time you push code to the following branch: \`some-branch\` # Check out GitHub's docs for more info on configuring this: # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows - - another-branch + - some-branch jobs: rdme-docs: @@ -406,16 +406,16 @@ jobs: - name: Run \`docs\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: docs ./docs --key=\${{ secrets.README_API_KEY }} --version=1.0.0 + rdme: docs ./docs/rdme.md --key=\${{ secrets.README_API_KEY }} --version=1.0.0 " `; -exports[`#createGHA command inputs docs:single should run GHA creation workflow and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs docs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-docs-single.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-docs-with-github-flag.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -424,7 +424,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs docs:single should run GHA creation workflow and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs docs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -432,31 +432,31 @@ name: ReadMe GitHub Action 🦉 on: push: branches: - # This workflow will run every time you push code to the following branch: \`some-branch\` + # This workflow will run every time you push code to the following branch: \`another-branch\` # Check out GitHub's docs for more info on configuring this: # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows - - some-branch + - another-branch jobs: - rdme-docs-single: + rdme-docs: runs-on: ubuntu-latest steps: - name: Check out repo 📚 uses: actions/checkout@v3 - - name: Run \`docs:single\` command 🚀 + - name: Run \`docs\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: docs:single ./docs/rdme.md --key=\${{ secrets.README_API_KEY }} --version=1.0.0 + rdme: docs --key=\${{ secrets.README_API_KEY }} --version=1.0.0 " `; -exports[`#createGHA command inputs docs:single should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 1`] = ` +exports[`#createGHA command inputs docs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 3`] = ` " Your GitHub Actions workflow file has been created! ✨ Almost done! Just a couple more steps: -1. Push your newly created file (.github/workflows/rdme-docs-single-with-github-flag.yml) to GitHub 🚀 +1. Push your newly created file (.github/workflows/rdme-docs-with-github-flag.yml) to GitHub 🚀 2. Create a GitHub secret called README_API_KEY and populate the value with your ReadMe API key (••••••••••••I_KEY) 🔑 🔐 Check out GitHub's docs for more info on creating encrypted secrets (https://docs.github.com/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) @@ -465,7 +465,7 @@ Almost done! Just a couple more steps: " `; -exports[`#createGHA command inputs docs:single should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 2`] = ` +exports[`#createGHA command inputs docs should run GHA creation workflow with \`--github\` flag and messy file name and generate valid workflow file 4`] = ` "# This GitHub Actions workflow was auto-generated by the \`rdme\` cli on 2022-01-01T00:00:00.000Z # You can view our full documentation here: https://docs.readme.com/docs/rdme name: ReadMe GitHub Action 🦉 @@ -479,16 +479,16 @@ on: - another-branch jobs: - rdme-docs-single: + rdme-docs: runs-on: ubuntu-latest steps: - name: Check out repo 📚 uses: actions/checkout@v3 - - name: Run \`docs:single\` command 🚀 + - name: Run \`docs\` command 🚀 uses: readmeio/rdme@7.8.9 with: - rdme: docs:single ./docs/rdme.md --key=\${{ secrets.README_API_KEY }} --version=1.0.0 + rdme: docs ./docs/rdme.md --key=\${{ secrets.README_API_KEY }} --version=1.0.0 " `; diff --git a/__tests__/lib/commands.test.ts b/__tests__/lib/commands.test.ts index de5fb3fd4..d43c6b2ca 100644 --- a/__tests__/lib/commands.test.ts +++ b/__tests__/lib/commands.test.ts @@ -2,7 +2,7 @@ /* eslint-disable jest/no-conditional-expect, jest/no-if */ import type Command from '../../src/lib/baseCommand'; -import SingleDocCommand from '../../src/cmds/docs/single'; +import DocsCommand from '../../src/cmds/docs'; import { CommandCategories } from '../../src/lib/baseCommand'; import * as commands from '../../src/lib/commands'; @@ -71,7 +71,7 @@ describe('utils', () => { describe('#load', () => { it('should load a valid command', () => { - expect(commands.load('docs:single')).toBeInstanceOf(SingleDocCommand); + expect(commands.load('docs')).toBeInstanceOf(DocsCommand); }); it('should throw an error on an invalid command', () => { diff --git a/__tests__/lib/createGHA.test.ts b/__tests__/lib/createGHA.test.ts index 45a15de1c..9dfedf574 100644 --- a/__tests__/lib/createGHA.test.ts +++ b/__tests__/lib/createGHA.test.ts @@ -9,11 +9,8 @@ import fs from 'fs'; import prompts from 'prompts'; import ChangelogsCommand from '../../src/cmds/changelogs'; -import SingleChangelogCommand from '../../src/cmds/changelogs/single'; import CustomPagesCommand from '../../src/cmds/custompages'; -import SingleCustomPageCommand from '../../src/cmds/custompages/single'; import DocsCommand from '../../src/cmds/docs'; -import SingleDocCommand from '../../src/cmds/docs/single'; import OpenAPICommand from '../../src/cmds/openapi'; import OpenAPIValidateCommand from '../../src/cmds/openapi/validate'; import configstore from '../../src/lib/configstore'; @@ -63,13 +60,13 @@ describe('#createGHA', () => { { cmd: 'openapi:validate', CmdClass: OpenAPIValidateCommand, opts: { spec: 'petstore.json' } }, { cmd: 'openapi', CmdClass: OpenAPICommand, opts: { key, spec: 'petstore.json', id: 'spec_id' } }, { cmd: 'docs', CmdClass: DocsCommand, opts: { key, folder: './docs', version: '1.0.0' } }, - { cmd: 'docs:single', CmdClass: SingleDocCommand, opts: { key, filePath: './docs/rdme.md', version: '1.0.0' } }, - { cmd: 'changelogs', CmdClass: ChangelogsCommand, opts: { key, folder: './changelogs' } }, - { cmd: 'changelogs:single', CmdClass: SingleChangelogCommand, opts: { key, filePath: './changelogs/rdme.md' } }, - { cmd: 'custompages', CmdClass: CustomPagesCommand, opts: { key, folder: './custompages' } }, + { cmd: 'docs', CmdClass: DocsCommand, opts: { key, filePath: './docs/rdme.md', version: '1.0.0' } }, + { cmd: 'changelogs', CmdClass: ChangelogsCommand, opts: { key, filePath: './changelogs' } }, + { cmd: 'changelogs', CmdClass: ChangelogsCommand, opts: { key, filePath: './changelogs/rdme.md' } }, + { cmd: 'custompages', CmdClass: CustomPagesCommand, opts: { key, filePath: './custompages' } }, { - cmd: 'custompages:single', - CmdClass: SingleCustomPageCommand, + cmd: 'custompages', + CmdClass: CustomPagesCommand, opts: { key, filePath: './custompages/rdme.md' }, }, ])('$cmd', ({ cmd, CmdClass, opts }) => { diff --git a/src/cmds/changelogs.ts b/src/cmds/changelogs.ts new file mode 100644 index 000000000..0da1a6958 --- /dev/null +++ b/src/cmds/changelogs.ts @@ -0,0 +1,48 @@ +import type { CommandOptions } from '../lib/baseCommand'; + +import Command, { CommandCategories } from '../lib/baseCommand'; +import supportsGHA from '../lib/decorators/supportsGHA'; +import syncDocsPath from '../lib/syncDocsPath'; + +export type Options = { + dryRun?: boolean; + filePath?: string; +}; + +@supportsGHA +export default class ChangelogsCommand extends Command { + constructor() { + super(); + + this.command = 'changelogs'; + this.usage = 'changelogs [options]'; + this.description = + 'Sync Markdown files to your ReadMe project as Changelog posts. Can either be a path to a directory or a single Markdown file.'; + this.cmdCategory = CommandCategories.CHANGELOGS; + this.position = 1; + + this.hiddenArgs = ['filePath']; + this.args = [ + this.getKeyArg(), + { + name: 'filePath', + type: String, + defaultOption: true, + }, + this.getGitHubArg(), + { + name: 'dryRun', + type: Boolean, + description: 'Runs the command without creating/updating any changelogs in ReadMe. Useful for debugging.', + }, + ]; + } + + async run(opts: CommandOptions) { + await super.run(opts); + + const { dryRun, filePath, key } = opts; + + return syncDocsPath(key, undefined, this.cmdCategory, this.usage, filePath, dryRun); + } +} diff --git a/src/cmds/changelogs/index.ts b/src/cmds/changelogs/index.ts deleted file mode 100644 index f63a3e377..000000000 --- a/src/cmds/changelogs/index.ts +++ /dev/null @@ -1,72 +0,0 @@ -import type { CommandOptions } from '../../lib/baseCommand'; - -import chalk from 'chalk'; -import config from 'config'; - -import Command, { CommandCategories } from '../../lib/baseCommand'; -import supportsGHA from '../../lib/decorators/supportsGHA'; -import pushDoc from '../../lib/pushDoc'; -import readdirRecursive from '../../lib/readdirRecursive'; - -export type Options = { - dryRun?: boolean; - folder?: string; -}; - -@supportsGHA -export default class ChangelogsCommand extends Command { - constructor() { - super(); - - this.command = 'changelogs'; - this.usage = 'changelogs [options]'; - this.description = 'Sync a folder of Markdown files to your ReadMe project as Changelog posts.'; - this.cmdCategory = CommandCategories.CHANGELOGS; - this.position = 1; - - this.hiddenArgs = ['folder']; - this.args = [ - this.getKeyArg(), - { - name: 'folder', - type: String, - defaultOption: true, - }, - this.getGitHubArg(), - { - name: 'dryRun', - type: Boolean, - description: 'Runs the command without creating/updating any changelogs in ReadMe. Useful for debugging.', - }, - ]; - } - - async run(opts: CommandOptions) { - await super.run(opts); - - const { dryRun, folder, key } = opts; - - if (!folder) { - return Promise.reject(new Error(`No folder provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); - } - - // Strip out non-markdown files - const files = readdirRecursive(folder).filter( - file => file.toLowerCase().endsWith('.md') || file.toLowerCase().endsWith('.markdown') - ); - - Command.debug(`number of files: ${files.length}`); - - if (!files.length) { - return Promise.reject(new Error(`We were unable to locate Markdown files in ${folder}.`)); - } - - const updatedDocs = await Promise.all( - files.map(async filename => { - return pushDoc(key, undefined, dryRun, filename, this.cmdCategory); - }) - ); - - return Promise.resolve(chalk.green(updatedDocs.join('\n'))); - } -} diff --git a/src/cmds/changelogs/single.ts b/src/cmds/changelogs/single.ts deleted file mode 100644 index ebccc971c..000000000 --- a/src/cmds/changelogs/single.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { CommandOptions } from '../../lib/baseCommand'; - -import chalk from 'chalk'; -import config from 'config'; - -import Command, { CommandCategories } from '../../lib/baseCommand'; -import supportsGHA from '../../lib/decorators/supportsGHA'; -import pushDoc from '../../lib/pushDoc'; - -export type Options = { - dryRun?: boolean; - filePath?: string; -}; - -@supportsGHA -export default class SingleChangelogCommand extends Command { - constructor() { - super(); - - this.command = 'changelogs:single'; - this.usage = 'changelogs:single [options]'; - this.description = 'Sync a single Markdown file to your ReadMe project as a Changelog post.'; - this.cmdCategory = CommandCategories.CHANGELOGS; - this.position = 2; - - this.hiddenArgs = ['filePath']; - this.args = [ - this.getKeyArg(), - { - name: 'filePath', - type: String, - defaultOption: true, - }, - this.getGitHubArg(), - { - name: 'dryRun', - type: Boolean, - description: 'Runs the command without creating/updating any changelogs in ReadMe. Useful for debugging.', - }, - ]; - } - - async run(opts: CommandOptions) { - await super.run(opts); - - const { dryRun, filePath, key } = opts; - - if (!filePath) { - return Promise.reject(new Error(`No file path provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); - } - - if (!(filePath.toLowerCase().endsWith('.md') || filePath.toLowerCase().endsWith('.markdown'))) { - return Promise.reject(new Error('The file path specified is not a Markdown file.')); - } - - const createdDoc = await pushDoc(key, undefined, dryRun, filePath, this.cmdCategory); - - return Promise.resolve(chalk.green(createdDoc)); - } -} diff --git a/src/cmds/custompages.ts b/src/cmds/custompages.ts new file mode 100644 index 000000000..5986c423a --- /dev/null +++ b/src/cmds/custompages.ts @@ -0,0 +1,48 @@ +import type { CommandOptions } from '../lib/baseCommand'; + +import Command, { CommandCategories } from '../lib/baseCommand'; +import supportsGHA from '../lib/decorators/supportsGHA'; +import syncDocsPath from '../lib/syncDocsPath'; + +export type Options = { + dryRun?: boolean; + filePath?: string; +}; + +@supportsGHA +export default class CustomPagesCommand extends Command { + constructor() { + super(); + + this.command = 'custompages'; + this.usage = 'custompages [options]'; + this.description = + 'Sync Markdown/HTML files to your ReadMe project as Custom Pages. Can either be a path to a directory or a single Markdown/HTML file.'; + this.cmdCategory = CommandCategories.CUSTOM_PAGES; + this.position = 1; + + this.hiddenArgs = ['filePath']; + this.args = [ + this.getKeyArg(), + { + name: 'filePath', + type: String, + defaultOption: true, + }, + this.getGitHubArg(), + { + name: 'dryRun', + type: Boolean, + description: 'Runs the command without creating/updating any custom pages in ReadMe. Useful for debugging.', + }, + ]; + } + + async run(opts: CommandOptions) { + await super.run(opts); + + const { dryRun, filePath, key } = opts; + + return syncDocsPath(key, undefined, this.cmdCategory, this.usage, filePath, dryRun, ['.html', '.markdown', '.md']); + } +} diff --git a/src/cmds/custompages/index.ts b/src/cmds/custompages/index.ts deleted file mode 100644 index 1ebebe172..000000000 --- a/src/cmds/custompages/index.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { CommandOptions } from '../../lib/baseCommand'; - -import chalk from 'chalk'; -import config from 'config'; - -import Command, { CommandCategories } from '../../lib/baseCommand'; -import supportsGHA from '../../lib/decorators/supportsGHA'; -import pushDoc from '../../lib/pushDoc'; -import readdirRecursive from '../../lib/readdirRecursive'; - -export type Options = { - dryRun?: boolean; - folder?: string; -}; - -@supportsGHA -export default class CustomPagesCommand extends Command { - constructor() { - super(); - - this.command = 'custompages'; - this.usage = 'custompages [options]'; - this.description = 'Sync a folder of Markdown files to your ReadMe project as Custom Pages.'; - this.cmdCategory = CommandCategories.CUSTOM_PAGES; - this.position = 1; - - this.hiddenArgs = ['folder']; - this.args = [ - this.getKeyArg(), - { - name: 'folder', - type: String, - defaultOption: true, - }, - this.getGitHubArg(), - { - name: 'dryRun', - type: Boolean, - description: 'Runs the command without creating/updating any custom pages in ReadMe. Useful for debugging.', - }, - ]; - } - - async run(opts: CommandOptions) { - await super.run(opts); - - const { dryRun, folder, key } = opts; - - if (!folder) { - return Promise.reject(new Error(`No folder provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); - } - - // Strip out non-markdown files - const files = readdirRecursive(folder).filter( - file => - file.toLowerCase().endsWith('.html') || - file.toLowerCase().endsWith('.md') || - file.toLowerCase().endsWith('.markdown') - ); - - Command.debug(`number of files: ${files.length}`); - - if (!files.length) { - return Promise.reject(new Error(`We were unable to locate Markdown or HTML files in ${folder}.`)); - } - - const updatedDocs = await Promise.all( - files.map(async filename => { - return pushDoc(key, undefined, dryRun, filename, this.cmdCategory); - }) - ); - - return Promise.resolve(chalk.green(updatedDocs.join('\n'))); - } -} diff --git a/src/cmds/custompages/single.ts b/src/cmds/custompages/single.ts deleted file mode 100644 index 0922baabb..000000000 --- a/src/cmds/custompages/single.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { CommandOptions } from '../../lib/baseCommand'; - -import chalk from 'chalk'; -import config from 'config'; - -import Command, { CommandCategories } from '../../lib/baseCommand'; -import supportsGHA from '../../lib/decorators/supportsGHA'; -import pushDoc from '../../lib/pushDoc'; - -export type Options = { - dryRun?: boolean; - filePath?: string; -}; - -@supportsGHA -export default class SingleCustomPageCommand extends Command { - constructor() { - super(); - this.command = 'custompages:single'; - this.usage = 'custompages:single [options]'; - this.description = 'Sync a single Markdown file to your ReadMe project as a Custom Page.'; - this.cmdCategory = CommandCategories.CUSTOM_PAGES; - this.position = 2; - - this.hiddenArgs = ['filePath']; - this.args = [ - this.getKeyArg(), - { - name: 'filePath', - type: String, - defaultOption: true, - }, - this.getGitHubArg(), - { - name: 'dryRun', - type: Boolean, - description: 'Runs the command without creating/updating any custom pages in ReadMe. Useful for debugging.', - }, - ]; - } - - async run(opts: CommandOptions) { - await super.run(opts); - - const { dryRun, filePath, key } = opts; - - if (!filePath) { - return Promise.reject(new Error(`No file path provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); - } - - if ( - !( - filePath.toLowerCase().endsWith('.html') || - filePath.toLowerCase().endsWith('.md') || - filePath.toLowerCase().endsWith('.markdown') - ) - ) { - return Promise.reject(new Error('The file path specified is not a Markdown or HTML file.')); - } - - const createdDoc = await pushDoc(key, undefined, dryRun, filePath, this.cmdCategory); - - return Promise.resolve(chalk.green(createdDoc)); - } -} diff --git a/src/cmds/docs/index.ts b/src/cmds/docs/index.ts index 7f2061c28..c6acafec8 100644 --- a/src/cmds/docs/index.ts +++ b/src/cmds/docs/index.ts @@ -1,17 +1,13 @@ import type { CommandOptions } from '../../lib/baseCommand'; -import chalk from 'chalk'; -import config from 'config'; - import Command, { CommandCategories } from '../../lib/baseCommand'; import createGHA from '../../lib/createGHA'; -import pushDoc from '../../lib/pushDoc'; -import readdirRecursive from '../../lib/readdirRecursive'; +import syncDocsPath from '../../lib/syncDocsPath'; import { getProjectVersion } from '../../lib/versionSelect'; export type Options = { dryRun?: boolean; - folder?: string; + filePath?: string; }; export default class DocsCommand extends Command { @@ -19,17 +15,18 @@ export default class DocsCommand extends Command { super(); this.command = 'docs'; - this.usage = 'docs [options]'; - this.description = 'Sync a folder of Markdown files to your ReadMe project.'; + this.usage = 'docs [options]'; + this.description = + 'Sync Markdown files to your ReadMe project as Guides. Can either be a path to a directory or a single Markdown file.'; this.cmdCategory = CommandCategories.DOCS; this.position = 1; - this.hiddenArgs = ['folder']; + this.hiddenArgs = ['filePath']; this.args = [ this.getKeyArg(), this.getVersionArg(), { - name: 'folder', + name: 'filePath', type: String, defaultOption: true, }, @@ -45,37 +42,14 @@ export default class DocsCommand extends Command { async run(opts: CommandOptions) { await super.run(opts); - const { dryRun, folder, key, version } = opts; - - if (!folder) { - return Promise.reject(new Error(`No folder provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); - } + const { dryRun, filePath, key, version } = opts; // TODO: should we allow version selection at all here? // Let's revisit this once we re-evaluate our category logic in the API. // Ideally we should ignore this parameter entirely if the category is included. const selectedVersion = await getProjectVersion(version, key); - Command.debug(`selectedVersion: ${selectedVersion}`); - - // Strip out non-markdown files - const files = readdirRecursive(folder).filter( - file => file.toLowerCase().endsWith('.md') || file.toLowerCase().endsWith('.markdown') - ); - - Command.debug(`number of files: ${files.length}`); - - if (!files.length) { - return Promise.reject(new Error(`We were unable to locate Markdown files in ${folder}.`)); - } - - const updatedDocs = await Promise.all( - files.map(async filename => { - return pushDoc(key, selectedVersion, dryRun, filename, this.cmdCategory); - }) - ); - - return Promise.resolve(chalk.green(updatedDocs.join('\n'))).then(msg => + return syncDocsPath(key, selectedVersion, this.cmdCategory, this.usage, filePath, dryRun).then(msg => createGHA(msg, this.command, this.args, { ...opts, version: selectedVersion }) ); } diff --git a/src/cmds/docs/single.ts b/src/cmds/docs/single.ts deleted file mode 100644 index b4c00442c..000000000 --- a/src/cmds/docs/single.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { CommandOptions } from '../../lib/baseCommand'; - -import chalk from 'chalk'; -import config from 'config'; - -import Command, { CommandCategories } from '../../lib/baseCommand'; -import createGHA from '../../lib/createGHA'; -import pushDoc from '../../lib/pushDoc'; -import { getProjectVersion } from '../../lib/versionSelect'; - -export type Options = { - dryRun?: boolean; - filePath?: string; -}; - -export default class SingleDocCommand extends Command { - constructor() { - super(); - - this.command = 'docs:single'; - this.usage = 'docs:single [options]'; - this.description = 'Sync a single Markdown file to your ReadMe project.'; - this.cmdCategory = CommandCategories.DOCS; - this.position = 3; - - this.hiddenArgs = ['filePath']; - this.args = [ - this.getKeyArg(), - this.getVersionArg(), - { - name: 'filePath', - type: String, - defaultOption: true, - }, - this.getGitHubArg(), - { - name: 'dryRun', - type: Boolean, - description: 'Runs the command without creating/updating any docs in ReadMe. Useful for debugging.', - }, - ]; - } - - async run(opts: CommandOptions) { - await super.run(opts); - - const { dryRun, filePath, key, version } = opts; - - if (!filePath) { - return Promise.reject(new Error(`No file path provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); - } - - if (!(filePath.toLowerCase().endsWith('.md') || filePath.toLowerCase().endsWith('.markdown'))) { - return Promise.reject(new Error('The file path specified is not a Markdown file.')); - } - - // TODO: should we allow version selection at all here? - // Let's revisit this once we re-evaluate our category logic in the API. - // Ideally we should ignore this parameter entirely if the category is included. - const selectedVersion = await getProjectVersion(version, key); - - Command.debug(`selectedVersion: ${selectedVersion}`); - - const createdDoc = await pushDoc(key, selectedVersion, dryRun, filePath, this.cmdCategory); - - return Promise.resolve(chalk.green(createdDoc)).then(msg => - createGHA(msg, this.command, this.args, { ...opts, version: selectedVersion }) - ); - } -} diff --git a/src/cmds/index.ts b/src/cmds/index.ts index 898057ddd..2a892cd38 100644 --- a/src/cmds/index.ts +++ b/src/cmds/index.ts @@ -1,13 +1,10 @@ import CategoriesCommand from './categories'; import CategoriesCreateCommand from './categories/create'; import ChangelogsCommand from './changelogs'; -import SingleChangelogCommand from './changelogs/single'; import CustomPagesCommand from './custompages'; -import SingleCustomPageCommand from './custompages/single'; import DocsCommand from './docs'; import DocsEditCommand from './docs/edit'; import DocsPruneCommand from './docs/prune'; -import SingleDocCommand from './docs/single'; import LoginCommand from './login'; import LogoutCommand from './logout'; import OASCommand from './oas'; @@ -28,15 +25,11 @@ const commands = { 'categories:create': CategoriesCreateCommand, changelogs: ChangelogsCommand, - 'changelogs:single': SingleChangelogCommand, - custompages: CustomPagesCommand, - 'custompages:single': SingleCustomPageCommand, docs: DocsCommand, 'docs:prune': DocsPruneCommand, 'docs:edit': DocsEditCommand, - 'docs:single': SingleDocCommand, versions: VersionsCommand, 'versions:create': CreateVersionCommand, diff --git a/src/lib/pushDoc.ts b/src/lib/syncDocsPath.ts similarity index 56% rename from src/lib/pushDoc.ts rename to src/lib/syncDocsPath.ts index e3cb45e7e..fdf4c213a 100644 --- a/src/lib/pushDoc.ts +++ b/src/lib/syncDocsPath.ts @@ -1,26 +1,29 @@ +import fs from 'fs/promises'; +import path from 'path'; + import chalk from 'chalk'; import config from 'config'; import { Headers } from 'node-fetch'; import APIError from './apiError'; -import { CommandCategories } from './baseCommand'; +import Command, { CommandCategories } from './baseCommand'; import fetch, { cleanHeaders, handleRes } from './fetch'; import { debug } from './logger'; +import readdirRecursive from './readdirRecursive'; import readDoc from './readDoc'; /** * Reads the contents of the specified Markdown or HTML file * and creates/updates the corresponding doc in ReadMe * - * @param {String} key the project API key - * @param {String} selectedVersion the project version - * @param {Boolean} dryRun boolean indicating dry run mode - * @param {String} filepath path to the HTML/Markdown file - * (file extension must end in `.html`, `.md`., or `.markdown`) - * @param {String} type module within ReadMe to update (e.g. docs, changelogs, etc.) - * @returns {Promise} a string containing the result + * @param key the project API key + * @param selectedVersion the project version + * @param dryRun boolean indicating dry run mode + * @param filepath path to file + * @param type module within ReadMe to update (e.g. docs, changelogs, etc.) + * @returns A promise-wrapped string with the result */ -export default async function pushDoc( +async function pushDoc( key: string, selectedVersion: string, dryRun: boolean, @@ -131,3 +134,76 @@ export default async function pushDoc( throw err; }); } + +/** + * Takes a path (either to a directory of files or to a single file) + * and syncs those (either via POST or PUT) to ReadMe. + * @returns A promise-wrapped string with the results + */ +export default async function syncDocsPath( + /** Project API key */ + key: string, + /** ReadMe project version */ + selectedVersion: string, + /** module within ReadMe to update (e.g. docs, changelogs, etc.) */ + cmdType: CommandCategories, + /** Example command usage, used in error message */ + usage: string, + /** Path input, can either be a directory or a single file */ + pathInput: string, + /** boolean indicating dry run mode */ + dryRun: boolean, + /** array of allowed file extensions */ + allowedFileExtensions = ['.markdown', '.md'] +) { + if (!pathInput) { + return Promise.reject(new Error(`No path provided. Usage \`${config.get('cli')} ${usage}\`.`)); + } + + const stat = await fs.stat(pathInput).catch(err => { + if (err.code === 'ENOENT') { + throw new Error("Oops! We couldn't locate a file or directory at the path you provided."); + } + throw err; + }); + + let output: string; + + if (stat.isDirectory()) { + // Filter out any files that don't match allowedFileExtensions + const files = readdirRecursive(pathInput).filter(file => + allowedFileExtensions.includes(path.extname(file).toLowerCase()) + ); + + Command.debug(`number of files: ${files.length}`); + + if (!files.length) { + return Promise.reject( + new Error( + `The directory you provided (${pathInput}) doesn't contain any of the following required files: ${allowedFileExtensions.join( + ', ' + )}.` + ) + ); + } + + output = ( + await Promise.all( + files.map(async filename => { + return pushDoc(key, selectedVersion, dryRun, filename, cmdType); + }) + ) + ).join('\n'); + } else { + const fileExtension = path.extname(pathInput).toLowerCase(); + if (!allowedFileExtensions.includes(fileExtension)) { + return Promise.reject( + new Error( + `Invalid file extension (${fileExtension}). Must be one of the following: ${allowedFileExtensions.join(', ')}` + ) + ); + } + output = await pushDoc(key, selectedVersion, dryRun, pathInput, cmdType); + } + return Promise.resolve(chalk.green(output)); +}