Add a script to generate unreleased changelog (#10988)
* Add script to generate changelog * Fix by prettier * Use CHANGELOG_CATEGORIES from utils * Fix filename * Fix typo * Add comments * Replace codeblock * Fix typo * Avoid to use top-level await * Use enquirer * Address review * Use meriyah for mjs * Add comment * Update usase comment * Update CONTRIBUTING.md
This commit is contained in:
1 parent
c5e33a3094
commit
83e5ebe891
6 files changed
+221
-22
No files matched your search
+1
-1
@@ -66,7 +66,7 @@ To debug Prettier locally, you can either debug it in Node (recommended) or the
|
||||
|
||||
The project uses ESLint for linting and Prettier for formatting. If your editor isn't set up to work with them, you can lint and format all files from the command line using `yarn fix`.
|
||||
|
||||
After opening a PR, describe your changes in a file in the `changelog_unreleased` directory following the template [`changelog_unreleased/TEMPLATE.md`](changelog_unreleased/TEMPLATE.md) and commit this file to your PR.
|
||||
After opening a PR, describe your changes in a file in the `changelog_unreleased` directory following the template [`changelog_unreleased/TEMPLATE.md`](changelog_unreleased/TEMPLATE.md) and commit this file to your PR. You can use `./scripts/generate-changelog.mjs` to create changelog file. Please see comments of the script file for usage.
|
||||
|
||||
Take a look at [`commands.md`](commands.md) and, if you know Haskell, check out [Wadler's paper](http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf) to understand how Prettier works.
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
"core-js": "3.16.0",
|
||||
"cross-env": "7.0.3",
|
||||
"cspell": "5.6.6",
|
||||
"enquirer": "2.3.6",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-formatter-friendly": "7.0.0",
|
||||
@@ -121,6 +122,7 @@
|
||||
"jest-snapshot-serializer-raw": "1.2.0",
|
||||
"jest-watch-typeahead": "0.6.4",
|
||||
"node-actionlint": "1.1.0",
|
||||
"node-fetch": "2.6.1",
|
||||
"npm-run-all": "4.1.5",
|
||||
"path-browserify": "1.0.1",
|
||||
"prettier": "2.3.2",
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* When you run the script, enter the number and category of the Pull Request at the prompt.
|
||||
* Get the PR title and author name via the GitHub API and create a file in ./changelog_unreleased
|
||||
*
|
||||
* $ node ./scripts/generate-changelog.mjs
|
||||
* ✔ Input your Pull Request number: · 10961
|
||||
* ✔ Input category of your Pull Request: · typescript
|
||||
*/
|
||||
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import fetch from "node-fetch";
|
||||
import createEsmUtils from "esm-utils";
|
||||
import enquirer from "enquirer";
|
||||
import { CHANGELOG_CATEGORIES } from "./utils/changelog-categories.mjs";
|
||||
|
||||
const { __dirname } = createEsmUtils(import.meta);
|
||||
|
||||
(async () => {
|
||||
const prNumberPrompt = new enquirer.NumberPrompt({
|
||||
message: "Input your Pull Request number:",
|
||||
});
|
||||
const prNumber = await prNumberPrompt.run();
|
||||
|
||||
const categoryPrompt = new enquirer.AutoComplete({
|
||||
message: "Input category of your Pull Request:",
|
||||
limit: CHANGELOG_CATEGORIES.length,
|
||||
// The array passed to `choices` will be broken, so copy it.
|
||||
choices: [...CHANGELOG_CATEGORIES],
|
||||
});
|
||||
const category = (await categoryPrompt.run()).trim();
|
||||
|
||||
if (!prNumber || !category) {
|
||||
throw new Error("Two args are required.");
|
||||
}
|
||||
assertCategory(category);
|
||||
|
||||
const { title, user } = await getPr(prNumber);
|
||||
|
||||
const newChangelog = await createChangelog(title, user, prNumber, category);
|
||||
|
||||
await addNewChangelog(prNumber, category, newChangelog);
|
||||
|
||||
console.log("Done");
|
||||
})();
|
||||
|
||||
/**
|
||||
* @param {number} prNumber
|
||||
* @returns {Promise<{ title: string; user: string }>}
|
||||
*/
|
||||
async function getPr(prNumber) {
|
||||
// https://docs.github.com/en/rest/reference/pulls#get-a-pull-request
|
||||
const url = `https://api.github.com/repos/prettier/prettier/pulls/${prNumber}`;
|
||||
const response = await fetch(url, {
|
||||
Headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
throw new Error(`Pull Request #${prNumber} not found.`);
|
||||
}
|
||||
throw new Error(response);
|
||||
}
|
||||
const { title, user } = await response.json();
|
||||
return {
|
||||
title,
|
||||
user: user.login,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} prNumber
|
||||
* @param {string} category
|
||||
* @param {string} newChangelog
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function addNewChangelog(prNumber, category, newChangelog) {
|
||||
const newChangelogPath = path.resolve(
|
||||
__dirname,
|
||||
`../changelog_unreleased/${category}/${prNumber}.md`
|
||||
);
|
||||
await fs.writeFile(newChangelogPath, newChangelog);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} title
|
||||
* @param {string} user
|
||||
* @param {number} prNumber
|
||||
* @param {string} string
|
||||
* @returns {string}
|
||||
*/
|
||||
async function createChangelog(title, user, prNumber, category) {
|
||||
const changelogTemplatePath = path.resolve(
|
||||
__dirname,
|
||||
"../changelog_unreleased/TEMPLATE.md"
|
||||
);
|
||||
const changelogTemplate = await fs.readFile(changelogTemplatePath, "utf-8");
|
||||
|
||||
const titlePart = "Title";
|
||||
const prNumberPart = "#XXXX";
|
||||
const userPart = "@user";
|
||||
const codeBlockPart = "```jsx\n";
|
||||
const inputCommentPart = "// Input\n";
|
||||
const stableCommentPart = "// Prettier stable\n";
|
||||
const mainCommentPart = "// Prettier main\n";
|
||||
|
||||
const syntax = getSyntaxFromCategory(category);
|
||||
|
||||
return changelogTemplate
|
||||
.replace(titlePart, title)
|
||||
.replace(prNumberPart, `#${prNumber}`)
|
||||
.replace(userPart, `@${user}`)
|
||||
.replace(codeBlockPart, `\`\`\`${syntax}\n`)
|
||||
.replace(inputCommentPart, getCommentForSyntax(syntax, "Input") + "\n")
|
||||
.replace(
|
||||
stableCommentPart,
|
||||
getCommentForSyntax(syntax, "Prettier stable") + "\n"
|
||||
)
|
||||
.replace(
|
||||
mainCommentPart,
|
||||
getCommentForSyntax(syntax, "Prettier main") + "\n"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} category
|
||||
* @returns {string}
|
||||
*/
|
||||
function getSyntaxFromCategory(category) {
|
||||
switch (category) {
|
||||
case "angular":
|
||||
case "html":
|
||||
case "lwc":
|
||||
return "html";
|
||||
case "cli":
|
||||
return "sh";
|
||||
case "graphql":
|
||||
return "gql";
|
||||
case "handlebars":
|
||||
return "hbs";
|
||||
case "json":
|
||||
return "jsonc";
|
||||
case "markdown":
|
||||
return "md";
|
||||
case "mdx":
|
||||
return "mdx";
|
||||
case "flow":
|
||||
case "javascript":
|
||||
case "api":
|
||||
return "jsx";
|
||||
case "typescript":
|
||||
return "tsx";
|
||||
default:
|
||||
return category;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} syntax
|
||||
* @param {string} comment
|
||||
* @returns {string}
|
||||
*/
|
||||
function getCommentForSyntax(syntax, comment) {
|
||||
switch (syntax) {
|
||||
case "md":
|
||||
case "mdx":
|
||||
case "html":
|
||||
return `<!-- ${comment} -->`;
|
||||
case "sh":
|
||||
case "gql":
|
||||
return `# ${comment}`;
|
||||
case "hbs":
|
||||
return `{{! ${comment} }}`;
|
||||
default:
|
||||
return `// ${comment}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown}
|
||||
* @returns {void}
|
||||
*/
|
||||
function assertCategory(category) {
|
||||
if (!CHANGELOG_CATEGORIES.includes(category)) {
|
||||
throw new Error(`${category} is invalid category`);
|
||||
}
|
||||
}
|
||||
@@ -4,32 +4,13 @@ import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import { outdent } from "outdent";
|
||||
import createEsmUtils from "esm-utils";
|
||||
import { CHANGELOG_CATEGORIES } from "./utils/changelog-categories.mjs";
|
||||
|
||||
const { __dirname } = createEsmUtils(import.meta);
|
||||
const CHANGELOG_DIR = "changelog_unreleased";
|
||||
const TEMPLATE_FILE = "TEMPLATE.md";
|
||||
const BLOG_POST_INTRO_TEMPLATE_FILE = "BLOG_POST_INTRO_TEMPLATE.md";
|
||||
const BLOG_POST_INTRO_FILE = "blog-post-intro.md";
|
||||
const CHANGELOG_CATEGORIES = [
|
||||
"angular",
|
||||
"api",
|
||||
"cli",
|
||||
"css",
|
||||
"flow",
|
||||
"graphql",
|
||||
"handlebars",
|
||||
"html",
|
||||
"javascript",
|
||||
"json",
|
||||
"less",
|
||||
"lwc",
|
||||
"markdown",
|
||||
"mdx",
|
||||
"scss",
|
||||
"typescript",
|
||||
"vue",
|
||||
"yaml",
|
||||
];
|
||||
const CHANGELOG_ROOT = path.join(__dirname, `../${CHANGELOG_DIR}`);
|
||||
const showErrorMessage = (message) => {
|
||||
console.error(message);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
export const CHANGELOG_CATEGORIES = [
|
||||
"angular",
|
||||
"api",
|
||||
"cli",
|
||||
"css",
|
||||
"flow",
|
||||
"graphql",
|
||||
"handlebars",
|
||||
"html",
|
||||
"javascript",
|
||||
"json",
|
||||
"less",
|
||||
"lwc",
|
||||
"markdown",
|
||||
"mdx",
|
||||
"scss",
|
||||
"typescript",
|
||||
"vue",
|
||||
"yaml",
|
||||
];
|
||||
@@ -2865,7 +2865,7 @@ enhanced-resolve@^5.8.0:
|
||||
graceful-fs "^4.2.4"
|
||||
tapable "^2.2.0"
|
||||
|
||||
enquirer@^2.3.5:
|
||||
enquirer@2.3.6, enquirer@^2.3.5:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
|
||||
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
|
||||
@@ -4969,6 +4969,11 @@ node-actionlint@1.1.0:
|
||||
chalk "^4.1.1"
|
||||
fast-glob "^3.2.7"
|
||||
|
||||
node-fetch@2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
node-int64@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||
|
||||
Reference in new issue
Block a user