/
githubmirror
/
amphtml
Обзор
Документация
Войти
/
githubmirror
/
amphtml
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
build-system/release-tagger/utils.js
319 строк
8 KB
Daniel Rozenberg
🏗 Partial updates for core devDependencies (#39765)
26 янв 2024, 20:21
Не верифицирован
26 янв 2024, 20:21
74f443b
Код
Авторство
О чём код?
/** * @fileoverview * GitHub API util functions. */ const {default: dedent} = require('dedent'); const {graphql} = require('@octokit/graphql'); const {Octokit} = require('@octokit/rest'); /** @typedef {import('@octokit/graphql').GraphQlQueryResponseData} GraphQlQueryResponseData */ /** * GitHub API util functions */ class GitHubApi { /** * @param {object} octokitRest * @param {object} octokitGraphQl */ constructor(octokitRest, octokitGraphQl) { this.octokit = octokitRest ? octokitRest : new Octokit({ auth: process.env.GITHUB_TOKEN, userAgent: 'amp release tagger', timeZone: 'America/Los_Angeles', }); this.octokit.hook.error('request', (error) => { // don't throw an error if resource is not found if (error.status === 404) { return; } }); this.graphqlWithAuth = octokitGraphQl ? octokitGraphQl : graphql.defaults({ headers: { authorization: `token ${process.env.GITHUB_TOKEN}`, }, }); this.info = {owner: 'ampproject', repo: 'amphtml'}; this.config = { singleNodeQueryLimit: 100, totalNodeQueryLimit: 500000, batchSize: 5, }; } /** * Queries the GitHub GraphQL API in batches. * @param {string} queryType * @param {Array<string>} queries * @return {Promise<Array<GraphQlQueryResponseData>>} */ async runQueryInBatches(queryType, queries) { const responses = []; for (let i = 0; i < queries.length; i += this.config.batchSize) { const join = queries .slice(i, i + Math.min(queries.length, this.config.batchSize)) .join(' '); const query = `${queryType} {${join}}`; const data = await this.graphqlWithAuth({query}); responses.push(...Object.values(data)); } return responses; } /** * Create a GitHub issue * @param {string} body * @param {string} label * @param {string} title * @return {Promise<Object>} */ async createIssue(body, label, title) { const {data} = await this.octokit.rest.issues.create({ ...this.info, title, body, labels: [label], }); return data; } /** * Create a GitHub release * @param {string} tag * @param {string} commit * @param {string} body * @param {boolean} prerelease * @return {Promise<Object>} */ async createRelease(tag, commit, body, prerelease) { const {data} = await this.octokit.rest.repos.createRelease({ ...this.info, name: tag, 'tag_name': tag, 'target_commitish': commit, body, prerelease, }); return data; } /** * Get a GitHub issue by title * @param {string} title * @return {Promise<GraphQlQueryResponseData|undefined>} */ async getIssue(title) { const search = dedent`\ search(query:"repo:${this.info.owner}/${this.info.repo} in:title ${title}", \ type: ISSUE, first: 1) { nodes { ... on Issue \ { number title body url }}}`; const query = `query {${search}}`; const response = await this.graphqlWithAuth({query}); if (response.search?.nodes) { return response.search.nodes[0]; } } /** * Get a GitHub release by tag name * @param {string} tag * @return {Promise<Object|undefined>} */ async getRelease(tag) { const response = await this.octokit.rest.repos.getReleaseByTag({ ...this.info, tag, }); return response?.data; } /** * Update a GitHub issue * @param {string} body * @param {number} number * @param {string} title * @param {'open' | 'closed'} state * @return {Promise<Object>} */ async updateIssue(body, number, title, state = 'open') { const {data} = await this.octokit.rest.issues.update({ ...this.info, 'issue_number': number, title, body, state, }); return data; } /** * Update a GitHub release * @param {string} id * @param {object} changes * @return {Promise<Object>} */ async updateRelease(id, changes) { const {data} = await this.octokit.rest.repos.updateRelease({ ...this.info, 'release_id': id, ...changes, }); return data; } /** * Get a list of commits between two commits * @param {string} head * @param {string} base * @return {Promise<Object>} */ async compareCommits(head, base) { const {data} = await this.octokit.rest.repos.compareCommits({ ...this.info, base, head, }); return data; } /** * Get pull requests associated with a list of commits * @param {Array<string>} shas * @return {Promise<Array<GraphQlQueryResponseData>>} */ async getPullRequests(shas) { const queries = []; for (const [i, sha] of shas.entries()) { queries.push( dedent`\ pr${i}: search(query:"repo:${this.info.owner}/${this.info.repo} sha:${sha}", type:ISSUE \ first:${this.config.singleNodeQueryLimit}){\ nodes { ... on PullRequest { id title number url author { login } \ files(first:${this.config.singleNodeQueryLimit}) { nodes { path }} \ mergeCommit { commitUrl oid abbreviatedOid }}}}` ); } const nodesLists = await this.runQueryInBatches('query', queries); // Only return pull requests with the merge commit shas const prs = []; for (const nodesList of nodesLists) { for (const node of nodesList.nodes) { if (node.mergeCommit && shas.includes(node.mergeCommit.oid)) { prs.push(node); } } } return prs; } /** * Get pull requests between two commits * @param {string} head * @param {string} base * @return {Promise<Array<GraphQlQueryResponseData>>} */ async getPullRequestsBetweenCommits(head, base) { const {commits} = await this.compareCommits(head, base); const shas = commits.map((commit) => commit.sha); return this.getPullRequests(shas); } /** * Get label * @param {string} name * @return {Promise<Object|undefined>} */ async getLabel(name) { const response = await this.octokit.rest.issues.getLabel({ ...this.info, name, }); return response?.data; } /** * Label pull requests * @param {Array<Object>} prs * @param {string} labelId * @return {Promise<Array<GraphQlQueryResponseData>>} */ async labelPullRequests(prs, labelId) { const mutations = []; for (const [i, pr] of prs.entries()) { mutations.push( dedent`\ pr${i}: addLabelsToLabelable(input:{labelIds:"${labelId}", \ labelableId:"${pr.id}", clientMutationId:"${pr.id}"})\ {clientMutationId}` ); } return await this.runQueryInBatches('mutation', mutations); } /** * Unlabel pull requests * @param {Array<Object>} prs * @param {string} labelId * @return {Promise<Array<GraphQlQueryResponseData>>} */ async unlabelPullRequests(prs, labelId) { const mutations = []; for (const [i, pr] of prs.entries()) { mutations.push( dedent`\ pr${i}: removeLabelsFromLabelable(input:{labelIds:"${labelId}", \ labelableId:"${pr.id}", clientMutationId:"${pr.id}"})\ {clientMutationId}` ); } return await this.runQueryInBatches('mutation', mutations); } /** * Get a git ref * @param {string} tag * @return {Promise<Object|undefined>} */ async getRef(tag) { const response = await this.octokit.rest.git.getRef({ ...this.info, ref: `tags/${tag}`, }); return response?.data; } /** * Create git tag and ref * @param {string} tag * @param {string} sha * @return {Promise<Object>} */ async createTag(tag, sha) { await this.octokit.rest.git.createTag({ ...this.info, tag, message: tag, object: sha, type: 'commit', }); // once a tag object is created, create a reference const {data} = await this.octokit.rest.git.createRef({ ...this.info, ref: `refs/tags/${tag}`, sha, }); return data; } } module.exports = {GitHubApi};