diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml
new file mode 100644
index 000000000..b90db4145
--- /dev/null
+++ b/.github/workflows/bump-version.yml
@@ -0,0 +1,100 @@
+name: Bump BitBurner Version
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Version (format: x.y.z)'
+ required: true
+ versionNumber:
+ description: 'Version Number (for saves migration)'
+ required: true
+ changelog:
+ description: 'Changelog (url that points to RAW markdown)'
+ default: ''
+ buildApp:
+ description: 'Include Application Build'
+ type: boolean
+ default: 'true'
+ required: true
+ buildDoc:
+ description: 'Include Documentation Build'
+ type: boolean
+ default: 'true'
+ required: true
+ prepareRelease:
+ description: 'Prepare Draft Release'
+ type: boolean
+ default: 'true'
+ required: true
+
+jobs:
+ bumpVersion:
+ name: Bump Version
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ pull-requests: write
+ steps:
+ - name: Install pandoc dependency
+ run: sudo apt-get install -y pandoc
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Use Node.js 16.13.1
+ uses: actions/setup-node@v2
+ with:
+ node-version: 16.13.1
+ cache: 'npm'
+ - name: Install NPM dependencies for version updater
+ working-directory: ./tools/bump-version
+ run: npm ci
+ - name: Bump version & update changelogs
+ working-directory: ./tools/bump-version
+ run: |
+ curl ${{ github.event.inputs.changelog }} > changes.md
+ node index.js --version=${{ github.event.inputs.version }} --versionNumber=${{ github.event.inputs.versionNumber }} < changes.md
+ - name: Install NPM dependencies for app
+ if: ${{ github.event.inputs.buildApp == 'true' || github.event.inputs.buildDoc == 'true' }}
+ run: npm ci
+ - name: Build Production App
+ if: ${{ github.event.inputs.buildApp == 'true' }}
+ run: npm run build
+ - name: Build Documentation
+ if: ${{ github.event.inputs.buildDoc == 'true' }}
+ run: npm run doc
+ - name: Commit Files
+ run: |
+ git config --global user.name "GitHub"
+ git config --global user.email "noreply@github.com"
+ git checkout -b bump/v${{ github.event.inputs.version }}
+ git add -A
+ echo "Bump version to v${{ github.event.inputs.version }}" > commitmessage.txt
+ echo "" >> commitmessage.txt
+ cat ./tools/bump-version/changes.md >> commitmessage.txt
+ git commit -F commitmessage.txt
+ git push -u origin bump/v${{ github.event.inputs.version }}
+ - name: Create Pull Request
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ gh pr create \
+ --base "${{ github.ref_name }}" \
+ --head "bump/v${{ github.event.inputs.version }}" \
+ --title "Bump version to v${{ github.event.inputs.version }}" \
+ --body-file ./tools/bump-version/changes.md
+ - name: Prepare release
+ if: ${{ github.event.inputs.prepareRelease == 'true' }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ RELEASE_TITLE="$(head -n 1 ./tools/bump-version/changes.md | sed 's/## //')"
+ RELEASE_TITLE="${RELEASE_TITLE:-v${{ github.event.inputs.version }}}"
+ gh release create \
+ v${{ github.event.inputs.version }} \
+ --target dev \
+ --title "$RELEASE_TITLE" \
+ --notes-file ./tools/bump-version/changes.md \
+ --generate-notes \
+ --draft
diff --git a/.github/workflows/fetch-changes.yml b/.github/workflows/fetch-changes.yml
new file mode 100644
index 000000000..594e8a13b
--- /dev/null
+++ b/.github/workflows/fetch-changes.yml
@@ -0,0 +1,44 @@
+name: Fetch Merged Changes
+on:
+ workflow_dispatch:
+ inputs:
+ fromCommit:
+ description: 'From Commit SHA (full-length)'
+ required: true
+ toCommit:
+ description: 'To Commit SHA (full-length, if omitted will use latest)'
+
+jobs:
+ fetchChangelog:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Use Node v16.13.1
+ uses: actions/setup-node@v2
+ with:
+ node-version: 16.13.1
+ cache: 'npm'
+ - name: Install NPM dependencies
+ working-directory: ./tools/fetch-changelog
+ run: npm ci
+ - name: Fetch Changes from GitHub API
+ working-directory: ./tools/fetch-changelog
+ env:
+ GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ node index.js \
+ --from=${{ github.event.inputs.fromCommit }} \
+ --to=${{ github.event.inputs.toCommit }} > changes.md
+ echo
+ echo "============================================================"
+ echo
+ cat changes.md
+ echo
+ echo "============================================================"
+ echo
+ echo "You may want to go to https://gist.github.com/ to upload the final changelog"
+ echo "The next step will require an url because we can't easily pass multiline strings to actions"
+ - uses: actions/upload-artifact@v2
+ with:
+ name: bitburner_changelog___DRAFT.md
+ path: ./tools/fetch-changelog/changes.md
diff --git a/src/SaveObject.tsx b/src/SaveObject.tsx
index d9cae146a..eaa997269 100755
--- a/src/SaveObject.tsx
+++ b/src/SaveObject.tsx
@@ -22,6 +22,7 @@ import { v1APIBreak } from "./utils/v1APIBreak";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import { PlayerOwnedAugmentation } from "./Augmentation/PlayerOwnedAugmentation";
import { LocationName } from "./Locations/data/LocationNames";
+import { SxProps } from "@mui/system";
/* SaveObject.js
* Defines the object used to save/load games
@@ -371,6 +372,18 @@ function createScamUpdateText(): void {
}
}
+const resets: SxProps = {
+ "& h1, & h2, & h3, & h4, & p, & a, & ul": {
+ margin: 0,
+ color: Settings.theme.primary,
+ whiteSpace: "initial",
+ },
+ "& ul": {
+ paddingLeft: "1.5em",
+ lineHeight: 1.5,
+ },
+};
+
function createNewUpdateText(): void {
setTimeout(
() =>
@@ -379,6 +392,7 @@ function createNewUpdateText(): void {
"Please report any bugs/issues through the github repository " +
"or the Bitburner subreddit (reddit.com/r/bitburner).
" +
CONSTANTS.LatestUpdate,
+ resets,
),
1000,
);
@@ -391,6 +405,7 @@ function createBetaUpdateText(): void {
"Please report any bugs/issues through the github repository (https://github.com/danielyxie/bitburner/issues) " +
"or the Bitburner subreddit (reddit.com/r/bitburner).
" +
CONSTANTS.LatestUpdate,
+ resets,
);
}
diff --git a/src/ui/React/DialogBox.tsx b/src/ui/React/DialogBox.tsx
index cc96d956f..9ae8035f6 100644
--- a/src/ui/React/DialogBox.tsx
+++ b/src/ui/React/DialogBox.tsx
@@ -1,11 +1,13 @@
import { AlertEvents } from "./AlertManager";
import React from "react";
+import { SxProps } from "@mui/system";
+import { Typography } from "@mui/material";
-export function dialogBoxCreate(txt: string | JSX.Element): void {
+export function dialogBoxCreate(txt: string | JSX.Element, styles?: SxProps): void {
if (typeof txt !== "string") {
AlertEvents.emit(txt);
} else {
- AlertEvents.emit();
+ AlertEvents.emit();
}
}
diff --git a/tools/README.md b/tools/README.md
index e9cb7e57b..b7fa5e55f 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -21,12 +21,28 @@ Used to synchronize the achievements info in steamworks to the game's data.json
node fetch-steam-achievements-data.js DEVKEYDEVKEYDEVKEYDEVKEY
```
-## Changelog script
+## Fetch Changelog
-Used to generate a basic git commit log (in markdown) between commit A & commit B
+Used to generate a changelog of merged pull requests & commits between A & B.
+The key is a personnal access token, from https://github.com/settings/tokens.
+It requires the "gist" scope as the result is pushed to a secret gist.
**Usage**
```sh
-# Will default to HEAD if second is not specified.
-./tools/changelog.sh 9a0062b 05cbc25
+cd ./tools/fetch-changelog
+npm install
+export GITHUB_API_TOKEN=tokenhere # this could go into your .bashrc or .profile etc.
+node index.js --from=31ebdbb139981a604bd0e8fc1e364916762e11b9 > ../bump-version/changes.md
+```
+
+## Bump Version
+
+Used to update the game's various version identifier.
+Requires pandoc installed to convert .md to .rst
+
+**Usage**
+```sh
+cd ./tools/bump-version
+npm install
+node index.js --version=1.10.3 --versionNumber=10 < changes.md
```
diff --git a/tools/bump-version/.gitignore b/tools/bump-version/.gitignore
new file mode 100644
index 000000000..4764e2f2e
--- /dev/null
+++ b/tools/bump-version/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+*.md
diff --git a/tools/bump-version/index.js b/tools/bump-version/index.js
new file mode 100644
index 000000000..8464bc189
--- /dev/null
+++ b/tools/bump-version/index.js
@@ -0,0 +1,118 @@
+// import { Octokit } from "@octokit/rest";
+import commandLineArgs from "command-line-args";
+
+import fs from 'fs/promises';
+import { readFileSync } from 'fs';
+import path from 'path';
+import { fileURLToPath } from 'url';
+import pandoc from 'node-pandoc';
+
+// https://github.com/75lb/command-line-args
+const optionDefinitions = [
+ { name: 'version', alias: 'v', type: String, required: true },
+ { name: 'versionNumber', alias: 'n', type: Number },
+ { name: 'versionDescription', alias: 'd', type: String },
+ { name: 'changelog', alias: 'l', type: String },
+];
+
+const cliArgs = commandLineArgs(optionDefinitions);
+
+const appPaths = {};
+appPaths.root = path.join(path.dirname(fileURLToPath(import.meta.url)), "../..");
+appPaths.mainPackage = path.join(appPaths.root, "./package.json");
+appPaths.electronPackage = path.join(appPaths.root, "./electron/package.json");
+appPaths.constants = path.join(appPaths.root, "./src/Constants.ts");
+appPaths.sphinxConf = path.join(appPaths.root, "./doc/source/conf.py");
+appPaths.sphinxChangelog = path.join(appPaths.root, "./doc/source/changelog.rst");
+
+async function main(version, versionNumber, changelog) {
+ console.log(`Updating app files to match v${version}`);
+
+ const [ major, minor ]= version.split('.');
+ const shortVersion = `${major}.${minor}`;
+ const modifiedMainPackage = (await fs.readFile(appPaths.mainPackage, 'utf8')).
+ replace(/(^\s*"version":\s)"(.*)",$/m, `$1"${version}",`);
+ await fs.writeFile(appPaths.mainPackage, modifiedMainPackage);
+ console.log(`Modified ${appPaths.mainPackage}`);
+
+ const modifiedElectronPackage = (await fs.readFile(appPaths.electronPackage, 'utf8')).
+ replace(/(^\s*"version":\s)"(.*)",$/m, `$1"${version}",`);
+ await fs.writeFile(appPaths.electronPackage, modifiedElectronPackage);
+ console.log(`Modified ${appPaths.electronPackage}`);
+
+ let modifiedConstants = (await fs.readFile(appPaths.constants, 'utf8')).
+ replace(/(^\s*?VersionString:\s)"(.*)",/m, `$1"${version}",`);
+ modifiedConstants = modifiedConstants.
+ replace(/(^\s*?VersionNumber:\s)(.*),/m, `$1${versionNumber},`);
+
+ if (changelog.trim() !== '') {
+ let htmlChangelog = '';
+ try {
+ htmlChangelog = await transform(changelog, 'html');
+ console.log('Converted markdown changelog to html')
+ } catch (error) {
+ console.error(error);
+ }
+
+ const paddedChangelog = htmlChangelog.split('\n').
+ map((line) => (line.trim() !== '' ? ' ' + line : '')).
+ join('\n').replaceAll('`', '\\`');
+
+ modifiedConstants = modifiedConstants.
+ replace(/(^\s*?LatestUpdate:\s`\n)(.*)`,$/ms, `$1${paddedChangelog}\n` + "`,");
+ }
+ await fs.writeFile(appPaths.constants, modifiedConstants);
+ console.log(`Modified ${appPaths.constants}`);
+
+ let modifiedSphinxConfig = (await fs.readFile(appPaths.sphinxConf, 'utf8')).
+ replace(/(^version = ')(.*)'$/m, `$1${shortVersion}'`);
+ modifiedSphinxConfig = modifiedSphinxConfig.
+ replace(/(^release = ')(.*)'$/m, `$1${version}'`);
+ await fs.writeFile(appPaths.sphinxConf, modifiedSphinxConfig);
+ console.log(`Modified ${appPaths.sphinxConf}`);
+
+ if (changelog.trim() !== '') {
+ let modifiedSphinxChangelog = await fs.readFile(appPaths.sphinxChangelog, 'utf8');
+ const lines = modifiedSphinxChangelog.split('\n');
+ let rstChangelog = '';
+ try {
+ rstChangelog = await transform(changelog, 'rst');
+ console.log('Converted markdown changelog to rst')
+ } catch (error) {
+ console.error(error);
+ }
+
+ lines.splice(5, 0, rstChangelog);
+ modifiedSphinxChangelog = lines.join('\n');
+ await fs.writeFile(appPaths.sphinxChangelog, modifiedSphinxChangelog);
+ console.log(`Modified ${appPaths.sphinxChangelog}`);
+ }
+}
+
+async function transform(markdown, format) {
+ return new Promise((resolve, reject) => {
+ const args = `-f markdown -t ${format}`;
+ pandoc(markdown, args, (error, rst) => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(rst);
+ }
+ });
+ });
+}
+
+async function getChangelog() {
+ // Read from stdin
+ // https://stackoverflow.com/a/56012724
+ try {
+ return readFileSync(0, 'utf-8').replace('\r\n', '\n');
+ } catch (error) {
+ return '';
+ }
+}
+
+getChangelog().then((changes) => {
+ main(cliArgs.version, cliArgs.versionNumber, changes).then(() => console.log('Done'));
+})
+
diff --git a/tools/bump-version/package-lock.json b/tools/bump-version/package-lock.json
new file mode 100644
index 000000000..d9632a14b
--- /dev/null
+++ b/tools/bump-version/package-lock.json
@@ -0,0 +1,109 @@
+{
+ "name": "update-version",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "update-version",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "command-line-args": "^5.2.0",
+ "node-pandoc": "^0.3.0"
+ }
+ },
+ "node_modules/array-back": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
+ "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/command-line-args": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz",
+ "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==",
+ "dependencies": {
+ "array-back": "^3.1.0",
+ "find-replace": "^3.0.0",
+ "lodash.camelcase": "^4.3.0",
+ "typical": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/find-replace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz",
+ "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==",
+ "dependencies": {
+ "array-back": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
+ },
+ "node_modules/node-pandoc": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/node-pandoc/-/node-pandoc-0.3.0.tgz",
+ "integrity": "sha1-1GV3zQpyr0FTU/y4oBF622JC+cg="
+ },
+ "node_modules/typical": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
+ "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==",
+ "engines": {
+ "node": ">=8"
+ }
+ }
+ },
+ "dependencies": {
+ "array-back": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
+ "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q=="
+ },
+ "command-line-args": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz",
+ "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==",
+ "requires": {
+ "array-back": "^3.1.0",
+ "find-replace": "^3.0.0",
+ "lodash.camelcase": "^4.3.0",
+ "typical": "^4.0.0"
+ }
+ },
+ "find-replace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz",
+ "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==",
+ "requires": {
+ "array-back": "^3.0.1"
+ }
+ },
+ "lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
+ },
+ "node-pandoc": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/node-pandoc/-/node-pandoc-0.3.0.tgz",
+ "integrity": "sha1-1GV3zQpyr0FTU/y4oBF622JC+cg="
+ },
+ "typical": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
+ "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="
+ }
+ }
+}
diff --git a/tools/bump-version/package.json b/tools/bump-version/package.json
new file mode 100644
index 000000000..c40bdde24
--- /dev/null
+++ b/tools/bump-version/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "update-version",
+ "version": "1.0.0",
+ "type": "module",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "command-line-args": "^5.2.0",
+ "node-pandoc": "^0.3.0"
+ }
+}
diff --git a/tools/changelog.sh b/tools/changelog.sh
deleted file mode 100644
index 11d59b7fa..000000000
--- a/tools/changelog.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-
-version=${2:-HEAD}
-cat >> temp_changelog.md << EOF
-# v1.X.X ($version)
-
-Description Here.
-
-Compare Commits [on github](https://github.com/danielyxie/bitburner/compare/$1...$version).
-
----
-
-### Commits
-EOF
-
-git log $1...${version} \
- --pretty=format:'* [`%h`]([https://github.com/danielyxie/bitburner/commit/%H): %s (by %aN on %ad) %n' \
- --date=short \
- --no-merges >> temp_changelog.md
- # --reverse >> temp_changelog.md
-
-rm -f changelog_$1_${version}.md
-mv temp_changelog.md changelog_$1_${version}.md
diff --git a/tools/fetch-changelog/.gitignore b/tools/fetch-changelog/.gitignore
new file mode 100644
index 000000000..3e7196636
--- /dev/null
+++ b/tools/fetch-changelog/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+
+*.md
diff --git a/tools/fetch-changelog/index.js b/tools/fetch-changelog/index.js
new file mode 100644
index 000000000..5aa14d1c7
--- /dev/null
+++ b/tools/fetch-changelog/index.js
@@ -0,0 +1,240 @@
+import { Octokit } from "@octokit/rest";
+import commandLineArgs from "command-line-args";
+
+const owner = "danielyxie";
+const repo = "bitburner"
+const basePath = `https://github.com/${owner}/${repo}`;
+
+const cliArgs = commandLineArgs([
+ { name: 'from', alias: 'f', type: String },
+ { name: 'to', alias: 't', type: String },
+ { name: 'detailed', alias: 'd', type: Boolean }
+]);
+
+class MergeChangelog {
+ constructor(options) {
+ this.octokit = new Octokit(options);
+ }
+
+ async getCommitsSearchResults(query) {
+ const iterator = this.octokit.paginate.iterator(
+ this.octokit.rest.search.commits,
+ {
+ owner, repo,
+ q: query,
+ sort: 'updated',
+ direction: 'desc',
+ },
+ );
+ const searchResults = [];
+ for await (const response of iterator) {
+ const entries = response.data.map((entry) => ({
+ sha: entry.sha,
+ url: entry.html_url,
+ user: {
+ id: entry.author.id,
+ login: entry.author.login,
+ avatar: entry.author.avatar_url,
+ url: entry.author.html_url,
+ },
+ commit_date: entry.commit.committer.date,
+ message: entry.commit.message,
+ }));
+ searchResults.push(...entries);
+ }
+ return searchResults;
+ }
+
+ async getPullsSearchResults(query) {
+ const iterator = this.octokit.paginate.iterator(
+ this.octokit.rest.search.issuesAndPullRequests,
+ {
+ owner, repo,
+ q: query,
+ sort: 'committer-date',
+ direction: 'desc',
+ },
+ );
+
+ const searchResults = [];
+ for await (const response of iterator) {
+ const entries = response.data.map((entry) => ({
+ id: entry.id,
+ number: entry.number,
+ created_at: entry.updated_at,
+ merged_at: entry.pull_request.merged_at,
+ url: entry.pull_request.html_url,
+ title: entry.title,
+ body: entry.body,
+ diff: entry.diff_url,
+ patch: entry.patch_url,
+ user: {
+ id: entry.user.id,
+ login: entry.user.login,
+ avatar: entry.user.avatar_url,
+ url: entry.user.html_url,
+ },
+ }));
+ searchResults.push(...entries);
+ }
+
+ const pullRequestPromises = [];
+ for (const entry of searchResults) {
+ pullRequestPromises.push(
+ this.octokit.rest.pulls.get({
+ owner, repo,
+ pull_number: entry.number,
+ }).then((response) => ({
+ ...entry,
+ merge_commit_sha: response.data.merge_commit_sha,
+ head_commit_sha: response.data.head.sha,
+ })));
+ }
+
+ const pulls = await Promise.all(pullRequestPromises);
+ return pulls;
+ }
+
+ async getCommit(sha) {
+ const response = await this.octokit.rest.git.getCommit({
+ owner, repo,
+ commit_sha: sha,
+ });
+ const commit = {
+ date: response.data.committer.date,
+ message: response.data.message,
+ sha: response.data.sha,
+ url: response.data.html_url,
+ }
+ return commit;
+ }
+
+ async getPullsMergedBetween(sha_from, sha_to) {
+ const from = {};
+ const to = {};
+ from.commit = await this.getCommit(sha_from);
+ from.date = new Date(from.commit.date);
+
+ if (!sha_to) {
+ const newest = await this.getLastCommitByBranch('dev');
+ to.commit = await this.getCommit(newest)
+ } else {
+ to.commit = await this.getCommit(sha_to);
+ }
+
+ to.date = new Date(to.commit.date);
+
+ const commitQuery = `user:${owner} repo:${repo} merge:false committer-date:"${from.date.toISOString()}..${to.date.toISOString()}"`;
+ const pullQuery = `user:${owner} repo:${repo} is:pr is:merged merged:"${from.date.toISOString()}..${to.date.toISOString()}"`;
+
+ const commits = await this.getCommitsSearchResults(commitQuery);
+ const pulls = await this.getPullsSearchResults(pullQuery);
+
+ // We only have the merge commit sha & the HEAD sha in this data, but it can exclude some entries
+ const pullsCommitSha = pulls.
+ map((p) => [p.merge_commit_sha, p.head_commit_sha]).
+ reduce((all, current) => [...all, ...current]);
+
+ let danglingCommits = commits.filter((c) => !pullsCommitSha.includes(c.sha));
+ const listPullsPromises = [];
+ for (const commit of danglingCommits) {
+ const promise = this.octokit.rest.repos.listPullRequestsAssociatedWithCommit({
+ owner, repo, commit_sha: commit.sha
+ }).then((response) => ({
+ ...commit,
+ nbPulls: response.data.length,
+ }));
+ listPullsPromises.push(promise);
+ }
+
+ const commitsThatAreIncludedInPulls = (await Promise.all(listPullsPromises)).
+ filter((c) => c.nbPulls > 0).
+ map((c) => c.sha);
+
+ danglingCommits = danglingCommits.
+ filter((c) => !commitsThatAreIncludedInPulls.includes(c.sha));
+ return {
+ from,
+ to,
+ pulls,
+ danglingCommits,
+ pullQuery,
+ commitQuery,
+ }
+ }
+
+ async getLastCommitByBranch(branch) {
+ const response = await this.octokit.rest.repos.getBranch({
+ owner,
+ repo,
+ branch,
+ });
+ return response.data.commit.sha;
+ }
+
+ async getChangelog(from, to, detailedOutput) {
+ const changes = await this.getPullsMergedBetween(from, to);
+ const pullLines = changes.pulls.map((line) => this.getPullMarkdown(line, detailedOutput));
+ const commitLines = changes.danglingCommits.map((line) => this.getCommitMarkdown(line, detailedOutput));
+ commitLines.push(`* Nerf noodle bar.`)
+ const shortFrom = changes.from.date.toISOString().split('T')[0];
+ const shortTo = changes.to.date.toISOString().split('T')[0]
+ const shortFromSha = changes.from.commit.sha.slice(0, 7);
+ const shortToSha = changes.to.commit.sha.slice(0, 7);
+ const title = `## [draft] v1.x.x - ${shortFrom} to ${shortTo}`;
+ let log = `
+${title}
+
+#### Information
+
+Modifications included between **${shortFrom}** and **${shortTo}** (\`${shortFromSha}\` to \`${shortToSha}\`).
+
+*[See Pull Requests on GitHub](https://github.com/search?q=${encodeURIComponent(changes.pullQuery)})*
+
+#### Merged Pull Requests
+
+${pullLines.join('\n')}
+
+`;
+
+ if (commitLines.length > 0) {
+ log += `
+#### Other Changes
+
+${commitLines.join('\n')}
+`;
+ }
+ return {
+ log: log.trim(),
+ changes: changes,
+ };
+ }
+
+ getPullMarkdown(pr, detailedOutput) {
+ if (!detailedOutput) {
+ return `* ` +
+ `${pr.title} (by @${pr.user.login})` +
+ ` #[${pr.number}](${pr.url})`;
+ } else {
+ return `* [${pr.merge_commit_sha.slice(0, 7)}](${basePath}/commit/${pr.merge_commit_sha}) | ` +
+ `${pr.title} ([@${pr.user.login}](${pr.user.url}))` +
+ ` PR #[${pr.number}](${pr.url})`;
+ }
+ }
+
+ getCommitMarkdown(commit, detailedOutput) {
+ if (!detailedOutput) {
+ return `* ` +
+ `${commit.message} (by @${commit.user.login})` +
+ ` - [${commit.sha.slice(0, 7)}](${commit.url})`;
+ } else {
+ return `* [${commit.sha.slice(0, 7)}](${commit.url}) | ` +
+ `${commit.message} ([@${commit.user.login}](${commit.user.url}))`;
+ }
+ }
+}
+
+const api = new MergeChangelog({ auth: process.env.GITHUB_API_TOKEN });
+api.getChangelog(cliArgs.from, cliArgs.to, cliArgs.detailed).then((data) => {
+ console.log(data.log);
+});
diff --git a/tools/fetch-changelog/package-lock.json b/tools/fetch-changelog/package-lock.json
new file mode 100644
index 000000000..b4a7062e0
--- /dev/null
+++ b/tools/fetch-changelog/package-lock.json
@@ -0,0 +1,465 @@
+{
+ "name": "fetch-changelog",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "fetch-changelog",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "@octokit/rest": "^18.12.0",
+ "command-line-args": "^5.2.0"
+ }
+ },
+ "node_modules/@octokit/auth-token": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+ "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+ "dependencies": {
+ "@octokit/types": "^6.0.3"
+ }
+ },
+ "node_modules/@octokit/core": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
+ "integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
+ "dependencies": {
+ "@octokit/auth-token": "^2.4.4",
+ "@octokit/graphql": "^4.5.8",
+ "@octokit/request": "^5.6.0",
+ "@octokit/request-error": "^2.0.5",
+ "@octokit/types": "^6.0.3",
+ "before-after-hook": "^2.2.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/endpoint": {
+ "version": "6.0.12",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+ "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+ "dependencies": {
+ "@octokit/types": "^6.0.3",
+ "is-plain-object": "^5.0.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/graphql": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+ "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+ "dependencies": {
+ "@octokit/request": "^5.6.0",
+ "@octokit/types": "^6.0.3",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/openapi-types": {
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz",
+ "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA=="
+ },
+ "node_modules/@octokit/plugin-paginate-rest": {
+ "version": "2.17.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz",
+ "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==",
+ "dependencies": {
+ "@octokit/types": "^6.34.0"
+ },
+ "peerDependencies": {
+ "@octokit/core": ">=2"
+ }
+ },
+ "node_modules/@octokit/plugin-request-log": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
+ "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
+ "peerDependencies": {
+ "@octokit/core": ">=3"
+ }
+ },
+ "node_modules/@octokit/plugin-rest-endpoint-methods": {
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz",
+ "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==",
+ "dependencies": {
+ "@octokit/types": "^6.34.0",
+ "deprecation": "^2.3.1"
+ },
+ "peerDependencies": {
+ "@octokit/core": ">=3"
+ }
+ },
+ "node_modules/@octokit/request": {
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
+ "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
+ "dependencies": {
+ "@octokit/endpoint": "^6.0.1",
+ "@octokit/request-error": "^2.1.0",
+ "@octokit/types": "^6.16.1",
+ "is-plain-object": "^5.0.0",
+ "node-fetch": "^2.6.7",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/request-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+ "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+ "dependencies": {
+ "@octokit/types": "^6.0.3",
+ "deprecation": "^2.0.0",
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/@octokit/rest": {
+ "version": "18.12.0",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
+ "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==",
+ "dependencies": {
+ "@octokit/core": "^3.5.1",
+ "@octokit/plugin-paginate-rest": "^2.16.8",
+ "@octokit/plugin-request-log": "^1.0.4",
+ "@octokit/plugin-rest-endpoint-methods": "^5.12.0"
+ }
+ },
+ "node_modules/@octokit/types": {
+ "version": "6.34.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz",
+ "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==",
+ "dependencies": {
+ "@octokit/openapi-types": "^11.2.0"
+ }
+ },
+ "node_modules/array-back": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
+ "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/before-after-hook": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
+ "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
+ },
+ "node_modules/command-line-args": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz",
+ "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==",
+ "dependencies": {
+ "array-back": "^3.1.0",
+ "find-replace": "^3.0.0",
+ "lodash.camelcase": "^4.3.0",
+ "typical": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/deprecation": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
+ },
+ "node_modules/find-replace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz",
+ "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==",
+ "dependencies": {
+ "array-back": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
+ },
+ "node_modules/node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+ },
+ "node_modules/typical": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
+ "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/universal-user-agent": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
+ "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ }
+ },
+ "dependencies": {
+ "@octokit/auth-token": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+ "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+ "requires": {
+ "@octokit/types": "^6.0.3"
+ }
+ },
+ "@octokit/core": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
+ "integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
+ "requires": {
+ "@octokit/auth-token": "^2.4.4",
+ "@octokit/graphql": "^4.5.8",
+ "@octokit/request": "^5.6.0",
+ "@octokit/request-error": "^2.0.5",
+ "@octokit/types": "^6.0.3",
+ "before-after-hook": "^2.2.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/endpoint": {
+ "version": "6.0.12",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+ "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+ "requires": {
+ "@octokit/types": "^6.0.3",
+ "is-plain-object": "^5.0.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/graphql": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+ "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+ "requires": {
+ "@octokit/request": "^5.6.0",
+ "@octokit/types": "^6.0.3",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/openapi-types": {
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz",
+ "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA=="
+ },
+ "@octokit/plugin-paginate-rest": {
+ "version": "2.17.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz",
+ "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==",
+ "requires": {
+ "@octokit/types": "^6.34.0"
+ }
+ },
+ "@octokit/plugin-request-log": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
+ "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
+ "requires": {}
+ },
+ "@octokit/plugin-rest-endpoint-methods": {
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz",
+ "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==",
+ "requires": {
+ "@octokit/types": "^6.34.0",
+ "deprecation": "^2.3.1"
+ }
+ },
+ "@octokit/request": {
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
+ "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
+ "requires": {
+ "@octokit/endpoint": "^6.0.1",
+ "@octokit/request-error": "^2.1.0",
+ "@octokit/types": "^6.16.1",
+ "is-plain-object": "^5.0.0",
+ "node-fetch": "^2.6.7",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/request-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+ "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+ "requires": {
+ "@octokit/types": "^6.0.3",
+ "deprecation": "^2.0.0",
+ "once": "^1.4.0"
+ }
+ },
+ "@octokit/rest": {
+ "version": "18.12.0",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
+ "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==",
+ "requires": {
+ "@octokit/core": "^3.5.1",
+ "@octokit/plugin-paginate-rest": "^2.16.8",
+ "@octokit/plugin-request-log": "^1.0.4",
+ "@octokit/plugin-rest-endpoint-methods": "^5.12.0"
+ }
+ },
+ "@octokit/types": {
+ "version": "6.34.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz",
+ "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==",
+ "requires": {
+ "@octokit/openapi-types": "^11.2.0"
+ }
+ },
+ "array-back": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
+ "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q=="
+ },
+ "before-after-hook": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
+ "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
+ },
+ "command-line-args": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz",
+ "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==",
+ "requires": {
+ "array-back": "^3.1.0",
+ "find-replace": "^3.0.0",
+ "lodash.camelcase": "^4.3.0",
+ "typical": "^4.0.0"
+ }
+ },
+ "deprecation": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
+ },
+ "find-replace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz",
+ "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==",
+ "requires": {
+ "array-back": "^3.0.1"
+ }
+ },
+ "is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
+ },
+ "lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
+ },
+ "node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+ },
+ "typical": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
+ "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="
+ },
+ "universal-user-agent": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
+ "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
+ },
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ }
+ }
+}
diff --git a/tools/fetch-changelog/package.json b/tools/fetch-changelog/package.json
new file mode 100644
index 000000000..1b6eb595d
--- /dev/null
+++ b/tools/fetch-changelog/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "fetch-changelog",
+ "version": "1.0.0",
+ "type": "module",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "@octokit/rest": "^18.12.0",
+ "command-line-args": "^5.2.0"
+ }
+}