diff --git a/src/entrypoint.ts b/src/entrypoint.ts index a6db5ca..663f695 100644 --- a/src/entrypoint.ts +++ b/src/entrypoint.ts @@ -1,14 +1,28 @@ -import { IssuesAddLabelsParams, IssuesAddLabelsResponseItem, IssuesListLabelsOnIssueParams, IssuesListLabelsOnIssueResponse, PullsListFilesParams, PullsListFilesResponse, PullsListFilesResponseItem, Response } from '@octokit/rest'; -import { Toolkit, ToolkitOptions } from 'actions-toolkit'; +import { + IssuesAddLabelsParams, + IssuesAddLabelsResponseItem, + IssuesListLabelsOnIssueParams, + IssuesListLabelsOnIssueResponse, + PullsListFilesParams, + PullsListFilesResponse, + PullsListFilesResponseItem, + Response +} from '@octokit/rest'; +import {Toolkit, ToolkitOptions} from 'actions-toolkit'; // tslint:disable-next-line:no-submodule-imports -import { WebhookPayloadWithRepository } from 'actions-toolkit/lib/context'; +import {WebhookPayloadWithRepository} from 'actions-toolkit/lib/context'; // tslint:disable-next-line:no-submodule-imports -import { Exit } from 'actions-toolkit/lib/exit'; +import {Exit} from 'actions-toolkit/lib/exit'; // tslint:disable-next-line:no-submodule-imports -import { GitHub } from 'actions-toolkit/lib/github'; -import { LoggerFunc, Signale } from 'signale'; -import { Filter, Repository } from './types'; -import { buildIssueRemoveLabelParams, filterConfiguredIssueLabels, intersectLabels, processListFilesResponses } from './utils'; +import {GitHub} from 'actions-toolkit/lib/github'; +import {LoggerFunc, Signale} from 'signale'; +import {Filter, Repository} from './types'; +import { + buildIssueRemoveLabelParams, + filterConfiguredIssueLabels, + intersectLabels, + processListFilesResponses +} from './utils'; const LOGO: string = ` ██████╗ ███████╗ ██████╗ █████╗ ████████╗██╗ ██╗██╗ ██████╗ ███╗ ██╗ @@ -42,19 +56,19 @@ const findRepositoryInformation = (gitHubEventPath: string, log: LoggerFunc & Si const findIssueLabels = (issuesListLabelsOnIssueParams: IssuesListLabelsOnIssueParams, issues, filters: Filter[]): Promise => { // Find issue labels that are configured in .github/label-pr.yml return issues.listLabelsOnIssue(issuesListLabelsOnIssueParams) - .then(({ data: labels }: Response) => labels.reduce((acc, label) => acc.concat(label.name), [])) + .then(({data: labels}: Response) => labels.reduce((acc, label) => acc.concat(label.name), [])) .then(issueLabels => filterConfiguredIssueLabels(issueLabels, filters)); }; // Remove provided labels -const removeIssueLabels = (labels: string[], { log, exit }: Toolkit, repository: Repository, issues): void => { +const removeIssueLabels = (labels: string[], {log, exit}: Toolkit, repository: Repository, issues): void => { log.info('Labels to remove: ', labels); buildIssueRemoveLabelParams(repository, labels) .forEach(value => issues.removeLabel(value).catch(reason => exit.failure(reason))); }; // Build labels to add -const getLabelsToAdd = (labels: string[], issueLabels: string[], { log, exit }: Toolkit): string[] => { +const getLabelsToAdd = (labels: string[], issueLabels: string[], {log, exit}: Toolkit): string[] => { const labelsToAdd: string[] = intersectLabels(labels, issueLabels); log.info('Labels to add: ', labelsToAdd); if (labelsToAdd.length === 0) { @@ -63,6 +77,21 @@ const getLabelsToAdd = (labels: string[], issueLabels: string[], { log, exit }: return labelsToAdd; }; +// Fetch all files (by recursively calling with page and per_page parameters) +const fetchAllFiles = (listFiles, log, params: PullsListFilesParams, per_page: number, page: number): Promise => { + log.info(`Listing files (page: ${page} | per_page: ${per_page})...`); + return listFiles({per_page, page, ...params}) + .then((response: Response) => { + // If there may be other files to fetch + log.info(`Loaded ${response.data.length} files`); + let pullsListFilesResponseItems: PullsListFilesResponse = response.data; + if (pullsListFilesResponseItems.length >= per_page) { + return fetchAllFiles(listFiles, log, params, per_page, page + 1).then(value => value.concat(pullsListFilesResponseItems)); + } + return pullsListFilesResponseItems; + }); +}; + Toolkit.run(async (toolkit: Toolkit) => { toolkit.log.info('Open sourced by\n' + LOGO); @@ -73,16 +102,15 @@ Toolkit.run(async (toolkit: Toolkit) => { if (!process.env.GITHUB_EVENT_PATH) { toolkit.exit.failure('Process env GITHUB_EVENT_PATH is undefined'); } else { - const { owner, issue_number, repo }: IssuesListLabelsOnIssueParams = findRepositoryInformation(process.env.GITHUB_EVENT_PATH, toolkit.log, toolkit.exit); - const { pulls: { listFiles }, issues }: GitHub = toolkit.github; + const {owner, issue_number, repo}: IssuesListLabelsOnIssueParams = findRepositoryInformation(process.env.GITHUB_EVENT_PATH, toolkit.log, toolkit.exit); + const {pulls: {listFiles}, issues}: GitHub = toolkit.github; // First, we need to retrieve the existing issue labels and filter them over the configured one in config file - const issueLabels: string[] = await findIssueLabels({ issue_number, owner, repo }, issues, filters); + const issueLabels: string[] = await findIssueLabels({issue_number, owner, repo}, issues, filters); - const params: PullsListFilesParams = { owner, pull_number: issue_number, repo }; + const params: PullsListFilesParams = {owner, pull_number: issue_number, repo}; - await listFiles(params) - .then((response: Response) => response.data) + await fetchAllFiles(listFiles, toolkit.log, params, 100, 1) .then((files: PullsListFilesResponseItem[]) => { toolkit.log.info('Checking files...', files.reduce((acc: string[], file: PullsListFilesResponseItem) => acc.concat(file.filename), [])); return files; @@ -90,8 +118,8 @@ Toolkit.run(async (toolkit: Toolkit) => { .then((files: PullsListFilesResponseItem[]) => processListFilesResponses(files, filters)) .then((eligibleFilters: Filter[]) => eligibleFilters.reduce((acc: string[], eligibleFilter: Filter) => acc.concat(eligibleFilter.labels), [])) .then((labels: string[]) => { - removeIssueLabels(intersectLabels(issueLabels, labels), toolkit, { owner, issue_number, repo }, issues); - return { issue_number, labels: getLabelsToAdd(labels, issueLabels, toolkit), owner, repo }; + removeIssueLabels(intersectLabels(issueLabels, labels), toolkit, {owner, issue_number, repo}, issues); + return {issue_number, labels: getLabelsToAdd(labels, issueLabels, toolkit), owner, repo}; } ) .then((addLabelsParams: IssuesAddLabelsParams) => issues.addLabels(addLabelsParams))