From a58bd4a9131807548ebc5a6fc02f1796723d81ed Mon Sep 17 00:00:00 2001
From: Kanad Gupta
Date: Mon, 9 Dec 2024 11:16:23 -0600
Subject: [PATCH 1/9] docs: v10 readme updates (#1108)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## π§° Changes
cleans up a few v9-specific callouts in our main README and main docs
page.
---
README.md | 5 +----
documentation/rdme.md | 4 ----
2 files changed, 1 insertion(+), 8 deletions(-)
diff --git a/README.md b/README.md
index a3ed86942..8b5d0d8f5 100644
--- a/README.md
+++ b/README.md
@@ -15,13 +15,10 @@
-With `rdme`, you can manage your API definition (we support [OpenAPI](https://spec.openapis.org/oas/v3.1.0.html), [Swagger](https://swagger.io/specification/v2/), and [Postman](https://schema.postman.com/)) and sync it to your API reference docs on ReadMe. You can also access other parts of [ReadMe's RESTful API](https://docs.readme.com/reference), including syncing Markdown documentation with your ReadMe project and managing project versions.
+With `rdme`, you can manage your API definition (we support [OpenAPI](https://spec.openapis.org/oas/v3.1.0.html), [Swagger](https://swagger.io/specification/v2/), and [Postman](https://schema.postman.com/)) and sync it to your API reference docs on ReadMe.
Not using ReadMe for your docs? No worries. `rdme` has a variety of tools to help you identify issues with your API definition β no ReadMe account required.
-> [!WARNING]
-> Heads up: our [new ReadMe Refactored experience](https://docs.readme.com/main/docs/welcome-to-readme-refactored) doesnβt yet support `rdme`. If your project is using the new ReadMe Refactored experience, we recommend [enabling bi-directional syncing via Git](https://docs.readme.com/main/docs/bi-directional-sync) for an even better editing experience for the technical and non-technical users on your team!
-
# Table of Contents
+
+> [!IMPORTANT]
+> You'll notice that several previous `rdme` commands are no longer present. That's because this version is for projects that use [ReadMe Refactored](https://docs.readme.com/main/docs/welcome-to-readme-refactored) and [bi-directional syncing](https://docs.readme.com/main/docs/bi-directional-sync) is the recommended approach for most workflows previously managed via `rdme`. See more in [our migration guide](./documentation/migration-guide.md).
diff --git a/__tests__/commands/categories/create.test.ts b/__tests__/commands/categories/create.test.ts
deleted file mode 100644
index 8b16d38a7..000000000
--- a/__tests__/commands/categories/create.test.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-import nock from 'nock';
-import { describe, beforeAll, afterEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/categories/create.js';
-import { getAPIv1Mock, getAPIv1MockWithVersionHeader } from '../../helpers/get-api-mock.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const key = 'API_KEY';
-const version = '1.0.0';
-
-describe('rdme categories create', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterEach(() => nock.cleanAll());
-
- it('should error if no title provided', () => {
- return expect(run(['--key', key])).rejects.toThrow('Missing 1 required arg:\ntitle');
- });
-
- it('should error if categoryType is blank', () => {
- return expect(run(['--key', key, 'Test Title'])).rejects.toThrow('Missing required flag categoryType');
- });
-
- it('should error if categoryType is not `guide` or `reference`', () => {
- return expect(run(['--key', key, 'Test Title', '--categoryType', 'test'])).rejects.toThrow(
- 'Expected --categoryType=test to be one of: guide, reference',
- );
- });
-
- it('should create a new category if the title and type do not match and preventDuplicates=true', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .persist()
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ title: 'Existing Category', slug: 'existing-category', type: 'guide' }], {
- 'x-total-count': '1',
- });
-
- const postMock = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/categories')
- .basicAuth({ user: key })
- .reply(201, { title: 'New Category', slug: 'new-category', type: 'guide', id: '123' });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run(['New Category', '--categoryType', 'guide', '--key', key, '--version', '1.0.0', '--preventDuplicates']),
- ).resolves.toBe("π± successfully created 'New Category' with a type of 'guide' and an id of '123'");
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
-
- it('should create a new category if the title matches but the type does not match and preventDuplicates=true', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .persist()
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ title: 'Category', slug: 'category', type: 'guide' }], {
- 'x-total-count': '1',
- });
-
- const postMock = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/categories')
- .basicAuth({ user: key })
- .reply(201, { title: 'Category', slug: 'category', type: 'reference', id: '123' });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run(['--categoryType', 'reference', '--key', key, '--version', '1.0.0', '--preventDuplicates', 'Category']),
- ).resolves.toBe("π± successfully created 'Category' with a type of 'reference' and an id of '123'");
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
-
- it('should create a new category if the title and type match and preventDuplicates=false', async () => {
- const postMock = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/categories')
- .basicAuth({ user: key })
- .reply(201, { title: 'Category', slug: 'category', type: 'reference', id: '123' });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['Category', '--categoryType', 'guide', '--key', key, '--version', '1.0.0'])).resolves.toBe(
- "π± successfully created 'Category' with a type of 'reference' and an id of '123'",
- );
-
- postMock.done();
- versionMock.done();
- });
-
- it('should not create a new category if the title and type match and preventDuplicates=true', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .persist()
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ title: 'Category', slug: 'category', type: 'guide', id: '123' }], {
- 'x-total-count': '1',
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run(['Category', '--categoryType', 'guide', '--key', key, '--version', '1.0.0', '--preventDuplicates']),
- ).rejects.toStrictEqual(
- new Error(
- "The 'Category' category with a type of 'guide' already exists with an id of '123'. A new category was not created.",
- ),
- );
-
- getMock.done();
- versionMock.done();
- });
-
- it('should not create a new category if the non case sensitive title and type match and preventDuplicates=true', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .persist()
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ title: 'Category', slug: 'category', type: 'guide', id: '123' }], {
- 'x-total-count': '1',
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run(['Category', '--categoryType', 'guide', '--key', key, '--version', '1.0.0', '--preventDuplicates']),
- ).rejects.toStrictEqual(
- new Error(
- "The 'Category' category with a type of 'guide' already exists with an id of '123'. A new category was not created.",
- ),
- );
-
- getMock.done();
- versionMock.done();
- });
-});
diff --git a/__tests__/commands/categories/index.test.ts b/__tests__/commands/categories/index.test.ts
deleted file mode 100644
index f3ebb3b54..000000000
--- a/__tests__/commands/categories/index.test.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import nock from 'nock';
-import { describe, beforeAll, afterEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/categories/index.js';
-import { getAPIv1Mock, getAPIv1MockWithVersionHeader } from '../../helpers/get-api-mock.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const key = 'API_KEY';
-const version = '1.0.0';
-
-describe('rdme categories', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterEach(() => nock.cleanAll());
-
- it('should return all categories for a single page', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .persist()
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ title: 'One Category', slug: 'one-category', type: 'guide' }], {
- 'x-total-count': '1',
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['--key', key, '--version', '1.0.0'])).resolves.toBe(
- JSON.stringify([{ title: 'One Category', slug: 'one-category', type: 'guide' }], null, 2),
- );
-
- getMock.done();
- versionMock.done();
- });
-
- it('should return all categories for multiple pages', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .persist()
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ title: 'One Category', slug: 'one-category', type: 'guide' }], {
- 'x-total-count': '21',
- })
- .get('/api/v1/categories?perPage=20&page=2')
- .basicAuth({ user: key })
- .reply(200, [{ title: 'Another Category', slug: 'another-category', type: 'guide' }], {
- 'x-total-count': '21',
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['--key', key, '--version', '1.0.0'])).resolves.toBe(
- JSON.stringify(
- [
- { title: 'One Category', slug: 'one-category', type: 'guide' },
- { title: 'Another Category', slug: 'another-category', type: 'guide' },
- ],
- null,
- 2,
- ),
- );
-
- getMock.done();
- versionMock.done();
- });
-});
diff --git a/__tests__/commands/custompages/index.test.ts b/__tests__/commands/custompages/index.test.ts
deleted file mode 100644
index a0b5061d2..000000000
--- a/__tests__/commands/custompages/index.test.ts
+++ /dev/null
@@ -1,350 +0,0 @@
-import fs from 'node:fs';
-import path from 'node:path';
-
-import chalk from 'chalk';
-import frontMatter from 'gray-matter';
-import nock from 'nock';
-import { describe, beforeAll, afterAll, beforeEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/custompages.js';
-import { APIv1Error } from '../../../src/lib/apiError.js';
-import { getAPIv1Mock } from '../../helpers/get-api-mock.js';
-import hashFileContents from '../../helpers/hash-file-contents.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const fixturesBaseDir = '__fixtures__/custompages';
-const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`;
-const key = 'API_KEY';
-
-describe('rdme custompages', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterAll(() => nock.cleanAll());
-
- it('should error if no path provided', () => {
- return expect(run(['--key', key])).rejects.toThrow('Missing 1 required arg:\npath');
- });
-
- it('should error if the argument is not a folder', () => {
- return expect(run(['--key', key, '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(run(['--key', key, '.github/workflows'])).rejects.toStrictEqual(
- new Error(
- "The directory you provided (.github/workflows) doesn't contain any of the following required files: .html, .markdown, .md.",
- ),
- );
- });
-
- describe('existing custompages', () => {
- let simpleDoc;
- let anotherDoc;
-
- beforeEach(() => {
- let fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/simple-doc.md'));
- simpleDoc = {
- slug: 'simple-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
-
- fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/subdir/another-doc.md'));
- anotherDoc = {
- slug: 'another-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
- });
-
- it('should fetch custom page and merge with what is returned', () => {
- expect.assertions(1);
-
- const getMocks = getAPIv1Mock()
- .get('/api/v1/custompages/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: simpleDoc.slug, htmlmode: false, lastUpdatedHash: 'anOldHash' })
- .get('/api/v1/custompages/another-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: anotherDoc.slug, htmlmode: false, lastUpdatedHash: 'anOldHash' });
-
- const updateMocks = getAPIv1Mock()
- .put('/api/v1/custompages/simple-doc', {
- body: simpleDoc.doc.content,
- htmlmode: false,
- lastUpdatedHash: simpleDoc.hash,
- ...simpleDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, {
- slug: simpleDoc.slug,
- htmlmode: false,
- body: simpleDoc.doc.content,
- })
- .put('/api/v1/custompages/another-doc', {
- body: anotherDoc.doc.content,
- htmlmode: false,
- lastUpdatedHash: anotherDoc.hash,
- ...anotherDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, { slug: anotherDoc.slug, body: anotherDoc.doc.content, htmlmode: false });
-
- return run([`./__tests__/${fixturesBaseDir}/existing-docs`, '--key', 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(
- [
- `βοΈ successfully updated 'simple-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`,
- `βοΈ successfully updated 'another-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/subdir/another-doc.md`,
- ].join('\n'),
- );
-
- getMocks.done();
- updateMocks.done();
- });
- });
-
- it('should return custom page update info for dry run', () => {
- expect.assertions(1);
-
- const getMocks = getAPIv1Mock()
- .get('/api/v1/custompages/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' })
- .get('/api/v1/custompages/another-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- return run(['--dryRun', `./__tests__/${fixturesBaseDir}/existing-docs`, '--key', 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(
- [
- `π dry run! This will update 'simple-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/simple-doc.md with the following metadata: ${JSON.stringify(
- simpleDoc.doc.data,
- )}`,
- `π dry run! This will update 'another-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/subdir/another-doc.md with the following metadata: ${JSON.stringify(
- anotherDoc.doc.data,
- )}`,
- ].join('\n'),
- );
-
- getMocks.done();
- });
- });
-
- it('should not send requests for custompages that have not changed', () => {
- expect.assertions(1);
-
- const getMocks = getAPIv1Mock()
- .get('/api/v1/custompages/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash })
- .get('/api/v1/custompages/another-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: anotherDoc.hash });
-
- return run([`./__tests__/${fixturesBaseDir}/existing-docs`, '--key', key]).then(skippedDocs => {
- expect(skippedDocs).toBe(
- [
- '`simple-doc` was not updated because there were no changes.',
- '`another-doc` was not updated because there were no changes.',
- ].join('\n'),
- );
-
- getMocks.done();
- });
- });
-
- it('should adjust "no changes" message if in dry run', () => {
- expect.assertions(1);
-
- const getMocks = getAPIv1Mock()
- .get('/api/v1/custompages/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash })
- .get('/api/v1/custompages/another-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: anotherDoc.slug, lastUpdatedHash: anotherDoc.hash });
-
- return run(['--dryRun', `./__tests__/${fixturesBaseDir}/existing-docs`, '--key', key]).then(skippedDocs => {
- expect(skippedDocs).toBe(
- [
- 'π dry run! `simple-doc` will not be updated because there were no changes.',
- 'π dry run! `another-doc` will not be updated because there were no changes.',
- ].join('\n'),
- );
-
- getMocks.done();
- });
- });
- });
-
- describe('new custompages', () => {
- it('should create new custom page', async () => {
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock()
- .post('/api/v1/custompages', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/new-docs`, '--key', key])).resolves.toBe(
- `π± successfully created 'new-doc' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md`,
- );
-
- getMock.done();
- postMock.done();
- });
-
- it('should create new HTML custom page', async () => {
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs-html/${slug}.html`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs-html/${slug}.html`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock()
- .post('/api/v1/custompages', { slug, html: doc.content, htmlmode: true, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, _id: id, html: doc.content, htmlmode: true, ...doc.data, lastUpdatedHash: hash });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/new-docs-html`, '--key', key])).resolves.toBe(
- `π± successfully created 'new-doc' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/new-docs-html/new-doc.html`,
- );
-
- getMock.done();
- postMock.done();
- });
-
- it('should return creation info for dry run', async () => {
- const slug = 'new-doc';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- await expect(run(['--dryRun', `./__tests__/${fixturesBaseDir}/new-docs`, '--key', 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,
- )}`,
- );
-
- getMock.done();
- });
-
- it('should fail if any custompages are invalid', async () => {
- const folder = 'failure-docs';
- const slug = 'new-doc';
-
- const errorObject = {
- error: 'CUSTOMPAGE_INVALID',
- message: "We couldn't save this page (Custom page title cannot be blank).",
- suggestion: 'Make sure all the data is correct, and the body is valid Markdown or HTML.',
- docs: 'fake-metrics-uuid',
- help: "If you need help, email support@readme.io and include the following link to your API log: 'fake-metrics-uuid'.",
- };
-
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/${folder}/${slug}.md`)));
-
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/${folder}/${slug}.md`)));
-
- const getMocks = getAPIv1Mock()
- .get(`/api/v1/custompages/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMocks = getAPIv1Mock()
- .post('/api/v1/custompages', { slug, body: doc.content, htmlmode: false, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(400, errorObject);
-
- const fullDirectory = `__tests__/${fixturesBaseDir}/${folder}`;
-
- const formattedErrorObject = {
- ...errorObject,
- message: `Error uploading ${chalk.underline(`${fullDirectory}/${slug}.md`)}:\n\n${errorObject.message}`,
- };
-
- await expect(run([`./${fullDirectory}`, '--key', key])).rejects.toStrictEqual(
- new APIv1Error(formattedErrorObject),
- );
-
- getMocks.done();
- postMocks.done();
- });
- });
-
- describe('slug metadata', () => {
- it('should use provided slug', async () => {
- const slug = 'new-doc-slug';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/slug-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/slug-docs/${slug}.md`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${doc.data.slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock()
- .post('/api/v1/custompages', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug: doc.data.slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/slug-docs`, '--key', key])).resolves.toBe(
- `π± successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`,
- );
-
- getMock.done();
- postMock.done();
- });
- });
-});
diff --git a/__tests__/commands/custompages/single.test.ts b/__tests__/commands/custompages/single.test.ts
deleted file mode 100644
index e255b3d6c..000000000
--- a/__tests__/commands/custompages/single.test.ts
+++ /dev/null
@@ -1,291 +0,0 @@
-import fs from 'node:fs';
-import path from 'node:path';
-
-import chalk from 'chalk';
-import frontMatter from 'gray-matter';
-import nock from 'nock';
-import { describe, beforeAll, afterAll, beforeEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/custompages.js';
-import { APIv1Error } from '../../../src/lib/apiError.js';
-import { getAPIv1Mock } from '../../helpers/get-api-mock.js';
-import hashFileContents from '../../helpers/hash-file-contents.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const fixturesBaseDir = '__fixtures__/custompages';
-const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`;
-const key = 'API_KEY';
-
-describe('rdme custompages (single)', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterAll(() => nock.cleanAll());
-
- it('should error if no file path provided', () => {
- return expect(run(['--key', key])).rejects.toThrow('Missing 1 required arg:\npath');
- });
-
- it('should error if the argument is not a Markdown/HTML file', () => {
- return expect(run(['--key', key, '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', () => {
- return expect(run(['--key', key, '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', () => {
- it('should create new custom page', async () => {
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock()
- .post('/api/v1/custompages', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, _id: id, body: doc.content, ...doc.data });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, '--key', key])).resolves.toBe(
- `π± successfully created 'new-doc' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`,
- );
-
- getMock.done();
- postMock.done();
- });
-
- it('should create new HTML custom page', async () => {
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs-html/${slug}.html`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs-html/${slug}.html`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock()
- .post('/api/v1/custompages', { slug, html: doc.content, htmlmode: true, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, _id: id, html: doc.content, htmlmode: true, ...doc.data });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/new-docs-html/new-doc.html`, '--key', key])).resolves.toBe(
- `π± successfully created 'new-doc' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/new-docs-html/new-doc.html`,
- );
-
- getMock.done();
- postMock.done();
- });
-
- it('should return creation info for dry run', async () => {
- const slug = 'new-doc';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- await expect(run(['--dryRun', `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, '--key', 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,
- )}`,
- );
-
- getMock.done();
- });
-
- it('should skip if it does not contain any front matter attributes', async () => {
- const filePath = `./__tests__/${fixturesBaseDir}/failure-docs/doc-sans-attributes.md`;
-
- await expect(run([filePath, '--key', key])).resolves.toBe(
- `βοΈ no front matter attributes found for ${filePath}, skipping`,
- );
- });
-
- it('should fail if some other error when retrieving page slug', async () => {
- const slug = 'new-doc';
-
- const errorObject = {
- error: 'INTERNAL_ERROR',
- message: 'Unknown error (yikes)',
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- };
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${slug}`)
- .basicAuth({ user: key })
- .reply(500, errorObject);
-
- const filePath = `./__tests__/${fixturesBaseDir}/failure-docs/${slug}.md`;
-
- const formattedErrorObject = {
- ...errorObject,
- message: `Error uploading ${chalk.underline(`${filePath}`)}:\n\n${errorObject.message}`,
- };
-
- await expect(run([filePath, '--key', key])).rejects.toStrictEqual(new APIv1Error(formattedErrorObject));
-
- getMock.done();
- });
- });
-
- describe('slug metadata', () => {
- it('should use provided slug', async () => {
- const slug = 'new-doc-slug';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/slug-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/slug-docs/${slug}.md`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/custompages/${doc.data.slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'CUSTOMPAGE_NOTFOUND',
- message: `The custom page with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock()
- .post('/api/v1/custompages', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug: doc.data.slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`, '--key', key])).resolves.toBe(
- `π± successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`,
- );
-
- getMock.done();
- postMock.done();
- });
- });
-
- describe('existing custompages', () => {
- let simpleDoc;
-
- beforeEach(() => {
- const fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/simple-doc.md'));
- simpleDoc = {
- slug: 'simple-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
- });
-
- it('should fetch custom page and merge with what is returned', () => {
- const getMock = getAPIv1Mock()
- .get('/api/v1/custompages/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- const updateMock = getAPIv1Mock()
- .put('/api/v1/custompages/simple-doc', {
- body: simpleDoc.doc.content,
- htmlmode: false,
- lastUpdatedHash: simpleDoc.hash,
- ...simpleDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, {
- slug: simpleDoc.slug,
- body: simpleDoc.doc.content,
- htmlmode: false,
- });
-
- return run([`./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, '--key', key]).then(updatedDocs => {
- expect(updatedDocs).toBe(
- `βοΈ successfully updated 'simple-doc' with contents from ./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`,
- );
-
- getMock.done();
- updateMock.done();
- });
- });
-
- it('should return custom page update info for dry run', () => {
- expect.assertions(1);
-
- const getMock = getAPIv1Mock()
- .get('/api/v1/custompages/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- return run(['--dryRun', `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, '--key', 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(
- [
- `π dry run! This will update 'simple-doc' with contents from ./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md with the following metadata: ${JSON.stringify(
- simpleDoc.doc.data,
- )}`,
- ].join('\n'),
- );
-
- getMock.done();
- },
- );
- });
-
- it('should not send requests for custompages that have not changed', () => {
- expect.assertions(1);
-
- const getMock = getAPIv1Mock()
- .get('/api/v1/custompages/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash });
-
- return run([`./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, '--key', key]).then(skippedDocs => {
- expect(skippedDocs).toBe('`simple-doc` was not updated because there were no changes.');
-
- getMock.done();
- });
- });
-
- it('should adjust "no changes" message if in dry run', () => {
- const getMock = getAPIv1Mock()
- .get('/api/v1/custompages/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash });
-
- return run(['--dryRun', `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, '--key', key]).then(
- skippedDocs => {
- expect(skippedDocs).toBe('π dry run! `simple-doc` will not be updated because there were no changes.');
-
- getMock.done();
- },
- );
- });
- });
-});
diff --git a/__tests__/commands/docs/__snapshots__/index.test.ts.snap b/__tests__/commands/docs/__snapshots__/index.test.ts.snap
deleted file mode 100644
index 3f7082f4c..000000000
--- a/__tests__/commands/docs/__snapshots__/index.test.ts.snap
+++ /dev/null
@@ -1,124 +0,0 @@
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`rdme docs > GHA onboarding E2E tests > should create GHA workflow with version passed as opt (github flag enabled) 1`] = `
-"
-Your GitHub Actions workflow file has been created! β¨
-
-Almost done! Just a couple more steps:
-1. Push your newly created file (.github/workflows/docs-test-file-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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`rdme docs > GHA onboarding E2E tests > should create GHA workflow with version passed as opt (github flag enabled) 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 π¦
-
-on:
- push:
- branches:
- # This workflow will run every time you push code to the following branch: \`docs-test-branch-github-flag\`
- # Check out GitHub's docs for more info on configuring this:
- # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows
- - docs-test-branch-github-flag
-
-jobs:
- rdme-docs:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`docs\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: docs ./__tests__/__fixtures__/docs/new-docs --key=\${{ secrets.README_API_KEY }} --version=1.0.0
-"
-`;
-
-exports[`rdme docs > GHA onboarding E2E tests > should create GHA workflow with version passed in via opt 1`] = `
-"
-Your GitHub Actions workflow file has been created! β¨
-
-Almost done! Just a couple more steps:
-1. Push your newly created file (.github/workflows/docs-test-file.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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`rdme docs > GHA onboarding E2E tests > should create GHA workflow with version passed in via opt 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 π¦
-
-on:
- push:
- branches:
- # This workflow will run every time you push code to the following branch: \`docs-test-branch\`
- # Check out GitHub's docs for more info on configuring this:
- # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows
- - docs-test-branch
-
-jobs:
- rdme-docs:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`docs\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: docs ./__tests__/__fixtures__/docs/new-docs --key=\${{ secrets.README_API_KEY }} --version=1.0.0
-"
-`;
-
-exports[`rdme docs > GHA onboarding E2E tests > should create GHA workflow with version passed in via prompt 1`] = `
-"
-Your GitHub Actions workflow file has been created! β¨
-
-Almost done! Just a couple more steps:
-1. Push your newly created file (.github/workflows/docs-test-file.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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`rdme docs > GHA onboarding E2E tests > should create GHA workflow with version passed in via prompt 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 π¦
-
-on:
- push:
- branches:
- # This workflow will run every time you push code to the following branch: \`docs-test-branch\`
- # Check out GitHub's docs for more info on configuring this:
- # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows
- - docs-test-branch
-
-jobs:
- rdme-docs:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`docs\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: docs ./__tests__/__fixtures__/docs/new-docs --key=\${{ secrets.README_API_KEY }} --version=1.0.1
-"
-`;
diff --git a/__tests__/commands/docs/__snapshots__/multiple.test.ts.snap b/__tests__/commands/docs/__snapshots__/multiple.test.ts.snap
deleted file mode 100644
index e6de4e4bc..000000000
--- a/__tests__/commands/docs/__snapshots__/multiple.test.ts.snap
+++ /dev/null
@@ -1,3 +0,0 @@
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`rdme docs (multiple) > should return an error message when it encounters a cycle 1`] = `[Error: Cyclic dependency, node was:{"content":"\\n# Parent Body\\n","data":{"title":"Parent","parentDocSlug":"grandparent"},"filePath":"__tests__/__fixtures__/docs/multiple-docs-cycle/parent.md","hash":"0fc832371f8e240047bfc14bc8be9e37d50c8bb8","slug":"parent"}]`;
diff --git a/__tests__/commands/docs/index.test.ts b/__tests__/commands/docs/index.test.ts
deleted file mode 100644
index f71d9d12c..000000000
--- a/__tests__/commands/docs/index.test.ts
+++ /dev/null
@@ -1,729 +0,0 @@
-/* eslint-disable no-console */
-
-import fs from 'node:fs';
-import path from 'node:path';
-
-import chalk from 'chalk';
-import frontMatter from 'gray-matter';
-import nock from 'nock';
-import prompts from 'prompts';
-import { describe, beforeAll, afterAll, beforeEach, afterEach, it, expect, vi, type MockInstance } from 'vitest';
-
-import Command from '../../../src/commands/docs/index.js';
-import { APIv1Error } from '../../../src/lib/apiError.js';
-import { getAPIv1Mock, getAPIv1MockWithVersionHeader } from '../../helpers/get-api-mock.js';
-import { after, before } from '../../helpers/get-gha-setup.js';
-import hashFileContents from '../../helpers/hash-file-contents.js';
-import { runCommandAndReturnResult, runCommandWithHooks } from '../../helpers/oclif.js';
-import { after as afterGHAEnv, before as beforeGHAEnv } from '../../helpers/setup-gha-env.js';
-
-const fixturesBaseDir = '__fixtures__/docs';
-const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`;
-
-const key = 'API_KEY';
-const version = '1.0.0';
-const category = 'CATEGORY_ID';
-
-describe('rdme docs', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterAll(() => nock.cleanAll());
-
- it('should error if no path provided', () => {
- return expect(run(['--key', key, '--version', '1.0.0'])).rejects.toThrow('Missing 1 required arg:\npath');
- });
-
- it('should error if the argument is not a folder', async () => {
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['--key', key, '--version', '1.0.0', 'not-a-folder'])).rejects.toStrictEqual(
- new Error("Oops! We couldn't locate a file or directory at the path you provided."),
- );
-
- versionMock.done();
- });
-
- it('should error if the folder contains no markdown files', async () => {
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['--key', key, '--version', '1.0.0', '.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();
- });
-
- describe('existing docs', () => {
- let simpleDoc;
- let anotherDoc;
-
- beforeEach(() => {
- let fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/simple-doc.md'));
- simpleDoc = {
- slug: 'simple-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
-
- fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/subdir/another-doc.md'));
- anotherDoc = {
- slug: 'another-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
- });
-
- it('should fetch doc and merge with what is returned', () => {
- expect.assertions(1);
-
- const getMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' })
- .get('/api/v1/docs/another-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: anotherDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- const updateMocks = getAPIv1MockWithVersionHeader(version)
- .put('/api/v1/docs/simple-doc', {
- body: simpleDoc.doc.content,
- lastUpdatedHash: simpleDoc.hash,
- ...simpleDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, {
- category,
- slug: simpleDoc.slug,
- body: simpleDoc.doc.content,
- })
- .put('/api/v1/docs/another-doc', {
- body: anotherDoc.doc.content,
- lastUpdatedHash: anotherDoc.hash,
- ...anotherDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, { category, slug: anotherDoc.slug, body: anotherDoc.doc.content });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- return run([`./__tests__/${fixturesBaseDir}/existing-docs`, '--key', key, '--version', 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(
- [
- `βοΈ successfully updated 'simple-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`,
- `βοΈ successfully updated 'another-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/subdir/another-doc.md`,
- ].join('\n'),
- );
-
- getMocks.done();
- updateMocks.done();
- versionMock.done();
- },
- );
- });
-
- it('should return doc update info for dry run', () => {
- expect.assertions(1);
-
- const getMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' })
- .get('/api/v1/docs/another-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: anotherDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- return run(['--dryRun', `./__tests__/${fixturesBaseDir}/existing-docs`, '--key', key, '--version', 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(
- [
- `π dry run! This will update 'simple-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/simple-doc.md with the following metadata: ${JSON.stringify(
- simpleDoc.doc.data,
- )}`,
- `π dry run! This will update 'another-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/subdir/another-doc.md with the following metadata: ${JSON.stringify(
- anotherDoc.doc.data,
- )}`,
- ].join('\n'),
- );
-
- getMocks.done();
- versionMock.done();
- },
- );
- });
-
- it('should not send requests for docs that have not changed', () => {
- expect.assertions(1);
-
- const getMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash })
- .get('/api/v1/docs/another-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: anotherDoc.slug, lastUpdatedHash: anotherDoc.hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- return run([`./__tests__/${fixturesBaseDir}/existing-docs`, '--key', key, '--version', version]).then(
- skippedDocs => {
- expect(skippedDocs).toBe(
- [
- '`simple-doc` was not updated because there were no changes.',
- '`another-doc` was not updated because there were no changes.',
- ].join('\n'),
- );
-
- getMocks.done();
- versionMock.done();
- },
- );
- });
-
- it('should adjust "no changes" message if in dry run', () => {
- expect.assertions(1);
-
- const getMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash })
- .get('/api/v1/docs/another-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: anotherDoc.slug, lastUpdatedHash: anotherDoc.hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- return run(['--dryRun', `./__tests__/${fixturesBaseDir}/existing-docs`, '--key', key, '--version', version]).then(
- skippedDocs => {
- expect(skippedDocs).toBe(
- [
- 'π dry run! `simple-doc` will not be updated because there were no changes.',
- 'π dry run! `another-doc` will not be updated because there were no changes.',
- ].join('\n'),
- );
-
- getMocks.done();
- versionMock.done();
- },
- );
- });
- });
-
- describe('new docs', () => {
- it('should create new doc', async () => {
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/new-docs`, '--key', key, '--version', version])).resolves.toBe(
- `π± successfully created 'new-doc' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md`,
- );
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
-
- it('should return creation info for dry run', async () => {
- const slug = 'new-doc';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run(['--dryRun', `./__tests__/${fixturesBaseDir}/new-docs`, '--key', key, '--version', 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,
- )}`,
- );
-
- getMock.done();
- versionMock.done();
- });
-
- it('should fail if any docs are invalid', async () => {
- const folder = 'failure-docs';
- const slug = 'new-doc';
-
- const errorObject = {
- error: 'DOC_INVALID',
- message: "We couldn't save this doc (Path `category` is required.).",
- };
-
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/${folder}/${slug}.md`)));
-
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/${folder}/${slug}.md`)));
-
- const getMocks = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMocks = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(400, errorObject);
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const fullDirectory = `__tests__/${fixturesBaseDir}/${folder}`;
-
- const formattedErrorObject = {
- ...errorObject,
- message: `Error uploading ${chalk.underline(`${fullDirectory}/${slug}.md`)}:\n\n${errorObject.message}`,
- };
-
- await expect(run([`./${fullDirectory}`, '--key', key, '--version', version])).rejects.toStrictEqual(
- new APIv1Error(formattedErrorObject),
- );
-
- getMocks.done();
- postMocks.done();
- versionMock.done();
- });
- });
-
- describe('slug metadata', () => {
- it('should use provided slug', async () => {
- const slug = 'new-doc-slug';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/slug-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/slug-docs/${slug}.md`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/docs/${doc.data.slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock()
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug: doc.data.slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/slug-docs`, '--key', key, '--version', version])).resolves.toBe(
- `π± successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`,
- );
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
- });
-
- describe('GHA onboarding E2E tests', () => {
- let consoleInfoSpy: MockInstance;
- let yamlOutput;
-
- const getCommandOutput = () => {
- return [consoleInfoSpy.mock.calls.join('\n\n')].filter(Boolean).join('\n\n');
- };
-
- beforeEach(() => {
- consoleInfoSpy = vi.spyOn(console, 'info').mockImplementation(() => {});
-
- before((fileName, data) => {
- yamlOutput = data;
- });
- });
-
- afterEach(() => {
- after();
-
- consoleInfoSpy.mockRestore();
- });
-
- it('should create GHA workflow with version passed in via prompt', async () => {
- expect.assertions(6);
-
- const altVersion = '1.0.1';
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const versionsMock = getAPIv1Mock()
- .get('/api/v1/version')
- .basicAuth({ user: key })
- .reply(200, [{ version }, { version: altVersion }]);
-
- const getMock = getAPIv1MockWithVersionHeader(altVersion)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1MockWithVersionHeader(altVersion)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { _id: id, slug, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const fileName = 'docs-test-file';
- prompts.inject([altVersion, true, 'docs-test-branch', fileName]);
-
- await expect(run([`./__tests__/${fixturesBaseDir}/new-docs`, '--key', key])).resolves.toMatchSnapshot();
-
- expect(yamlOutput).toMatchSnapshot();
- expect(fs.writeFileSync).toHaveBeenCalledWith(`.github/workflows/${fileName}.yml`, expect.any(String));
- expect(console.info).toHaveBeenCalledTimes(2);
- const output = getCommandOutput();
- expect(output).toMatch("Looks like you're running this command in a GitHub Repository!");
- expect(output).toMatch(`successfully created '${slug}' (ID: ${id}) with contents from`);
-
- versionsMock.done();
- getMock.done();
- postMock.done();
- });
-
- it('should create GHA workflow with version passed in via opt', async () => {
- expect.assertions(3);
-
- const slug = 'new-doc';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const fileName = 'docs-test-file';
- prompts.inject([true, 'docs-test-branch', fileName]);
-
- await expect(
- run([`./__tests__/${fixturesBaseDir}/new-docs`, '--key', key, '--version', version]),
- ).resolves.toMatchSnapshot();
-
- expect(yamlOutput).toMatchSnapshot();
- expect(fs.writeFileSync).toHaveBeenCalledWith(`.github/workflows/${fileName}.yml`, expect.any(String));
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
-
- it('should create GHA workflow with version passed as opt (github flag enabled)', async () => {
- expect.assertions(3);
-
- const slug = 'new-doc';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const fileName = 'docs-test-file-github-flag';
- prompts.inject(['docs-test-branch-github-flag', fileName]);
-
- await expect(
- run([`./__tests__/${fixturesBaseDir}/new-docs`, '--github', '--key', key, '--version', version]),
- ).resolves.toMatchSnapshot();
-
- expect(yamlOutput).toMatchSnapshot();
- expect(fs.writeFileSync).toHaveBeenCalledWith(`.github/workflows/${fileName}.yml`, expect.any(String));
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
-
- it('should reject if user says no to creating GHA workflow', async () => {
- const slug = 'new-doc';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- prompts.inject([false]);
-
- await expect(
- run([`./__tests__/${fixturesBaseDir}/new-docs`, '--key', key, '--version', 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.',
- ),
- );
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
- });
-
- describe('command execution in GitHub Actions runner', () => {
- beforeEach(() => {
- beforeGHAEnv();
- });
-
- afterEach(afterGHAEnv);
-
- it('should sync new docs directory with correct headers', async () => {
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock({
- 'x-rdme-ci': 'GitHub Actions (test)',
- 'x-readme-source': 'cli-gh',
- 'x-readme-source-url':
- 'https://github.com/octocat/Hello-World/blob/ffac537e6cbbf934b08745a378932722df287a53/__tests__/__fixtures__/docs/new-docs/new-doc.md',
- 'x-readme-version': version,
- })
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run([`./__tests__/${fixturesBaseDir}/new-docs`, '--key', key, '--version', version])).resolves.toBe(
- `π± successfully created 'new-doc' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/new-docs/new-doc.md`,
- );
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
-
- it('should sync existing docs directory with correct headers', () => {
- let fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/simple-doc.md'));
- const simpleDoc = {
- slug: 'simple-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
-
- fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/subdir/another-doc.md'));
- const anotherDoc = {
- slug: 'another-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
-
- expect.assertions(1);
-
- const getMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' })
- .get('/api/v1/docs/another-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: anotherDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- const firstUpdateMock = getAPIv1Mock({
- 'x-rdme-ci': 'GitHub Actions (test)',
- 'x-readme-source': 'cli-gh',
- 'x-readme-source-url':
- 'https://github.com/octocat/Hello-World/blob/ffac537e6cbbf934b08745a378932722df287a53/__tests__/__fixtures__/docs/existing-docs/simple-doc.md',
- 'x-readme-version': version,
- })
- .put('/api/v1/docs/simple-doc', {
- body: simpleDoc.doc.content,
- lastUpdatedHash: simpleDoc.hash,
- ...simpleDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, {
- category,
- slug: simpleDoc.slug,
- body: simpleDoc.doc.content,
- });
-
- const secondUpdateMock = getAPIv1Mock({
- 'x-rdme-ci': 'GitHub Actions (test)',
- 'x-readme-source': 'cli-gh',
- 'x-readme-source-url':
- 'https://github.com/octocat/Hello-World/blob/ffac537e6cbbf934b08745a378932722df287a53/__tests__/__fixtures__/docs/existing-docs/subdir/another-doc.md',
- 'x-readme-version': version,
- })
- .put('/api/v1/docs/another-doc', {
- body: anotherDoc.doc.content,
- lastUpdatedHash: anotherDoc.hash,
- ...anotherDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, { category, slug: anotherDoc.slug, body: anotherDoc.doc.content });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- return run([`__tests__/${fixturesBaseDir}/existing-docs`, '--key', key, '--version', 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(
- [
- `βοΈ successfully updated 'simple-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`,
- `βοΈ successfully updated 'another-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/subdir/another-doc.md`,
- ].join('\n'),
- );
-
- getMocks.done();
- firstUpdateMock.done();
- secondUpdateMock.done();
- versionMock.done();
- },
- );
- });
- });
-
- describe('rdme guides', () => {
- it('should error if no path provided', async () => {
- return expect(
- (await runCommandWithHooks(['guides', '--key', key, '--version', '1.0.0'])).error.message,
- ).toContain('Missing 1 required arg:\npath');
- });
- });
-});
diff --git a/__tests__/commands/docs/multiple.test.ts b/__tests__/commands/docs/multiple.test.ts
deleted file mode 100644
index 40c0a29de..000000000
--- a/__tests__/commands/docs/multiple.test.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import fs from 'node:fs';
-import path from 'node:path';
-
-import frontMatter from 'gray-matter';
-import nock from 'nock';
-import { describe, beforeAll, afterAll, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/docs/index.js';
-import { getAPIv1Mock, getAPIv1MockWithVersionHeader } from '../../helpers/get-api-mock.js';
-import hashFileContents from '../../helpers/hash-file-contents.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const fixturesBaseDir = '__fixtures__/docs';
-const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`;
-
-const key = 'API_KEY';
-const version = '1.0.0';
-
-describe('rdme docs (multiple)', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterAll(() => nock.cleanAll());
-
- it('should upload parent docs first', async () => {
- const dir = 'multiple-docs';
- const slugs = ['grandparent', 'parent', 'child', 'friend'];
- let id = 1234;
-
- const mocks = slugs.flatMap(slug => {
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/${dir}/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/${dir}/${slug}.md`)));
-
- return [
- getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- }),
- getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- // eslint-disable-next-line no-plusplus
- .reply(201, { slug, _id: id++, body: doc.content, ...doc.data, lastUpdatedHash: hash }),
- ];
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const promise = run([`./__tests__/${fixturesBaseDir}/${dir}`, '--key', key, '--version', version]);
-
- await expect(promise).resolves.toStrictEqual(
- [
- `π± successfully created 'friend' (ID: 1237) with contents from __tests__/${fixturesBaseDir}/${dir}/friend.md`,
- `π± successfully created 'grandparent' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/${dir}/grandparent.md`,
- `π± successfully created 'parent' (ID: 1235) with contents from __tests__/${fixturesBaseDir}/${dir}/parent.md`,
- `π± successfully created 'child' (ID: 1236) with contents from __tests__/${fixturesBaseDir}/${dir}/child.md`,
- ].join('\n'),
- );
-
- mocks.forEach(mock => mock.done());
- versionMock.done();
- });
-
- it('should upload docs with parent doc ids first', async () => {
- const dir = 'docs-with-parent-ids';
- const slugs = ['child', 'friend', 'with-parent-doc', 'parent'];
- let id = 1234;
-
- const mocks = slugs.flatMap(slug => {
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/${dir}/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/${dir}/${slug}.md`)));
-
- return [
- getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- }),
- getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- // eslint-disable-next-line no-plusplus
- .reply(201, { slug, _id: id++, body: doc.content, ...doc.data, lastUpdatedHash: hash }),
- ];
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const promise = run([`./__tests__/${fixturesBaseDir}/${dir}`, '--key', key, '--version', version]);
-
- await expect(promise).resolves.toStrictEqual(
- [
- `π± successfully created 'with-parent-doc' (ID: 1236) with contents from __tests__/${fixturesBaseDir}/${dir}/with-parent-doc.md`,
- `π± successfully created 'friend' (ID: 1235) with contents from __tests__/${fixturesBaseDir}/${dir}/friend.md`,
- `π± successfully created 'parent' (ID: 1237) with contents from __tests__/${fixturesBaseDir}/${dir}/parent.md`,
- `π± successfully created 'child' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/${dir}/child.md`,
- ].join('\n'),
- );
-
- mocks.forEach(mock => mock.done());
- versionMock.done();
- });
-
- it('should upload child docs without the parent', async () => {
- const dir = 'multiple-docs-no-parents';
- const slugs = ['child', 'friend'];
- let id = 1234;
-
- const mocks = slugs.flatMap(slug => {
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/${dir}/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/${dir}/${slug}.md`)));
-
- return [
- getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- }),
- getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- // eslint-disable-next-line no-plusplus
- .reply(201, { slug, _id: id++, body: doc.content, ...doc.data, lastUpdatedHash: hash }),
- ];
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const promise = run([`./__tests__/${fixturesBaseDir}/${dir}`, '--key', key, '--version', version]);
-
- await expect(promise).resolves.toStrictEqual(
- [
- `π± successfully created 'child' (ID: 1234) with contents from __tests__/${fixturesBaseDir}/${dir}/child.md`,
- `π± successfully created 'friend' (ID: 1235) with contents from __tests__/${fixturesBaseDir}/${dir}/friend.md`,
- ].join('\n'),
- );
-
- mocks.forEach(mock => mock.done());
- versionMock.done();
- });
-
- it('should return an error message when it encounters a cycle', async () => {
- const dir = 'multiple-docs-cycle';
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const promise = run([`./__tests__/${fixturesBaseDir}/${dir}`, '--key', key, '--version', version]);
-
- await expect(promise).rejects.toMatchSnapshot();
- versionMock.done();
- });
-});
diff --git a/__tests__/commands/docs/prune.test.ts b/__tests__/commands/docs/prune.test.ts
deleted file mode 100644
index 162e5cb7e..000000000
--- a/__tests__/commands/docs/prune.test.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-import nock from 'nock';
-import prompts from 'prompts';
-import { describe, beforeAll, afterAll, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/docs/prune.js';
-import { getAPIv1Mock, getAPIv1MockWithVersionHeader } from '../../helpers/get-api-mock.js';
-import { runCommandAndReturnResult, runCommandWithHooks } from '../../helpers/oclif.js';
-
-const fixturesBaseDir = '__fixtures__/docs';
-
-const key = 'API_KEY';
-const version = '1.0.0';
-
-describe('rdme docs prune', () => {
- const folder = `./__tests__/${fixturesBaseDir}/delete-docs`;
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterAll(() => nock.cleanAll());
-
- it('should error if no folder provided', () => {
- return expect(run(['--key', key, '--version', version])).rejects.rejects.toThrow('Missing 1 required arg:\nfolder');
- });
-
- it('should error if the argument is not a folder', async () => {
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['--key', key, '--version', version, 'not-a-folder'])).rejects.toStrictEqual(
- new Error("ENOENT: no such file or directory, scandir 'not-a-folder'"),
- );
-
- versionMock.done();
- });
-
- it('should do nothing if the user aborted', async () => {
- prompts.inject([false]);
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run([folder, '--key', key, '--version', version])).rejects.toStrictEqual(
- new Error('Aborting, no changes were made.'),
- );
-
- versionMock.done();
- });
-
- it('should not ask for user confirmation if `confirm` is set to true', async () => {
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const apiMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ slug: 'category1', type: 'guide' }], { 'x-total-count': '1' })
- .get('/api/v1/categories/category1/docs')
- .basicAuth({ user: key })
- .reply(200, [{ slug: 'this-doc-should-be-missing-in-folder' }, { slug: 'some-doc' }])
- .delete('/api/v1/docs/this-doc-should-be-missing-in-folder')
- .basicAuth({ user: key })
- .reply(204, '');
-
- await expect(run([folder, '--key', key, '--version', version, '--confirm'])).resolves.toBe(
- 'ποΈ successfully deleted `this-doc-should-be-missing-in-folder`.',
- );
-
- apiMocks.done();
- versionMock.done();
- });
-
- it('should delete doc if file is missing', async () => {
- prompts.inject([true]);
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const apiMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ slug: 'category1', type: 'guide' }], { 'x-total-count': '1' })
- .get('/api/v1/categories/category1/docs')
- .basicAuth({ user: key })
- .reply(200, [{ slug: 'this-doc-should-be-missing-in-folder' }, { slug: 'some-doc' }])
- .delete('/api/v1/docs/this-doc-should-be-missing-in-folder')
- .basicAuth({ user: key })
- .reply(204, '');
-
- await expect(run([folder, '--key', key, '--version', version])).resolves.toBe(
- 'ποΈ successfully deleted `this-doc-should-be-missing-in-folder`.',
- );
-
- apiMocks.done();
- versionMock.done();
- });
-
- it('should delete doc and its child if they are missing', async () => {
- prompts.inject([true]);
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const apiMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ slug: 'category1', type: 'guide' }], { 'x-total-count': '1' })
- .get('/api/v1/categories/category1/docs')
- .basicAuth({ user: key })
- .reply(200, [
- { slug: 'this-doc-should-be-missing-in-folder', children: [{ slug: 'this-child-is-also-missing' }] },
- { slug: 'some-doc' },
- ])
- .delete('/api/v1/docs/this-doc-should-be-missing-in-folder')
- .basicAuth({ user: key })
- .reply(204, '')
- .delete('/api/v1/docs/this-child-is-also-missing')
- .basicAuth({ user: key })
- .reply(204, '');
-
- await expect(run([folder, '--key', key, '--version', version])).resolves.toBe(
- 'ποΈ successfully deleted `this-child-is-also-missing`.\nποΈ successfully deleted `this-doc-should-be-missing-in-folder`.',
- );
-
- apiMocks.done();
- versionMock.done();
- });
-
- it('should return doc delete info for dry run', async () => {
- prompts.inject([true]);
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
- const apiMocks = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/categories?perPage=20&page=1')
- .basicAuth({ user: key })
- .reply(200, [{ slug: 'category1', type: 'guide' }], { 'x-total-count': '1' })
- .get('/api/v1/categories/category1/docs')
- .basicAuth({ user: key })
- .reply(200, [{ slug: 'this-doc-should-be-missing-in-folder' }]);
-
- await expect(run([folder, '--key', key, '--version', version, '--dryRun'])).resolves.toBe(
- 'π dry run! This will delete `this-doc-should-be-missing-in-folder`.',
- );
-
- apiMocks.done();
- versionMock.done();
- });
-
- describe('rdme guides prune', () => {
- it('should error if no folder provided', async () => {
- return expect(
- (await runCommandWithHooks(['guides', 'prune', '--key', key, '--version', version])).error.message,
- ).toContain('Missing 1 required arg:\nfolder');
- });
- });
-});
diff --git a/__tests__/commands/docs/single.test.ts b/__tests__/commands/docs/single.test.ts
deleted file mode 100644
index 007bd28d2..000000000
--- a/__tests__/commands/docs/single.test.ts
+++ /dev/null
@@ -1,443 +0,0 @@
-import fs from 'node:fs';
-import path from 'node:path';
-
-import chalk from 'chalk';
-import frontMatter from 'gray-matter';
-import nock from 'nock';
-import { describe, beforeAll, afterAll, beforeEach, afterEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/docs/index.js';
-import { APIv1Error } from '../../../src/lib/apiError.js';
-import { getAPIv1Mock, getAPIv1MockWithVersionHeader } from '../../helpers/get-api-mock.js';
-import hashFileContents from '../../helpers/hash-file-contents.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-import { after as afterGHAEnv, before as beforeGHAEnv } from '../../helpers/setup-gha-env.js';
-
-const fixturesBaseDir = '__fixtures__/docs';
-const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`;
-
-const key = 'API_KEY';
-const version = '1.0.0';
-const category = 'CATEGORY_ID';
-
-describe('rdme docs (single)', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterAll(() => nock.cleanAll());
-
- it('should error if no file path provided', () => {
- return expect(run(['--key', key, '--version', version])).rejects.toThrow('Missing 1 required arg:\npath');
- });
-
- it('should error if the argument is not a Markdown file', async () => {
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['--key', key, '--version', version, '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 = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
- await expect(run(['--key', key, '--version', version, 'non-existent-file.markdown'])).rejects.toStrictEqual(
- new Error("Oops! We couldn't locate a file or directory at the path you provided."),
- );
- versionMock.done();
- });
-
- describe('new docs', () => {
- it('should create new doc', async () => {
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1MockWithVersionHeader(version)
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run([`./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, '--key', key, '--version', version]),
- ).resolves.toBe(
- `π± successfully created 'new-doc' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`,
- );
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
-
- it('should return creation info for dry run', async () => {
- const slug = 'new-doc';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run(['--dryRun', `./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, '--key', key, '--version', 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,
- )}`,
- );
-
- getMock.done();
- versionMock.done();
- });
-
- it('should skip doc if it does not contain any front matter attributes', async () => {
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const filePath = `./__tests__/${fixturesBaseDir}/failure-docs/doc-sans-attributes.md`;
-
- await expect(run(['--key', key, '--version', version, filePath])).resolves.toBe(
- `βοΈ no front matter attributes found for ${filePath}, skipping`,
- );
-
- versionMock.done();
- });
-
- it('should fail if some other error when retrieving page slug', async () => {
- const slug = 'new-doc';
-
- const errorObject = {
- error: 'INTERNAL_ERROR',
- message: 'Unknown error (yikes)',
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- };
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(500, errorObject);
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- const filePath = `./__tests__/${fixturesBaseDir}/failure-docs/${slug}.md`;
-
- const formattedErrorObject = {
- ...errorObject,
- message: `Error uploading ${chalk.underline(`${filePath}`)}:\n\n${errorObject.message}`,
- };
-
- await expect(run([filePath, '--key', key, '--version', version])).rejects.toStrictEqual(
- new APIv1Error(formattedErrorObject),
- );
-
- getMock.done();
- versionMock.done();
- });
- });
-
- describe('slug metadata', () => {
- it('should use provided slug', async () => {
- const slug = 'new-doc-slug';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/slug-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/slug-docs/${slug}.md`)));
-
- const getMock = getAPIv1Mock()
- .get(`/api/v1/docs/${doc.data.slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock()
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug: doc.data.slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run([`./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`, '--key', key, '--version', version]),
- ).resolves.toBe(
- `π± successfully created 'marc-actually-wrote-a-test' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/slug-docs/new-doc-slug.md`,
- );
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
- });
-
- describe('existing docs', () => {
- let simpleDoc;
-
- beforeEach(() => {
- const fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/simple-doc.md'));
- simpleDoc = {
- slug: 'simple-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
- });
-
- it('should fetch doc and merge with what is returned', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- const updateMock = getAPIv1MockWithVersionHeader(version)
- .put('/api/v1/docs/simple-doc', {
- body: simpleDoc.doc.content,
- lastUpdatedHash: simpleDoc.hash,
- ...simpleDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, {
- category,
- slug: simpleDoc.slug,
- body: simpleDoc.doc.content,
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run([`./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, '--key', key, '--version', version]),
- ).resolves.toBe(
- `βοΈ successfully updated 'simple-doc' with contents from ./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`,
- );
-
- getMock.done();
- updateMock.done();
- versionMock.done();
- });
-
- it('should return doc update info for dry run', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run([
- '--dryRun',
- `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`,
- '--key',
- key,
- '--version',
- version,
- ]),
- ).resolves.toBe(
- [
- `π dry run! This will update 'simple-doc' with contents from ./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md with the following metadata: ${JSON.stringify(
- simpleDoc.doc.data,
- )}`,
- ].join('\n'),
- );
-
- getMock.done();
- versionMock.done();
- });
-
- it('should not send requests for docs that have not changed', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run([`./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, '--key', key, '--version', version]),
- ).resolves.toBe('`simple-doc` was not updated because there were no changes.');
-
- getMock.done();
- versionMock.done();
- });
-
- it('should adjust "no changes" message if in dry run', async () => {
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: simpleDoc.hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run([
- '--dryRun',
- `./__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`,
- '--key',
- key,
- '--version',
- version,
- ]),
- ).resolves.toBe('π dry run! `simple-doc` will not be updated because there were no changes.');
-
- getMock.done();
- versionMock.done();
- });
- });
-
- describe('command execution in GitHub Actions runner', () => {
- beforeEach(() => {
- beforeGHAEnv();
- });
-
- afterEach(afterGHAEnv);
-
- it('should sync new doc with correct headers', async () => {
- const slug = 'new-doc';
- const id = '1234';
- const doc = frontMatter(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
- const hash = hashFileContents(fs.readFileSync(path.join(fullFixturesDir, `/new-docs/${slug}.md`)));
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get(`/api/v1/docs/${slug}`)
- .basicAuth({ user: key })
- .reply(404, {
- error: 'DOC_NOTFOUND',
- message: `The doc with the slug '${slug}' couldn't be found`,
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- });
-
- const postMock = getAPIv1Mock({
- 'x-rdme-ci': 'GitHub Actions (test)',
- 'x-readme-source': 'cli-gh',
- 'x-readme-source-url':
- 'https://github.com/octocat/Hello-World/blob/ffac537e6cbbf934b08745a378932722df287a53/__tests__/__fixtures__/docs/new-docs/new-doc.md',
- 'x-readme-version': version,
- })
- .post('/api/v1/docs', { slug, body: doc.content, ...doc.data, lastUpdatedHash: hash })
- .basicAuth({ user: key })
- .reply(201, { slug, _id: id, body: doc.content, ...doc.data, lastUpdatedHash: hash });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run([`./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`, '--key', key, '--version', version]),
- ).resolves.toBe(
- `π± successfully created 'new-doc' (ID: 1234) with contents from ./__tests__/${fixturesBaseDir}/new-docs/new-doc.md`,
- );
-
- getMock.done();
- postMock.done();
- versionMock.done();
- });
-
- it('should sync existing doc with correct headers', async () => {
- const fileContents = fs.readFileSync(path.join(fullFixturesDir, '/existing-docs/simple-doc.md'));
- const simpleDoc = {
- slug: 'simple-doc',
- doc: frontMatter(fileContents),
- hash: hashFileContents(fileContents),
- };
-
- const getMock = getAPIv1MockWithVersionHeader(version)
- .get('/api/v1/docs/simple-doc')
- .basicAuth({ user: key })
- .reply(200, { category, slug: simpleDoc.slug, lastUpdatedHash: 'anOldHash' });
-
- const updateMock = getAPIv1Mock({
- 'x-rdme-ci': 'GitHub Actions (test)',
- 'x-readme-source': 'cli-gh',
- 'x-readme-source-url':
- 'https://github.com/octocat/Hello-World/blob/ffac537e6cbbf934b08745a378932722df287a53/__tests__/__fixtures__/docs/existing-docs/simple-doc.md',
- 'x-readme-version': version,
- })
- .put('/api/v1/docs/simple-doc', {
- body: simpleDoc.doc.content,
- lastUpdatedHash: simpleDoc.hash,
- ...simpleDoc.doc.data,
- })
- .basicAuth({ user: key })
- .reply(200, {
- category,
- slug: simpleDoc.slug,
- body: simpleDoc.doc.content,
- });
-
- const versionMock = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(
- run([`__tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`, '--key', key, '--version', version]),
- ).resolves.toBe(
- `βοΈ successfully updated 'simple-doc' with contents from __tests__/${fixturesBaseDir}/existing-docs/simple-doc.md`,
- );
-
- getMock.done();
- updateMock.done();
- versionMock.done();
- });
- });
-});
diff --git a/__tests__/commands/open.test.ts b/__tests__/commands/open.test.ts
deleted file mode 100644
index 3ab9829f0..000000000
--- a/__tests__/commands/open.test.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import type { Version } from '../../src/commands/versions/index.js';
-
-import chalk from 'chalk';
-import { describe, afterEach, beforeAll, it, expect } from 'vitest';
-
-import pkg from '../../package.json' with { type: 'json' };
-import Command from '../../src/commands/open.js';
-import configStore from '../../src/lib/configstore.js';
-import { getAPIv1Mock } from '../helpers/get-api-mock.js';
-import { runCommandAndReturnResult } from '../helpers/oclif.js';
-
-const mockArg = ['--mock'];
-
-describe('rdme open', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- run = runCommandAndReturnResult(Command);
- });
-
- afterEach(() => {
- configStore.clear();
- });
-
- it('should error if no project provided', () => {
- configStore.delete('project');
-
- return expect(run(mockArg)).rejects.toStrictEqual(new Error(`Please login using \`${pkg.name} login\`.`));
- });
-
- it('should open the project', () => {
- configStore.set('project', 'subdomain');
-
- const projectUrl = 'https://subdomain.readme.io';
-
- return expect(run(mockArg)).resolves.toBe(`Opening ${chalk.green(projectUrl)} in your browser...`);
- });
-
- describe('open --dash', () => {
- it('should open the dash', async () => {
- configStore.set('project', 'subdomain');
- configStore.set('apiKey', '12345');
-
- const version = '1.0';
- const key = '12345';
- const versionPayload: Version = {
- createdAt: '2019-06-17T22:39:56.462Z',
- is_deprecated: false,
- is_hidden: false,
- is_beta: false,
- is_stable: true,
- codename: '',
- version,
- };
-
- const mockRequest = getAPIv1Mock()
- .get('/api/v1/version')
- .basicAuth({ user: key })
- .reply(200, [versionPayload, { version: '1.0.1' }]);
-
- const dashUrl = 'https://dash.readme.com/project/subdomain/v1.0/overview';
-
- await expect(run(mockArg.concat('--dash'))).resolves.toBe(`Opening ${chalk.green(dashUrl)} in your browser...`);
- mockRequest.done();
- });
-
- it('should require user to be logged in', () => {
- configStore.set('project', 'subdomain');
-
- return expect(run(mockArg.concat('--dash'))).rejects.toStrictEqual(
- new Error(`Please login using \`${pkg.name} login\`.`),
- );
- });
- });
-});
diff --git a/__tests__/commands/versions/create.test.ts b/__tests__/commands/versions/create.test.ts
deleted file mode 100644
index 014bad9ff..000000000
--- a/__tests__/commands/versions/create.test.ts
+++ /dev/null
@@ -1,176 +0,0 @@
-import nock from 'nock';
-import prompts from 'prompts';
-import { describe, beforeAll, afterEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/versions/create.js';
-import { APIv1Error } from '../../../src/lib/apiError.js';
-import { getAPIv1Mock } from '../../helpers/get-api-mock.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const key = 'API_KEY';
-const version = '1.0.0';
-
-describe('rdme versions create', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterEach(() => nock.cleanAll());
-
- it('should error if no version provided', () => {
- return expect(run(['--key', key])).rejects.toThrow('Missing 1 required arg:\nversion');
- });
-
- it('should error if invalid version provided', () => {
- return expect(run(['--key', key, 'test'])).rejects.toStrictEqual(
- new Error('Please specify a semantic version. See `rdme help versions create` for help.'),
- );
- });
-
- it('should create a specific version', async () => {
- prompts.inject([version, false, true, true, false]);
- const newVersion = '1.0.1';
-
- const mockRequest = getAPIv1Mock()
- .get('/api/v1/version')
- .basicAuth({ user: key })
- .reply(200, [{ version }, { version: '1.1.0' }])
- .post('/api/v1/version', {
- version: newVersion,
- is_stable: false,
- is_beta: true,
- from: '1.0.0',
- is_hidden: true,
- is_deprecated: false,
- })
- .basicAuth({ user: key })
- .reply(201, { version: newVersion });
-
- await expect(run(['--key', key, newVersion])).resolves.toBe(`Version ${newVersion} created successfully.`);
- mockRequest.done();
- });
-
- it('should create a specific version with options', async () => {
- const newVersion = '1.0.1';
-
- const mockRequest = getAPIv1Mock()
- .post('/api/v1/version', {
- version: newVersion,
- codename: 'test',
- from: '1.0.0',
- is_beta: false,
- is_deprecated: false,
- is_hidden: false,
- is_stable: false,
- })
- .basicAuth({ user: key })
- .reply(201, { version: newVersion });
-
- await expect(
- run([
- '--key',
- key,
- newVersion,
- '--fork',
- version,
- '--beta',
- 'false',
- '--deprecated',
- 'false',
- '--main',
- 'false',
- '--codename',
- 'test',
- '--hidden',
- 'false',
- ]),
- ).resolves.toBe(`Version ${newVersion} created successfully.`);
-
- mockRequest.done();
- });
-
- it('should create successfully a main version', async () => {
- const newVersion = '1.0.1';
-
- const mockRequest = getAPIv1Mock()
- .post('/api/v1/version', {
- version: newVersion,
- from: '1.0.0',
- is_beta: false,
- is_stable: true,
- })
- .basicAuth({ user: key })
- .reply(201, { version: newVersion });
-
- await expect(
- run([
- '--key',
- key,
- newVersion,
- '--fork',
- version,
- '--beta',
- 'false',
- '--main',
- 'true',
- '--hidden',
- 'true',
- '--deprecated',
- 'true',
- ]),
- ).resolves.toBe(`Version ${newVersion} created successfully.`);
-
- mockRequest.done();
- });
-
- it('should catch any post request errors', async () => {
- const errorResponse = {
- error: 'VERSION_EMPTY',
- message: 'You need to include an x-readme-version header',
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- };
-
- const mockRequest = getAPIv1Mock().post('/api/v1/version').basicAuth({ user: key }).reply(400, errorResponse);
-
- await expect(run(['--key', key, version, '--fork', '0.0.5'])).rejects.toStrictEqual(new APIv1Error(errorResponse));
- mockRequest.done();
- });
-
- describe('bad flag values', () => {
- it('should throw if non-boolean `beta` flag is passed', () => {
- const newVersion = '1.0.1';
-
- return expect(run(['--key', key, newVersion, '--fork', version, '--beta', 'test'])).rejects.toThrow(
- 'Expected --beta=test to be one of: true, false',
- );
- });
-
- it('should throw if non-boolean `deprecated` flag is passed', () => {
- const newVersion = '1.0.1';
-
- return expect(run(['--key', key, newVersion, '--fork', version, '--deprecated', 'test'])).rejects.toThrow(
- 'Expected --deprecated=test to be one of: true, false',
- );
- });
-
- it('should throw if non-boolean `hidden` flag is passed', () => {
- const newVersion = '1.0.1';
-
- return expect(run(['--key', key, newVersion, '--fork', version, '--hidden', 'test'])).rejects.toThrow(
- 'Expected --hidden=test to be one of: true, false',
- );
- });
-
- it('should throw if non-boolean `main` flag is passed', () => {
- const newVersion = '1.0.1';
-
- return expect(run(['--key', key, newVersion, '--fork', version, '--main', 'test'])).rejects.toThrow(
- 'Expected --main=test to be one of: true, false',
- );
- });
- });
-});
diff --git a/__tests__/commands/versions/delete.test.ts b/__tests__/commands/versions/delete.test.ts
deleted file mode 100644
index a82b11efe..000000000
--- a/__tests__/commands/versions/delete.test.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import nock from 'nock';
-import { describe, beforeAll, afterEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/versions/delete.js';
-import { APIv1Error } from '../../../src/lib/apiError.js';
-import { getAPIv1Mock } from '../../helpers/get-api-mock.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const key = 'API_KEY';
-const version = '1.0.0';
-
-describe('rdme versions delete', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterEach(() => nock.cleanAll());
-
- it('should delete a specific version', async () => {
- const mockRequest = getAPIv1Mock()
- .delete(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { removed: true })
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['--key', key, version])).resolves.toBe('Version 1.0.0 deleted successfully.');
- mockRequest.done();
- });
-
- it('should catch any request errors', async () => {
- const errorResponse = {
- error: 'VERSION_NOTFOUND',
- message:
- "The version you specified ({version}) doesn't match any of the existing versions ({versions_list}) in ReadMe.",
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- };
-
- const mockRequest = getAPIv1Mock()
- .delete(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(404, errorResponse)
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version });
-
- await expect(run(['--key', key, version])).rejects.toStrictEqual(new APIv1Error(errorResponse));
- mockRequest.done();
- });
-});
diff --git a/__tests__/commands/versions/index.test.ts b/__tests__/commands/versions/index.test.ts
deleted file mode 100644
index 7ba6650d7..000000000
--- a/__tests__/commands/versions/index.test.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import type { Version } from '../../../src/commands/versions/index.js';
-
-import nock from 'nock';
-import { describe, beforeAll, afterEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/versions/index.js';
-import { getAPIv1Mock } from '../../helpers/get-api-mock.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const key = 'API_KEY';
-const version = '1.0.0';
-const version2 = '2.0.0';
-
-const versionPayload: Version = {
- createdAt: '2019-06-17T22:39:56.462Z',
- is_deprecated: false,
- is_hidden: false,
- is_beta: false,
- is_stable: true,
- codename: '',
- version,
-};
-
-const version2Payload: Version = {
- createdAt: '2019-06-17T22:39:56.462Z',
- is_deprecated: false,
- is_hidden: false,
- is_beta: false,
- is_stable: true,
- codename: '',
- version: version2,
-};
-
-describe('rdme versions', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterEach(() => nock.cleanAll());
-
- it('should make a request to get a list of existing versions', async () => {
- const mockRequest = getAPIv1Mock()
- .get('/api/v1/version')
- .basicAuth({ user: key })
- .reply(200, [versionPayload, version2Payload]);
-
- const output = await run(['--key', key]);
- expect(output).toStrictEqual(JSON.stringify([versionPayload, version2Payload], null, 2));
- mockRequest.done();
- });
-
- it('should get a specific version object if version flag provided', async () => {
- const mockRequest = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, versionPayload);
-
- const output = await run(['--key', key, '--version', version]);
- expect(output).toStrictEqual(JSON.stringify(versionPayload, null, 2));
- mockRequest.done();
- });
-});
diff --git a/__tests__/commands/versions/update.test.ts b/__tests__/commands/versions/update.test.ts
deleted file mode 100644
index 66734d9ab..000000000
--- a/__tests__/commands/versions/update.test.ts
+++ /dev/null
@@ -1,388 +0,0 @@
-import nock from 'nock';
-import prompts from 'prompts';
-import { describe, beforeAll, afterEach, it, expect } from 'vitest';
-
-import Command from '../../../src/commands/versions/update.js';
-import { APIv1Error } from '../../../src/lib/apiError.js';
-import { getAPIv1Mock } from '../../helpers/get-api-mock.js';
-import { runCommandAndReturnResult } from '../../helpers/oclif.js';
-
-const key = 'API_KEY';
-const version = '1.0.0';
-
-describe('rdme versions update', () => {
- let run: (args?: string[]) => Promise;
-
- beforeAll(() => {
- nock.disableNetConnect();
- run = runCommandAndReturnResult(Command);
- });
-
- afterEach(() => nock.cleanAll());
-
- it('should update a specific version object using prompts', async () => {
- const versionToChange = '1.1.0';
- prompts.inject([versionToChange, undefined, false, true, false, false]);
-
- const updatedVersionObject = {
- version: versionToChange,
- is_stable: false,
- is_beta: true,
- is_deprecated: false,
- is_hidden: false,
- };
-
- const mockRequest = getAPIv1Mock()
- .get('/api/v1/version')
- .basicAuth({ user: key })
- .reply(200, [{ version }, { version: versionToChange }])
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .put(`/api/v1/version/${versionToChange}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(201, updatedVersionObject);
-
- await expect(run(['--key', key])).resolves.toBe(`Version ${versionToChange} updated successfully.`);
- mockRequest.done();
- });
-
- it('should rename a specific version object using prompts', async () => {
- const versionToChange = '1.1.0';
- const renamedVersion = '1.1.0-update';
- prompts.inject([versionToChange, renamedVersion, false, true, false, false]);
-
- const updatedVersionObject = {
- version: renamedVersion,
- is_stable: false,
- is_beta: true,
- is_deprecated: false,
- is_hidden: false,
- };
-
- const mockRequest = getAPIv1Mock()
- .get('/api/v1/version')
- .basicAuth({ user: key })
- .reply(200, [{ version }, { version: versionToChange }])
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .put(`/api/v1/version/${versionToChange}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(201, updatedVersionObject);
-
- await expect(run(['--key', key])).resolves.toBe(`Version ${versionToChange} updated successfully.`);
- mockRequest.done();
- });
-
- it('should use subset of prompts when updating stable version', async () => {
- const versionToChange = '1.1.0';
- prompts.inject([versionToChange, undefined, true]);
-
- const updatedVersionObject = {
- version: versionToChange,
- is_beta: true,
- };
-
- const mockRequest = getAPIv1Mock()
- .get('/api/v1/version')
- .basicAuth({ user: key })
- .reply(200, [{ version }, { version: versionToChange, is_stable: true }])
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange, is_stable: true })
- .put(`/api/v1/version/${versionToChange}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(201, updatedVersionObject);
-
- await expect(run(['--key', key])).resolves.toBe(`Version ${versionToChange} updated successfully.`);
- mockRequest.done();
- });
-
- it('should update a specific version object using flags', async () => {
- const versionToChange = '1.1.0';
- const renamedVersion = '1.1.0-update';
-
- const updatedVersionObject = {
- codename: 'updated-test',
- version: renamedVersion,
- is_beta: true,
- is_deprecated: true,
- is_hidden: false,
- is_stable: false,
- };
-
- const mockRequest = getAPIv1Mock()
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .put(`/api/v1/version/${versionToChange}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(201, updatedVersionObject);
-
- await expect(
- run([
- '--key',
- key,
- versionToChange,
- '--newVersion',
- renamedVersion,
- '--deprecated',
- 'true',
- '--beta',
- 'true',
- '--main',
- 'false',
- '--codename',
- 'updated-test',
- '--hidden',
- 'false',
- ]),
- ).resolves.toBe(`Version ${versionToChange} updated successfully.`);
- mockRequest.done();
- });
-
- it("should update a specific version object using flags that contain the string 'false'", async () => {
- const versionToChange = '1.1.0';
- const renamedVersion = '1.1.0-update';
-
- const updatedVersionObject = {
- codename: 'updated-test',
- version: renamedVersion,
- is_beta: false,
- is_deprecated: false,
- is_hidden: true,
- is_stable: false,
- };
-
- const mockRequest = getAPIv1Mock()
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .put(`/api/v1/version/${versionToChange}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(201, updatedVersionObject);
-
- await expect(
- run([
- '--key',
- key,
- versionToChange,
- '--newVersion',
- renamedVersion,
- '--beta',
- 'false',
- '--deprecated',
- 'false',
- '--main',
- 'false',
- '--codename',
- 'updated-test',
- '--hidden',
- 'true',
- ]),
- ).resolves.toBe(`Version ${versionToChange} updated successfully.`);
- mockRequest.done();
- });
-
- it("should update a specific version object using flags that contain the string 'false' and a prompt", async () => {
- const versionToChange = '1.1.0';
- const renamedVersion = '1.1.0-update';
- // prompt for beta flag
- prompts.inject([false]);
-
- const updatedVersionObject = {
- codename: 'updated-test',
- version: renamedVersion,
- is_beta: false,
- is_hidden: false,
- is_stable: false,
- };
-
- const mockRequest = getAPIv1Mock()
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .put(`/api/v1/version/${versionToChange}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(201, updatedVersionObject);
-
- await expect(
- run([
- '--key',
- key,
- versionToChange,
- '--newVersion',
- renamedVersion,
- '--main',
- 'false',
- '--codename',
- 'updated-test',
- '--hidden',
- 'false',
- ]),
- ).resolves.toBe(`Version ${versionToChange} updated successfully.`);
- mockRequest.done();
- });
-
- it('should update a specific version object even if user bypasses prompt for new version name', async () => {
- const versionToChange = '1.1.0';
- // simulating user entering nothing for the prompt to enter a new version name
- prompts.inject(['']);
-
- const updatedVersionObject = {
- codename: 'updated-test',
- is_beta: false,
- is_hidden: false,
- is_stable: false,
- version: versionToChange,
- };
-
- const mockRequest = getAPIv1Mock()
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .put(`/api/v1/version/${versionToChange}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(201, updatedVersionObject);
-
- await expect(
- run([
- '--key',
- key,
- versionToChange,
- '--beta',
- 'false',
- '--main',
- 'false',
- '--codename',
- 'updated-test',
- '--hidden',
- 'false',
- ]),
- ).resolves.toBe(`Version ${versionToChange} updated successfully.`);
- mockRequest.done();
- });
-
- it('should update a version to be the main one', async () => {
- const versionToChange = '1.1.0';
- const renamedVersion = '1.1.0-update';
-
- const updatedVersionObject = {
- version: renamedVersion,
- is_beta: false,
- is_stable: true,
- };
-
- const mockRequest = getAPIv1Mock()
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .get(`/api/v1/version/${versionToChange}`)
- .basicAuth({ user: key })
- .reply(200, { version: versionToChange })
- .put(`/api/v1/version/${versionToChange}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(201, updatedVersionObject);
-
- await expect(
- run([
- '--key',
- key,
- versionToChange,
- '--newVersion',
- renamedVersion,
- '--deprecated',
- 'true',
- '--beta',
- 'false',
- '--main',
- 'true',
- '--hidden',
- 'true',
- ]),
- ).resolves.toBe(`Version ${versionToChange} updated successfully.`);
- mockRequest.done();
- });
-
- it('should catch any put request errors', async () => {
- const renamedVersion = '1.0.0-update';
-
- const updatedVersionObject = {
- version: renamedVersion,
- is_beta: true,
- is_deprecated: true,
- is_hidden: false,
- is_stable: false,
- };
-
- prompts.inject([renamedVersion, false, true, false, true]);
-
- const errorResponse = {
- error: 'VERSION_DUPLICATE',
- message: 'The version already exists.',
- suggestion: '...a suggestion to resolve the issue...',
- help: 'If you need help, email support@readme.io and mention log "fake-metrics-uuid".',
- };
-
- const mockRequest = getAPIv1Mock()
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version })
- .get(`/api/v1/version/${version}`)
- .basicAuth({ user: key })
- .reply(200, { version })
- .put(`/api/v1/version/${version}`, updatedVersionObject)
- .basicAuth({ user: key })
- .reply(400, errorResponse);
-
- await expect(run(['--key', key, version])).rejects.toStrictEqual(new APIv1Error(errorResponse));
- mockRequest.done();
- });
-
- describe('bad flag values', () => {
- it('should throw if non-boolean `beta` flag is passed', () => {
- const versionToChange = '1.1.0';
-
- return expect(run(['--key', key, versionToChange, '--beta', 'hi'])).rejects.toThrow(
- 'Expected --beta=hi to be one of: true, false',
- );
- });
-
- it('should throw if non-boolean `deprecated` flag is passed', () => {
- const versionToChange = '1.1.0';
-
- return expect(run(['--key', key, versionToChange, '--deprecated', 'hi'])).rejects.toThrow(
- 'Expected --deprecated=hi to be one of: true, false',
- );
- });
-
- it('should throw if non-boolean `hidden` flag is passed', () => {
- const versionToChange = '1.1.0';
-
- return expect(run(['--key', key, versionToChange, '--hidden', 'hi'])).rejects.toThrow(
- 'Expected --hidden=hi to be one of: true, false',
- );
- });
-
- it('should throw if non-boolean `main` flag is passed', () => {
- const versionToChange = '1.1.0';
-
- return expect(run(['--key', key, versionToChange, '--main', 'hi'])).rejects.toThrow(
- 'Expected --main=hi to be one of: true, false',
- );
- });
- });
-});
diff --git a/__tests__/lib/__snapshots__/createGHA.test.ts.snap b/__tests__/lib/__snapshots__/createGHA.test.ts.snap
index fce4a5120..79d9e2e84 100644
--- a/__tests__/lib/__snapshots__/createGHA.test.ts.snap
+++ b/__tests__/lib/__snapshots__/createGHA.test.ts.snap
@@ -164,334 +164,6 @@ jobs:
"
`;
-exports[`#createGHA > command inputs > 'custompages' ' (single)' > should run GHA creation workflow 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.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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`#createGHA > command inputs > 'custompages' ' (single)' > should run GHA creation workflow 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 π¦
-
-on:
- push:
- branches:
- # 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
- - some-branch
-
-jobs:
- rdme-custompages:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`custompages\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: custompages ./custompages/rdme.md --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`] = `
-"
-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 π
-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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`#createGHA > command inputs > 'custompages' ' (single)' > 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 π¦
-
-on:
- push:
- branches:
- # 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
- - another-branch
-
-jobs:
- rdme-custompages:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`custompages\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: custompages ./custompages/rdme.md --key=\${{ secrets.README_API_KEY }}
-"
-`;
-
-exports[`#createGHA > command inputs > 'custompages' '' > should run GHA creation workflow 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.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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`#createGHA > command inputs > 'custompages' '' > should run GHA creation workflow 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 π¦
-
-on:
- push:
- branches:
- # 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
- - some-branch
-
-jobs:
- rdme-custompages:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`custompages\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: custompages ./custompages --key=\${{ secrets.README_API_KEY }}
-"
-`;
-
-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-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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-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 π¦
-
-on:
- push:
- branches:
- # 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
- - another-branch
-
-jobs:
- rdme-custompages:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`custompages\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: custompages ./custompages --key=\${{ secrets.README_API_KEY }}
-"
-`;
-
-exports[`#createGHA > command inputs > 'docs' ' (single)' > should run GHA creation workflow 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.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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`#createGHA > command inputs > 'docs' ' (single)' > should run GHA creation workflow 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 π¦
-
-on:
- push:
- branches:
- # 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
- - some-branch
-
-jobs:
- rdme-docs:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`docs\` command π
- uses: readmeio/rdme@v7
- with:
- 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 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-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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`#createGHA > command inputs > 'docs' ' (single)' > 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 π¦
-
-on:
- push:
- branches:
- # 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
- - another-branch
-
-jobs:
- rdme-docs:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`docs\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: docs ./docs/rdme.md --key=\${{ secrets.README_API_KEY }} --version=1.0.0
-"
-`;
-
-exports[`#createGHA > command inputs > 'docs' '' > should run GHA creation workflow 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.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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-exports[`#createGHA > command inputs > 'docs' '' > should run GHA creation workflow 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 π¦
-
-on:
- push:
- branches:
- # 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
- - some-branch
-
-jobs:
- rdme-docs:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`docs\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: docs ./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`] = `
-"
-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 π
-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)
-
-π¦ If you have any more questions, feel free to drop us a line! support@readme.io
-"
-`;
-
-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 π¦
-
-on:
- push:
- branches:
- # 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
- - another-branch
-
-jobs:
- rdme-docs:
- runs-on: ubuntu-latest
- steps:
- - name: Check out repo π
- uses: actions/checkout@v4
-
- - name: Run \`docs\` command π
- uses: readmeio/rdme@v7
- with:
- rdme: docs ./docs --key=\${{ secrets.README_API_KEY }} --version=1.0.0
-"
-`;
-
exports[`#createGHA > command inputs > 'openapi' '' > should run GHA creation workflow and generate valid workflow file 1`] = `
"
Your GitHub Actions workflow file has been created! β¨
diff --git a/__tests__/lib/createGHA.test.ts b/__tests__/lib/createGHA.test.ts
index 943bb90f9..99f14053a 100644
--- a/__tests__/lib/createGHA.test.ts
+++ b/__tests__/lib/createGHA.test.ts
@@ -59,13 +59,6 @@ describe('#createGHA', () => {
// hence we're using this command ID here
{ cmd: 'openapi:validate', opts: { spec: 'petstore.json' }, label: '' },
{ cmd: 'openapi', opts: { key, spec: 'petstore.json', id: 'spec_id' }, label: '' },
- { cmd: 'docs', opts: { key, path: './docs', version: '1.0.0' }, label: '' },
- {
- cmd: 'docs',
-
- label: ' (single)',
- opts: { key, path: './docs/rdme.md', version: '1.0.0' },
- },
{ cmd: 'changelogs', opts: { key, path: './changelogs' }, label: '' },
{
cmd: 'changelogs',
@@ -73,12 +66,6 @@ describe('#createGHA', () => {
label: ' (single)',
opts: { key, path: './changelogs/rdme.md' },
},
- { cmd: 'custompages', opts: { key, path: './custompages' }, label: '' },
- {
- cmd: 'custompages',
- label: ' (single)',
- opts: { key, path: './custompages/rdme.md' },
- },
])('$cmd $label', ({ cmd, opts }) => {
let CurrentCommand: Command.Class;
diff --git a/__tests__/lib/prompts.test.ts b/__tests__/lib/prompts.test.ts
index d1dba0a90..94b8287a6 100644
--- a/__tests__/lib/prompts.test.ts
+++ b/__tests__/lib/prompts.test.ts
@@ -4,17 +4,6 @@ import { describe, it, expect } from 'vitest';
import * as promptHandler from '../../src/lib/prompts.js';
import promptTerminal from '../../src/lib/promptWrapper.js';
-const versionlist = [
- {
- version: '1',
- is_stable: true,
- },
- {
- version: '2',
- is_stable: false,
- },
-];
-
const specList = [
{
_id: 'spec1',
@@ -78,26 +67,4 @@ describe('prompt test bed', () => {
expect(answer).toStrictEqual({ option: 'spec1' });
});
});
-
- describe('versionPrompt()', () => {
- it('should allow user to choose a fork if flag is not passed (creating version)', async () => {
- prompts.inject(['1', true, true]);
-
- const answer = await promptTerminal(promptHandler.versionPrompt(versionlist));
- expect(answer).toStrictEqual({ from: '1', is_stable: true, is_beta: true });
- });
-
- it('should skip fork prompt if value passed (updating version)', async () => {
- prompts.inject(['1.2.1', false, true, true, false]);
-
- const answer = await promptTerminal(promptHandler.versionPrompt(versionlist, { is_stable: false }));
- expect(answer).toStrictEqual({
- newVersion: '1.2.1',
- is_stable: false,
- is_beta: true,
- is_hidden: true,
- is_deprecated: false,
- });
- });
- });
});
diff --git a/documentation/commands/categories.md b/documentation/commands/categories.md
deleted file mode 100644
index 237c23592..000000000
--- a/documentation/commands/categories.md
+++ /dev/null
@@ -1,92 +0,0 @@
-`rdme categories`
-=================
-
-List or create categories in your ReadMe developer hub.
-
-* [`rdme categories`](#rdme-categories)
-* [`rdme categories create TITLE`](#rdme-categories-create-title)
-
-## `rdme categories`
-
-Get all categories in your ReadMe project.
-
-```
-USAGE
- $ rdme categories --key [--version ]
-
-FLAGS
- --key= (required) An API key for your ReadMe project. Note that API authentication is required despite
- being omitted from the example usage. See our docs for more information:
- https://github.com/readmeio/rdme/tree/v9#authentication
- --version= ReadMe project version
-
-DESCRIPTION
- Get all categories in your ReadMe project.
-
-EXAMPLES
- Get all categories associated to your project version:
-
- $ rdme categories --version={project-version}
-
-FLAG DESCRIPTIONS
- --key=
-
- An API key for your ReadMe project. Note that API authentication is required despite being omitted from the example
- usage. See our docs for more information: https://github.com/readmeio/rdme/tree/v9#authentication
-
- ReadMe project API key
-
- --version= ReadMe project version
-
- If running command in a CI environment and this option is not passed, the main project version will be used. See our
- docs for more information: https://docs.readme.com/main/docs/versions
-```
-
-## `rdme categories create TITLE`
-
-Create a category with the specified title and guide in your ReadMe project.
-
-```
-USAGE
- $ rdme categories create TITLE --categoryType guide|reference --key [--preventDuplicates] [--version ]
-
-ARGUMENTS
- TITLE Title of the category
-
-FLAGS
- --categoryType=