1
0
term/pkg/axios/bin/RepoBot.js
2024-03-24 02:31:03 +09:00

129 lines
3.2 KiB
JavaScript

import GithubAPI from "./GithubAPI.js";
import api from './api.js';
import Handlebars from "handlebars";
import fs from "fs/promises";
import {colorize} from "./helpers/colorize.js";
import {getReleaseInfo} from "./contributors.js";
import path from "path";
import {fileURLToPath} from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const NOTIFY_PR_TEMPLATE = path.resolve(__dirname, '../templates/pr_published.hbs');
const normalizeTag = (tag) => tag ? 'v' + tag.replace(/^v/, '') : '';
const GITHUB_BOT_LOGIN = 'github-actions[bot]';
const skipCollaboratorPRs = true;
class RepoBot {
constructor(options) {
const {
owner, repo,
templates
} = options || {};
this.templates = Object.assign({
published: NOTIFY_PR_TEMPLATE
}, templates);
this.github = api || new GithubAPI(owner, repo);
this.owner = this.github.owner;
this.repo = this.github.repo;
}
async addComment(targetId, message) {
return this.github.createComment(targetId, message);
}
async notifyPRPublished(id, tag) {
let pr;
try {
pr = await this.github.getPR(id);
} catch (err) {
if(err.response?.status === 404) {
throw new Error(`PR #${id} not found (404)`);
}
throw err;
}
tag = normalizeTag(tag);
const {merged, labels, user: {login, type}} = pr;
const isBot = type === 'Bot';
if (!merged) {
return false
}
await this.github.appendLabels(id, [tag]);
if (isBot || labels.find(({name}) => name === 'automated pr') || (skipCollaboratorPRs && await this.github.isCollaborator(login))) {
return false;
}
const comments = await this.github.getComments(id, {desc: true});
const comment = comments.find(
({body, user}) => user.login === GITHUB_BOT_LOGIN && body.indexOf('published in') >= 0
)
if (comment) {
console.log(colorize()`Release comment [${comment.html_url}] already exists in #${pr.id}`);
return false;
}
const author = await this.github.getUser(login);
author.isBot = isBot;
const message = await this.constructor.renderTemplate(this.templates.published, {
id,
author,
release: {
tag,
url: `https://github.com/${this.owner}/${this.repo}/releases/tag/${tag}`
}
});
return await this.addComment(id, message);
}
async notifyPublishedPRs(tag) {
tag = normalizeTag(tag);
const release = await getReleaseInfo(tag);
if (!release) {
throw Error(colorize()`Can't get release info for ${tag}`);
}
const {merges} = release;
console.log(colorize()`Found ${merges.length} PRs in ${tag}:`);
let i = 0;
for (const pr of merges) {
try {
console.log(colorize()`${i++}) Notify PR #${pr.id}`)
const result = await this.notifyPRPublished(pr.id, tag);
console.log('✔️', result ? 'Label, comment' : 'Label');
} catch (err) {
console.warn(colorize('green', 'red')`❌ Failed notify PR ${pr.id}: ${err.message}`);
}
}
}
static async renderTemplate(template, data) {
return Handlebars.compile(String(await fs.readFile(template)))(data);
}
}
export default RepoBot;