129 lines
3.2 KiB
JavaScript
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;
|