From d72937432300eb37d0f2a91aa7794d7ee581c742 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Thu, 28 Jul 2022 15:31:13 -0400 Subject: [PATCH 1/4] fix: support files with .markdown extension --- __tests__/cmds/changelogs.test.js | 6 ++++++ __tests__/cmds/docs.test.js | 8 ++++++++ src/cmds/changelogs/single.js | 2 +- src/cmds/docs/single.js | 2 +- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/__tests__/cmds/changelogs.test.js b/__tests__/cmds/changelogs.test.js index f8ecc0cc1..459907894 100644 --- a/__tests__/cmds/changelogs.test.js +++ b/__tests__/cmds/changelogs.test.js @@ -367,6 +367,12 @@ describe('rdme changelogs:single', () => { ); }); + it('should support .markdown files but error if file path cannot be found', async () => { + await expect(changelogsSingle.run({ key, filePath: 'non-existent-file.markdown' })).rejects.toThrow( + 'ENOENT: no such file or directory' + ); + }); + describe('new changelogs', () => { it('should create new changelog', async () => { const slug = 'new-doc'; diff --git a/__tests__/cmds/docs.test.js b/__tests__/cmds/docs.test.js index 71514d3f7..4a57434b3 100644 --- a/__tests__/cmds/docs.test.js +++ b/__tests__/cmds/docs.test.js @@ -570,6 +570,14 @@ describe('rdme docs:single', () => { ); }); + it('should support .markdown files but error if file path cannot be found', async () => { + const versionMock = getApiNock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); + await expect(docsSingle.run({ key, version: '1.0.0', filePath: 'non-existent-file.markdown' })).rejects.toThrow( + 'ENOENT: no such file or directory' + ); + versionMock.done(); + }); + describe('new docs', () => { it('should create new doc', async () => { const slug = 'new-doc'; diff --git a/src/cmds/changelogs/single.js b/src/cmds/changelogs/single.js index 104a8e36e..eba0c5042 100644 --- a/src/cmds/changelogs/single.js +++ b/src/cmds/changelogs/single.js @@ -45,7 +45,7 @@ module.exports = class SingleChangelogCommand { return Promise.reject(new Error(`No file path provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); } - if (filePath.endsWith('.md') === false || !filePath.endsWith('.markdown') === false) { + if (!(filePath.endsWith('.md') || filePath.endsWith('.markdown'))) { return Promise.reject(new Error('The file path specified is not a markdown file.')); } diff --git a/src/cmds/docs/single.js b/src/cmds/docs/single.js index 6c12b6c4d..e10fbfa71 100644 --- a/src/cmds/docs/single.js +++ b/src/cmds/docs/single.js @@ -51,7 +51,7 @@ module.exports = class SingleDocCommand { return Promise.reject(new Error(`No file path provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); } - if (filePath.endsWith('.md') === false || !filePath.endsWith('.markdown') === false) { + if (!(filePath.endsWith('.md') || filePath.endsWith('.markdown'))) { return Promise.reject(new Error('The file path specified is not a markdown file.')); } From 21ba907ca774230366ff2fee6d872babe02137ef Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Thu, 28 Jul 2022 15:31:37 -0400 Subject: [PATCH 2/4] test: random cleanup fixing typo, removing unused version param, stricter error checks --- __tests__/cmds/changelogs.test.js | 12 ++++++------ __tests__/cmds/docs.test.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/__tests__/cmds/changelogs.test.js b/__tests__/cmds/changelogs.test.js index 459907894..9f86a5858 100644 --- a/__tests__/cmds/changelogs.test.js +++ b/__tests__/cmds/changelogs.test.js @@ -32,19 +32,19 @@ describe('rdme changelogs', () => { }); it('should error if no folder provided', () => { - return expect(changelogs.run({ key, version: '1.0.0' })).rejects.toThrow( + return expect(changelogs.run({ key })).rejects.toThrow( 'No folder provided. Usage `rdme changelogs [options]`.' ); }); - it('should error if the argument isnt a folder', () => { - return expect(changelogs.run({ key, version: '1.0.0', folder: 'not-a-folder' })).rejects.toThrow( + it('should error if the argument is not a folder', () => { + return expect(changelogs.run({ key, folder: 'not-a-folder' })).rejects.toThrow( "ENOENT: no such file or directory, scandir 'not-a-folder'" ); }); it('should error if the folder contains no markdown files', () => { - return expect(changelogs.run({ key, version: '1.0.0', folder: '.github/workflows' })).rejects.toThrow( + return expect(changelogs.run({ key, folder: '.github/workflows' })).rejects.toThrow( 'We were unable to locate Markdown files in .github/workflows.' ); }); @@ -356,13 +356,13 @@ describe('rdme changelogs:single', () => { }); it('should error if no file path provided', () => { - return expect(changelogsSingle.run({ key, version: '1.0.0' })).rejects.toThrow( + return expect(changelogsSingle.run({ key })).rejects.toThrow( 'No file path provided. Usage `rdme changelogs:single [options]`.' ); }); it('should error if the argument is not a markdown file', async () => { - await expect(changelogsSingle.run({ key, version: '1.0.0', filePath: 'not-a-markdown-file' })).rejects.toThrow( + await expect(changelogsSingle.run({ key, filePath: 'not-a-markdown-file' })).rejects.toThrow( 'The file path specified is not a markdown file.' ); }); diff --git a/__tests__/cmds/docs.test.js b/__tests__/cmds/docs.test.js index 4a57434b3..d5df4eb9a 100644 --- a/__tests__/cmds/docs.test.js +++ b/__tests__/cmds/docs.test.js @@ -49,7 +49,7 @@ describe('rdme docs', () => { ); }); - it('should error if the argument isnt a folder', async () => { + it('should error if the argument is not a folder', async () => { const versionMock = getApiNock().get(`/api/v1/version/${version}`).basicAuth({ user: key }).reply(200, { version }); await expect(docs.run({ key, version: '1.0.0', folder: 'not-a-folder' })).rejects.toThrow( From 7a7fb49662788d012c68e128617ab6c0c9467682 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Thu, 28 Jul 2022 15:40:55 -0400 Subject: [PATCH 3/4] refactor: DRY some docs logic --- src/cmds/changelogs/index.js | 16 +--------------- src/cmds/custompages/index.js | 16 +--------------- src/cmds/docs/index.js | 16 +--------------- src/lib/pushDoc.js | 18 ++++++++++++++++++ 4 files changed, 21 insertions(+), 45 deletions(-) diff --git a/src/cmds/changelogs/index.js b/src/cmds/changelogs/index.js index f0637b847..ca4917504 100644 --- a/src/cmds/changelogs/index.js +++ b/src/cmds/changelogs/index.js @@ -1,10 +1,9 @@ const chalk = require('chalk'); const config = require('config'); -const fs = require('fs'); -const path = require('path'); const { debug } = require('../../lib/logger'); const pushDoc = require('../../lib/pushDoc'); +const { readdirRecursive } = require('../../lib/pushDoc'); module.exports = class ChangelogsCommand { constructor() { @@ -48,19 +47,6 @@ module.exports = class ChangelogsCommand { return Promise.reject(new Error(`No folder provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); } - // Find the files to sync - const readdirRecursive = folderToSearch => { - const filesInFolder = fs.readdirSync(folderToSearch, { withFileTypes: true }); - const files = filesInFolder - .filter(fileHandle => fileHandle.isFile()) - .map(fileHandle => path.join(folderToSearch, fileHandle.name)); - const folders = filesInFolder.filter(fileHandle => fileHandle.isDirectory()); - const subFiles = [].concat( - ...folders.map(fileHandle => readdirRecursive(path.join(folderToSearch, fileHandle.name))) - ); - return [...files, ...subFiles]; - }; - // Strip out non-markdown files const files = readdirRecursive(folder).filter(file => file.endsWith('.md') || file.endsWith('.markdown')); diff --git a/src/cmds/custompages/index.js b/src/cmds/custompages/index.js index a62aa1e7e..d8a7a37c8 100644 --- a/src/cmds/custompages/index.js +++ b/src/cmds/custompages/index.js @@ -1,10 +1,9 @@ const chalk = require('chalk'); const config = require('config'); -const fs = require('fs'); -const path = require('path'); const { debug } = require('../../lib/logger'); const pushDoc = require('../../lib/pushDoc'); +const { readdirRecursive } = require('../../lib/pushDoc'); module.exports = class CustomPagesCommand { constructor() { @@ -48,19 +47,6 @@ module.exports = class CustomPagesCommand { return Promise.reject(new Error(`No folder provided. Usage \`${config.get('cli')} ${this.usage}\`.`)); } - // Find the files to sync - const readdirRecursive = folderToSearch => { - const filesInFolder = fs.readdirSync(folderToSearch, { withFileTypes: true }); - const files = filesInFolder - .filter(fileHandle => fileHandle.isFile()) - .map(fileHandle => path.join(folderToSearch, fileHandle.name)); - const folders = filesInFolder.filter(fileHandle => fileHandle.isDirectory()); - const subFiles = [].concat( - ...folders.map(fileHandle => readdirRecursive(path.join(folderToSearch, fileHandle.name))) - ); - return [...files, ...subFiles]; - }; - // Strip out non-markdown files const files = readdirRecursive(folder).filter( file => file.endsWith('.html') || file.endsWith('.md') || file.endsWith('.markdown') diff --git a/src/cmds/docs/index.js b/src/cmds/docs/index.js index 46710adc4..9a673635d 100644 --- a/src/cmds/docs/index.js +++ b/src/cmds/docs/index.js @@ -1,11 +1,10 @@ const chalk = require('chalk'); const config = require('config'); -const fs = require('fs'); -const path = require('path'); const { getProjectVersion } = require('../../lib/versionSelect'); const { debug } = require('../../lib/logger'); const pushDoc = require('../../lib/pushDoc'); +const { readdirRecursive } = require('../../lib/pushDoc'); module.exports = class DocsCommand { constructor() { @@ -61,19 +60,6 @@ module.exports = class DocsCommand { debug(`selectedVersion: ${selectedVersion}`); - // Find the files to sync - const readdirRecursive = folderToSearch => { - const filesInFolder = fs.readdirSync(folderToSearch, { withFileTypes: true }); - const files = filesInFolder - .filter(fileHandle => fileHandle.isFile()) - .map(fileHandle => path.join(folderToSearch, fileHandle.name)); - const folders = filesInFolder.filter(fileHandle => fileHandle.isDirectory()); - const subFiles = [].concat( - ...folders.map(fileHandle => readdirRecursive(path.join(folderToSearch, fileHandle.name))) - ); - return [...files, ...subFiles]; - }; - // Strip out non-markdown files const files = readdirRecursive(folder).filter(file => file.endsWith('.md') || file.endsWith('.markdown')); diff --git a/src/lib/pushDoc.js b/src/lib/pushDoc.js index 0d507580e..5c973a444 100644 --- a/src/lib/pushDoc.js +++ b/src/lib/pushDoc.js @@ -117,3 +117,21 @@ module.exports = async function pushDoc(key, selectedVersion, dryRun, filepath, throw err; }); }; + +/** + * Recursively grabs all files within a given directory + * (including subdirectories) + * @param {String} folderToSearch path to directory + * @returns {String[]} array of files + */ +module.exports.readdirRecursive = function readdirRecursive(folderToSearch) { + const filesInFolder = fs.readdirSync(folderToSearch, { withFileTypes: true }); + const files = filesInFolder + .filter(fileHandle => fileHandle.isFile()) + .map(fileHandle => path.join(folderToSearch, fileHandle.name)); + const folders = filesInFolder.filter(fileHandle => fileHandle.isDirectory()); + const subFiles = [].concat( + ...folders.map(fileHandle => readdirRecursive(path.join(folderToSearch, fileHandle.name))) + ); + return [...files, ...subFiles]; +}; From d600ef45802c88631d8160dbed76980e8f3ac3c0 Mon Sep 17 00:00:00 2001 From: Ryan Park Date: Thu, 28 Jul 2022 13:51:39 -0700 Subject: [PATCH 4/4] feat: add retag-release workflow to add a vX.Y.Z tag for our GitHub Action (#545) * feat: add retag-release workflow to add a vX.Y.Z tag for our GitHub Action * Update .github/workflows/retag-release.yaml Co-authored-by: Kanad Gupta * refactor: move code out of YAML and into bin/ script * fix: lint fixes Co-authored-by: Kanad Gupta --- .github/workflows/retag-release.yaml | 20 +++++++++++++ bin/retag-release.js | 42 ++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 .github/workflows/retag-release.yaml create mode 100644 bin/retag-release.js diff --git a/.github/workflows/retag-release.yaml b/.github/workflows/retag-release.yaml new file mode 100644 index 000000000..5f4d26c69 --- /dev/null +++ b/.github/workflows/retag-release.yaml @@ -0,0 +1,20 @@ +# This script adds a "vX.Y.Z" tag to every new release. +# +# Our releases are tagged like "1.2.3" but we want people to be able to write +# GitHub Action workflows to say "uses: readmeio/readme@v1.2.3" because that's +# the usual GitHub convention. + +name: retag-release + +on: + release: + types: [created] + +jobs: + retag-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/github-script@v6 + with: + script: require('./bin/retag-release.js')(github, context); diff --git a/bin/retag-release.js b/bin/retag-release.js new file mode 100644 index 000000000..113e6098d --- /dev/null +++ b/bin/retag-release.js @@ -0,0 +1,42 @@ +/* eslint-disable no-console */ +module.exports = async (github, context) => { + const { owner, repo } = context.repo; + const oldTag = context.payload.release.tag_name; + if (!oldTag.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)) { + console.log('Not retagging this release: This script will only retag releases that use'); + console.log(`semantic versioning, like "1.2.3", but this release's tag is "${oldTag}".`); + return {}; + } + const newTag = `v${oldTag}`; + console.log(`Retagging release "${oldTag}" as "${newTag}".`); + + const oldRef = await github.rest.git.getRef({ + owner, + repo, + ref: `tags/${oldTag}`, + }); + if (oldRef.status < 200 || oldRef.status >= 400) { + console.log(oldRef); + throw new Error(`GitHub API call returned HTTP status code ${oldRef.status}`); + } + const sha = oldRef.data.object.sha; + console.log(`Found tag "${oldTag}"; commit hash is ${sha}`); + + console.log(`Creating tag "${newTag}" pointing to commit hash ${sha}...`); + const newRef = await github.rest.git.createRef({ + owner, + repo, + ref: `refs/tags/${newTag}`, + sha, + }); + if (newRef.status < 200 || newRef.status >= 400) { + console.log(newRef); + throw new Error(`GitHub API call returned HTTP status code ${newRef.status}`); + } + console.log('Successfully retagged this release.'); + return { + original_tag: oldTag, + new_tag: newTag, + sha, + }; +};