forked from axios/axios
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(ci): added labeling and notification for published PRs; (axios#…
- Loading branch information
1 parent
dd465ab
commit 37cbf92
Showing
13 changed files
with
373 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import util from "util"; | ||
import cp from "child_process"; | ||
import {parseVersion} from "./helpers/parser.js"; | ||
import githubAxios from "./githubAxios.js"; | ||
import memoize from 'memoizee'; | ||
|
||
const exec = util.promisify(cp.exec); | ||
|
||
export default class GithubAPI { | ||
constructor(owner, repo) { | ||
if (!owner) { | ||
throw new Error('repo owner must be specified'); | ||
} | ||
|
||
if (!repo) { | ||
throw new Error('repo must be specified'); | ||
} | ||
|
||
this.repo = repo; | ||
this.owner = owner; | ||
this.axios = githubAxios.create({ | ||
baseURL: `https://api.github.com/repos/${this.owner}/${this.repo}/`, | ||
}) | ||
} | ||
|
||
async createComment(issue, body) { | ||
return (await this.axios.post(`/issues/${issue}/comments`, {body})).data; | ||
} | ||
|
||
async getComments(issue, {desc = false, per_page= 100, page = 1}) { | ||
return (await this.axios.get(`/issues/${issue}/comments`, {params: {direction: desc ? 'desc' : 'asc', per_page, page}})).data; | ||
} | ||
|
||
async getComment(id) { | ||
return (await this.axios.get(`/issues/comments/${id}`)).data; | ||
} | ||
|
||
async updateComment(id, body) { | ||
return (await this.axios.patch(`/issues/comments/${id}`, {body})).data; | ||
} | ||
|
||
async appendLabels(issue, labels) { | ||
return (await this.axios.post(`issues/${issue}/labels`, {labels})).data; | ||
} | ||
|
||
async getUser(user) { | ||
return (await this.axios.get(`users/${user}`)).data; | ||
} | ||
|
||
async isCollaborator(user) { | ||
try { | ||
return (await this.axios.get(`/collaborators/${user}`)).status === 204; | ||
} catch (e) { | ||
|
||
} | ||
} | ||
|
||
async deleteLabel(issue, label) { | ||
return (await this.axios.delete(`/issues/${issue}/labels/${label}`)).data; | ||
} | ||
|
||
async getIssue(issue) { | ||
return (await this.axios.get(`/issues/${issue}`)).data; | ||
} | ||
|
||
async getPR(issue) { | ||
return (await this.axios.get(`/pulls/${issue}`)).data; | ||
} | ||
|
||
async getIssues({state= 'open', labels, sort = 'created', desc = false, per_page = 100, page = 1}) { | ||
return (await this.axios.get(`/issues`, {params: {state, labels, sort, direction: desc ? 'desc' : 'asc', per_page, page}})).data; | ||
} | ||
|
||
async updateIssue(issue, data) { | ||
return (await this.axios.patch(`/issues/${issue}`, data)).data; | ||
} | ||
|
||
async closeIssue(issue) { | ||
return this.updateIssue(issue, { | ||
state: "closed" | ||
}) | ||
} | ||
|
||
async getReleases({per_page = 30, page= 1} = {}) { | ||
return (await this.axios.get(`/releases`, {params: {per_page, page}})).data; | ||
} | ||
|
||
async getRelease(release = 'latest') { | ||
return (await this.axios.get(parseVersion(release) ? `/releases/tags/${release}` : `/releases/${release}`)).data; | ||
} | ||
|
||
async getTags({per_page = 30, page= 1} = {}) { | ||
return (await this.axios.get(`/tags`, {params: {per_page, page}})).data; | ||
} | ||
|
||
async reopenIssue(issue) { | ||
return this.updateIssue(issue, { | ||
state: "open" | ||
}) | ||
} | ||
|
||
static async getTagRef(tag) { | ||
try { | ||
return (await exec(`git show-ref --tags "refs/tags/${tag}"`)).stdout.split(' ')[0]; | ||
} catch (e) { | ||
} | ||
} | ||
} | ||
|
||
const {prototype} = GithubAPI; | ||
|
||
['getUser', 'isCollaborator'].forEach(methodName => { | ||
prototype[methodName] = memoize(prototype[methodName], { promise: true }) | ||
}); | ||
|
||
['get', 'post', 'put', 'delete', 'isAxiosError'].forEach((method) => prototype[method] = function(...args){ | ||
return this.axios[method](...args); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
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"; | ||
|
||
const normalizeTag = (tag) => tag.replace(/^v/, ''); | ||
|
||
class RepoBot { | ||
constructor(options) { | ||
const { | ||
owner, repo, | ||
templates | ||
} = options || {}; | ||
|
||
this.templates = Object.assign({ | ||
published: '../templates/pr_published.hbs' | ||
}, 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) { | ||
const pr = await this.github.getPR(id); | ||
|
||
tag = normalizeTag(tag); | ||
|
||
const {merged, labels, user: {login, type}} = pr; | ||
|
||
const isBot = type === 'Bot'; | ||
|
||
if (!merged) { | ||
return false | ||
} | ||
|
||
await this.github.appendLabels(id, ['v' + tag]); | ||
|
||
if (isBot || labels.find(({name}) => name === 'automated pr') || (await this.github.isCollaborator(login))) { | ||
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/v${tag}` | ||
} | ||
}); | ||
|
||
return await this.addComment(id, message); | ||
} | ||
|
||
async notifyPublishedPRs(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 ? 'OK' : 'Skipped'); | ||
} 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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import minimist from "minimist"; | ||
import RepoBot from '../RepoBot.js'; | ||
|
||
const argv = minimist(process.argv.slice(2)); | ||
console.log(argv); | ||
|
||
const tag = argv.tag; | ||
|
||
if (!tag) { | ||
throw new Error('tag must be specified'); | ||
} | ||
|
||
const bot = new RepoBot(); | ||
|
||
(async() => { | ||
try { | ||
await bot.notifyPublishedPRs(tag); | ||
} catch (err) { | ||
console.warn('Error:', err.message); | ||
} | ||
})(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import GithubAPI from "./GithubAPI.js"; | ||
|
||
export default new GithubAPI('axios', 'axios'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export const matchAll = (text, regexp, cb) => { | ||
let match; | ||
while((match = regexp.exec(text))) { | ||
cb(match); | ||
} | ||
} | ||
|
||
export const parseSection = (body, name, cb) => { | ||
matchAll(body, new RegExp(`^(#+)\\s+${name}?(.*?)^\\1\\s+\\w+`, 'gims'), cb); | ||
} | ||
|
||
export const parseVersion = (rawVersion) => /^v?(\d+).(\d+).(\d+)/.exec(rawVersion); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.