247 lines
8.7 KiB
JavaScript
247 lines
8.7 KiB
JavaScript
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
|
|
import fs from "fs";
|
|
import { Octokit } from "octokit";
|
|
import { parseReleases } from "auto-changelog/src/releases.js";
|
|
import { fetchTags } from "auto-changelog/src/tags.js";
|
|
import { fetchRemote } from "auto-changelog/src/remote.js";
|
|
import * as toml from "@iarna/toml";
|
|
|
|
import "zx/globals";
|
|
|
|
// if (!process.env.GITHUB_TOKEN) {
|
|
// throw new Error("Missing GITHUB_TOKEN");
|
|
// }
|
|
|
|
const IS_NIGHTLY = process.argv.indexOf("--nightly") > -1;
|
|
|
|
const PKG_VERSION = JSON.parse(fs.readFileSync("./package.json")).version.match(
|
|
/[0-9]+\.[0-9]+\.[0-9]+/,
|
|
)[0];
|
|
|
|
const GIT_REV = await $`git show --no-patch --format=%ct HEAD`;
|
|
|
|
console.log();
|
|
|
|
const NEW_VERSION = IS_NIGHTLY
|
|
? `${PKG_VERSION}-dev${+new Date(parseInt(GIT_REV.toString()))}`
|
|
: PKG_VERSION;
|
|
|
|
/**
|
|
* A Github data fetching cache designed to run in parallel with changelog formatting.
|
|
* When a SHA is requested, it is looked up in a local cache, and if it isn't there,
|
|
* the next Github API page is awaited. Requests are always triggered in advance.
|
|
*/
|
|
class GithubPRCache {
|
|
constructor() {
|
|
this.prs = new Map();
|
|
this.page = 1;
|
|
this.octokit = new Octokit({
|
|
auth: process.env.GITHUB_TOKEN,
|
|
});
|
|
this.next();
|
|
}
|
|
async next() {
|
|
let ret;
|
|
if (this._next_req) {
|
|
ret = await this._next_req;
|
|
}
|
|
console.log(
|
|
`Fetching Github commits ${(this.page - 1) * 100} - ${
|
|
this.page * 100 - 1
|
|
}`,
|
|
);
|
|
this._next_req = this.octokit.request(
|
|
"GET /repos/{owner}/{repo}/pulls?state=closed&per_page={per_page}&page={page}",
|
|
{
|
|
owner: "perspective-dev",
|
|
repo: "perspective",
|
|
per_page: 100,
|
|
page: this.page++,
|
|
},
|
|
);
|
|
return ret;
|
|
}
|
|
async get(sha) {
|
|
while (!this.prs.has(sha) && !this.failed) {
|
|
const resp = await this.next();
|
|
if (resp.data.length == 0) {
|
|
this.failed = true;
|
|
}
|
|
for (const pr of resp.data) {
|
|
this.prs.set(pr.merge_commit_sha, pr);
|
|
}
|
|
}
|
|
return this.prs.get(sha);
|
|
}
|
|
}
|
|
function template_group(label, rows, prs) {
|
|
if (rows.length > 0) {
|
|
const group_prs = rows
|
|
.map((merge) => `- ${merge.message} [#${merge.id}](${merge.href})`)
|
|
.join("\n");
|
|
return `${label}\n\n${group_prs}\n`;
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
function template_release(args) {
|
|
const prs = Object.keys(args.row)
|
|
.map((label) => template_group(label, args.row[label]))
|
|
.filter((x) => x.length > 0)
|
|
.join("\n");
|
|
return `# [${args.release.title}](https://github.com/perspective-dev/perspective/releases/tag/${args.release.title})
|
|
|
|
_${args.release.niceDate}_ ([Full changelog](${args.release.href}))
|
|
|
|
${prs}
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* Generate the changelog text from the output of `auto-changelog`, iteratively calling
|
|
* Github's API when necessary to get label information for grouping.
|
|
*
|
|
* @param {*} json the output data from `auto-changelog`
|
|
* @returns
|
|
*/
|
|
async function template(json) {
|
|
const cache = new GithubPRCache();
|
|
let changelog = "";
|
|
for (const release of json) {
|
|
const row = {
|
|
"**Breaking**": [],
|
|
Features: [],
|
|
Fixes: [],
|
|
Misc: [],
|
|
};
|
|
for (const merge of release.merges) {
|
|
const pr = await cache.get(merge.commit.hash);
|
|
merge.pr = pr;
|
|
if (pr) {
|
|
const labels = pr.labels.map((x) => x.name);
|
|
if (labels.indexOf("breaking") > -1) {
|
|
row["**Breaking**"].push(merge);
|
|
} else if (labels.indexOf("enhancement") > -1) {
|
|
row.Features.push(merge);
|
|
} else if (labels.indexOf("bug") > -1) {
|
|
row.Fixes.push(merge);
|
|
} else {
|
|
row.Misc.push(merge);
|
|
}
|
|
} else {
|
|
row.Misc.push(merge);
|
|
}
|
|
}
|
|
changelog += template_release({
|
|
row,
|
|
release,
|
|
});
|
|
}
|
|
return changelog;
|
|
}
|
|
|
|
/**
|
|
* Update the `CHANGELOG.md` file from Github API.
|
|
*/
|
|
async function update_changelog() {
|
|
let options = {
|
|
remote: "origin",
|
|
commitLimit: 10000,
|
|
backfillLimit: 10000,
|
|
tagPrefix: "",
|
|
sortCommits: "relevance",
|
|
appendGitLog: "",
|
|
appendGitTag: "",
|
|
latestVersion: NEW_VERSION,
|
|
};
|
|
const remote = await fetchRemote(options);
|
|
options = {
|
|
...options,
|
|
...remote,
|
|
};
|
|
console.log("Fetching tags…");
|
|
const tags = await fetchTags(options);
|
|
console.log(`${tags.length} version tags found…`);
|
|
const onParsed = ({ title }) => console.log(`Fetched ${title}…`);
|
|
const json = await parseReleases(tags, options, onParsed);
|
|
const changelog = await template(json);
|
|
fs.writeFileSync("./CHANGELOG.md", changelog);
|
|
$.sync`git add CHANGELOG.md`;
|
|
}
|
|
|
|
/**
|
|
* Update all project `package.json` files.
|
|
*/
|
|
async function update_package_jsons() {
|
|
const pkg = JSON.parse(fs.readFileSync("./package.json"));
|
|
pkg.version = NEW_VERSION;
|
|
const pkg_json = `${JSON.stringify(pkg, undefined, 4)}\n`;
|
|
fs.writeFileSync("./package.json", pkg_json);
|
|
const packages = {};
|
|
for (const ws of pkg.workspaces) {
|
|
if (ws === "packages/jupyterlab" && IS_NIGHTLY) {
|
|
continue;
|
|
}
|
|
|
|
for (const path of glob.sync(`${ws}/package.json`, {
|
|
sync: true,
|
|
})) {
|
|
const pkg = JSON.parse(fs.readFileSync(path));
|
|
pkg.version = NEW_VERSION;
|
|
fs.writeFileSync(path, JSON.stringify(pkg, undefined, 4) + "\n");
|
|
packages[pkg.name] = {
|
|
pkg,
|
|
path,
|
|
};
|
|
}
|
|
}
|
|
|
|
const cargo = toml.parse(fs.readFileSync("./Cargo.toml"));
|
|
for (const pkg of cargo.workspace.members) {
|
|
const crate = toml.parse(fs.readFileSync(`./${pkg}/Cargo.toml`));
|
|
if (crate?.package.version) {
|
|
crate.package.version = NEW_VERSION;
|
|
}
|
|
|
|
for (const key of Object.keys(crate?.dependencies)) {
|
|
if (key.startsWith("perspective")) {
|
|
crate.dependencies[key].version = NEW_VERSION;
|
|
}
|
|
}
|
|
fs.writeFileSync(`./${pkg}/Cargo.toml`, toml.stringify(crate));
|
|
}
|
|
|
|
// if (!IS_NIGHTLY) {
|
|
const pyproject = toml.parse(
|
|
fs.readFileSync(`./rust/perspective-python/pyproject.toml`),
|
|
);
|
|
|
|
pyproject.tool.maturin.data = `perspective_python-${NEW_VERSION}.data`;
|
|
fs.writeFileSync(
|
|
`./rust/perspective-python/pyproject.toml`,
|
|
toml.stringify(pyproject),
|
|
);
|
|
// }
|
|
}
|
|
|
|
if (!IS_NIGHTLY) {
|
|
if (!process.env.GITHUB_TOKEN) {
|
|
throw new Error("Missing GITHUB_TOKEN");
|
|
}
|
|
|
|
await update_changelog();
|
|
}
|
|
|
|
await update_package_jsons();
|