Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(docs/upload): add safeguard if projects have bidi enabled #1175

Open
wants to merge 7 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions __tests__/commands/docs/__snapshots__/upload.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`rdme docs upload > given that ReadMe project has bidirection sync set up > should should error if validation is not skipped 1`] = `
{
"error": [Error: Bi-directional syncing is enabled for this project. Uploading these docs will overwrite what's currently synced from Git. To proceed with uploading via \`rdme\`, please use the \`--skip-validation\` flag.],
"stderr": "",
"stdout": "",
}
`;

exports[`rdme docs upload > given that ReadMe project has bidirection sync set up > should upload if validation is skipped 1`] = `
{
"result": {
"created": [
{
"filePath": "__tests__/__fixtures__/docs/new-docs/new-doc.md",
"response": {},
"result": "created",
"slug": "new-doc",
},
],
"failed": [],
"skipped": [],
"updated": [],
},
"stderr": " › Warning: Skipping pre-upload validation of the Markdown file(s). This is
› not recommended.
- 🚀 Uploading files to ReadMe...
✔ 🚀 Uploading files to ReadMe... done!
",
"stdout": "🌱 Successfully created 1 page(s) in ReadMe:
- new-doc (__tests__/__fixtures__/docs/new-docs/new-doc.md)
",
}
`;

exports[`rdme docs upload > given that the file path is a directory > given that the directory contains parent/child docs > should upload parents before children 1`] = `
{
"result": {
Expand Down
72 changes: 72 additions & 0 deletions __tests__/commands/docs/upload.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ describe('rdme docs upload', () => {
categories: {},
parentPages: {},
});
getAPIv2Mock({ authorization }).get('/projects/me').reply(200, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these tests are great, ty! could you also add a test case for if this initial /projects/me request fails? i'll DM you an example error response that you can pull from shortly

data: {},
});
vi.spyOn(fs, 'writeFileSync').mockImplementation(() => {});
});

Expand Down Expand Up @@ -195,6 +198,10 @@ describe('rdme docs upload', () => {
})
.reply(201, {});

const projectsMeMock = getAPIv2Mock({ authorization }).get('/projects/me').reply(200, {
data: {},
});

prompts.inject([true]);

const result = await run(['__tests__/__fixtures__/docs/mixed-docs/legacy-category.md', '--key', key]);
Expand All @@ -208,6 +215,7 @@ describe('rdme docs upload', () => {

mappingsMock.done();
mock.done();
projectsMeMock.done();
});

it('should exit if the user declines to fix the issues', async () => {
Expand Down Expand Up @@ -289,20 +297,29 @@ describe('rdme docs upload', () => {
})
.reply(201, {});

const projectsMeMock = getAPIv2MockForGHA({ authorization }).get('/projects/me').reply(200, {
data: {},
});

const result = await run(['__tests__/__fixtures__/docs/new-docs/new-doc.md', '--key', key]);

expect(result).toMatchSnapshot();
expect(fs.writeFileSync).not.toHaveBeenCalled();

headMock.done();
postMock.done();
projectsMeMock.done();
});

it('should error out if the file has validation errors', async () => {
const projectsMeMock = getAPIv2MockForGHA({ authorization }).get('/projects/me').reply(200, {
data: {},
});
const result = await run(['__tests__/__fixtures__/docs/mixed-docs/legacy-category.md', '--key', key]);

expect(result).toMatchSnapshot();
expect(fs.writeFileSync).not.toHaveBeenCalled();
projectsMeMock.done();
});
});

Expand Down Expand Up @@ -508,4 +525,59 @@ describe('rdme docs upload', () => {
mock.done();
});
});

describe('given that ReadMe project has bidirection sync set up', () => {
it('should should error if validation is not skipped', async () => {
nock.cleanAll();

const mock = getAPIv2Mock({ authorization })
.get('/projects/me')
.reply(200, {
data: { git: { connection: { name: 'some-repo' } } },
});

const result = await run(['__tests__/__fixtures__/docs/new-docs/new-doc.md', '--key', key]);

expect(result).toMatchSnapshot();
expect(fs.writeFileSync).not.toHaveBeenCalled();

mock.done();
});

it('should upload if validation is skipped', async () => {
nock.cleanAll();

const mock = getAPIv2Mock({ authorization })
.head('/versions/1.2.3/guides/new-doc')
.reply(404)
.post('/versions/1.2.3/guides', {
category: { uri: '/versions/1.2.3/categories/guides/category-slug' },
slug: 'new-doc',
title: 'This is the document title',
content: { body: '\nBody\n' },
})
.reply(201, {});

const projectsMeMock = getAPIv2Mock({ authorization })
.get('/projects/me')
.reply(200, {
data: { git: { connection: { name: 'some-repo' } } },
});

const result = await run([
'__tests__/__fixtures__/docs/new-docs/new-doc.md',
'--key',
key,
'--version',
'1.2.3',
'--skip-validation',
]);

expect(result).toMatchSnapshot();
expect(fs.writeFileSync).not.toHaveBeenCalled();

mock.done();
projectsMeMock.done();
});
});
});
21 changes: 19 additions & 2 deletions src/lib/syncPagePath.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { PageMetadata } from './readPage.js';
import type { GuidesRequestRepresentation } from './types.js';
import type { GuidesRequestRepresentation, ProjectRepresentation } from './types.js';
import type DocsUploadCommand from '../commands/docs/upload.js';

import fs from 'node:fs/promises';
Expand Down Expand Up @@ -197,7 +197,7 @@ function sortFiles(files: PageMetadata<PageRepresentation>[]): PageMetadata<Page
*/
export default async function syncPagePath(this: CommandsThatSyncMarkdown) {
const { path: pathInput }: { path: string } = this.args;
const { 'dry-run': dryRun, 'skip-validation': skipValidation } = this.flags;
const { key, 'dry-run': dryRun, 'skip-validation': skipValidation } = this.flags;

const allowedFileExtensions = ['.markdown', '.md'];

Expand All @@ -208,6 +208,23 @@ export default async function syncPagePath(this: CommandsThatSyncMarkdown) {
throw err;
});

// check whether or not the project has bidirection syncing enabled
// if it is, validations must be skipped to prevent frontmatter from being overwritten
const headers = new Headers({ authorization: `Bearer ${key}` });
const projectMetadata: ProjectRepresentation = await this.readmeAPIFetch('/projects/me', {
method: 'GET',
headers,
}).then(res => {
return this.handleAPIRes(res);
});

const biDiConnection = projectMetadata.data.git?.connection;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe just to be extra cautious:

Suggested change
const biDiConnection = projectMetadata.data.git?.connection;
const biDiConnection = projectMetadata?.data?.git?.connection;

if (biDiConnection && !skipValidation) {
throw new Error(
"Bi-directional syncing is enabled for this project. Uploading these docs will overwrite what's currently synced from Git. To proceed with uploading via `rdme`, please use the `--skip-validation` flag.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Bi-directional syncing is enabled for this project. Uploading these docs will overwrite what's currently synced from Git. To proceed with uploading via `rdme`, please use the `--skip-validation` flag.",
"Bi-directional syncing is enabled for this project. Uploading these docs will overwrite what's currently synced from Git. To proceed with the upload, re-run this command with the `--skip-validation` flag.",

);
}

if (skipValidation) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thoughts on making it so this warning is only shown if bidi is not enabled? or maybe we have a separate warning for those users?

Suggested change
if (skipValidation) {
if (skipValidation && !bidiConnection) {

this.warn('Skipping pre-upload validation of the Markdown file(s). This is not recommended.');
}
Expand Down
Loading
Loading