diff --git a/src/pr-collector/pullRequests.ts b/src/pr-collector/pullRequests.ts index 844d51e..86a9fca 100644 --- a/src/pr-collector/pullRequests.ts +++ b/src/pr-collector/pullRequests.ts @@ -215,19 +215,7 @@ export class PullRequests { } } -export function fetchedEnough(pullRequests: PullsListData, fromDate: moment.Moment): boolean { - for (let i = 0; i < Math.min(pullRequests.length, 3); i++) { - const firstPR = pullRequests[i] - if (!firstPR.merged_at) { - continue // no merged_at timestamp -> look for the next - } else if (fromDate.isAfter(moment(firstPR.merged_at))) { - return true - } else { - break // not enough PRs yet, go further - } - } - return false -} + function sortPrs(pullRequests: PullRequestInfo[]): PullRequestInfo[] { return sortPullRequests(pullRequests, { @@ -294,38 +282,3 @@ export function retrieveProperty(pr: PullRequestInfo, property: Property, useCas return value } -// helper function to add a special open label to prs not merged. -function attachSpeciaLabels(status: 'open' | 'merged', labels: string[]): string[] { - labels.push(`--rcba-${status}`) - return labels -} - -export const mapPullRequest = (pr: PullData | Unpacked, status: 'open' | 'merged' = 'open'): PullRequestInfo => ({ - number: pr.number, - title: pr.title, - htmlURL: pr.html_url, - baseBranch: pr.base.ref, - branch: pr.head.ref, - createdAt: moment(pr.created_at), - mergedAt: pr.merged_at ? moment(pr.merged_at) : undefined, - mergeCommitSha: pr.merge_commit_sha || '', - author: pr.user?.login || '', - repoName: pr.base.repo.full_name, - labels: attachSpeciaLabels(status, pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || []), - milestone: pr.milestone?.title || '', - body: pr.body || '', - assignees: pr.assignees?.map(asignee => asignee?.login || '') || [], - requestedReviewers: pr.requested_reviewers?.map(reviewer => reviewer?.login || '') || [], - approvedReviewers: [], - reviews: undefined, - status -}) - -export const mapComment = (comment: Unpacked): CommentInfo => ({ - id: comment.id, - htmlURL: comment.html_url, - submittedAt: comment.submitted_at ? moment(comment.submitted_at) : undefined, - author: comment.user?.login || '', - body: comment.body, - state: comment.state -}) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index 820e3f0..7ad1c5f 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -3,6 +3,8 @@ import {DiffInfo} from "../pr-collector/commits"; import {Options} from "../pr-collector/prCollector"; import moment from "moment/moment"; import {PullRequestInfo} from "../pr-collector/pullRequests"; +import * as core from "@actions/core"; +import {createCommandManager} from "../pr-collector/gitHelper"; export abstract class BaseRepository { proxy?: string; @@ -11,7 +13,7 @@ export abstract class BaseRepository { // Define an abstract getter for the default URL abstract get defaultUrl(): string; - protected constructor(protected token: string, protected url?: string) { + protected constructor(protected token: string, protected url: string | undefined,protected repositoryPath:string) { this.proxy = process.env.https_proxy || process.env.HTTPS_PROXY const noProxy = process.env.no_proxy || process.env.NO_PROXY this.noProxyArray = [] @@ -34,4 +36,24 @@ export abstract class BaseRepository { abstract getOpen(owner: string, repo: string, maxPullRequests: number): Promise abstract getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise + + + protected async getTagByCreateTime(repositoryPath: string, tagInfo: TagInfo) { + core.info(`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`) + const gitHelper = await createCommandManager(repositoryPath) + const creationTimeString = await gitHelper.tagCreation(tagInfo.name) + const creationTime = moment(creationTimeString) + if (creationTimeString !== null && creationTime.isValid()) { + tagInfo.date = creationTime + core.info( + `ℹ️ Resolved tag creation time (${creationTimeString}) from 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}` + ) + } else { + core.info( + `⚠️ Could not retrieve tag creation time via git cli 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}'` + ) + } + return tagInfo + } + } \ No newline at end of file diff --git a/src/repositories/GithubRepository.ts b/src/repositories/GithubRepository.ts index 9ce7deb..289da05 100644 --- a/src/repositories/GithubRepository.ts +++ b/src/repositories/GithubRepository.ts @@ -4,16 +4,13 @@ import {HttpsProxyAgent} from "https-proxy-agent"; import * as core from "@actions/core"; import {TagInfo} from "../pr-collector/tags"; import moment from "moment/moment"; -import {createCommandManager} from "../pr-collector/gitHelper"; import {DiffInfo} from "../pr-collector/commits"; import { - CommentInfo, - fetchedEnough, - mapComment, - mapPullRequest, + CommentInfo, PullData, PullRequestInfo, PullReviewsData, PullsListData } from "../pr-collector/pullRequests"; +import {Unpacked} from "../pr-collector/utils"; export class GithubRepository extends BaseRepository { @@ -90,11 +87,12 @@ export class GithubRepository extends BaseRepository { const prs: PullsListData = response.data as PullsListData for (const pr of prs) { - mergedPRs.push(mapPullRequest(pr, pr.merged_at ? 'merged' : 'open')) + mergedPRs.push(this.mapPullRequest(pr, pr.merged_at ? 'merged' : 'open')) } } return mergedPRs } + async getBetweenDates(owner: string, repo: string, fromDate: moment.Moment, toDate: moment.Moment, maxPullRequests: number): Promise { const mergedPRs: PullRequestInfo[] = [] const options = this.octokit.pulls.list.endpoint.merge({ @@ -109,13 +107,13 @@ export class GithubRepository extends BaseRepository { const prs: PullsListData = response.data as PullsListData for (const pr of prs.filter(p => !!p.merged_at)) { - mergedPRs.push(mapPullRequest(pr, 'merged')) + mergedPRs.push(this.mapPullRequest(pr, 'merged')) } if (mergedPRs.length >= maxPullRequests) { core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests} (1)`) break // bail out early to not keep iterating forever } else if (prs.length > 0) { - if (fetchedEnough(prs, fromDate)) { + if (this.fetchedEnough(prs, fromDate)) { return mergedPRs // bail out early to not keep iterating on PRs super old } } else { @@ -125,6 +123,7 @@ export class GithubRepository extends BaseRepository { } return mergedPRs } + async getOpen(owner: string, repo: string, maxPullRequests: number): Promise { const openPrs: PullRequestInfo[] = [] const options = this.octokit.pulls.list.endpoint.merge({ @@ -140,7 +139,7 @@ export class GithubRepository extends BaseRepository { const prs: PullsListData = response.data as PullsListData for (const pr of prs) { - openPrs.push(mapPullRequest(pr, 'open')) + openPrs.push(this.mapPullRequest(pr, 'open')) } const firstPR = prs[0] @@ -153,6 +152,7 @@ export class GithubRepository extends BaseRepository { } return openPrs } + async getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise { const options = this.octokit.pulls.listReviews.endpoint.merge({ owner, @@ -166,17 +166,20 @@ export class GithubRepository extends BaseRepository { const comments: PullReviewsData = response.data as PullReviewsData for (const comment of comments) { - prReviews.push(mapComment(comment)) + prReviews.push(this.mapComment(comment)) } } pr.reviews = prReviews } + get defaultUrl(): string { - return "https://api.example.com"; + return "https://api.github.com"; } - private octokit:Octokit - constructor(token: string, url?: string) { - super(token, url); + + private octokit: Octokit + + constructor(token: string, url: string|undefined,repositoryPath:string) { + super(token, url,repositoryPath); this.url = url || this.defaultUrl // load octokit instance @@ -240,23 +243,57 @@ export class GithubRepository extends BaseRepository { tagInfo.date = moment(release.created_at) core.info(`ℹ️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`) } catch (error) { - core.info(`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`) - const gitHelper = await createCommandManager(repositoryPath) - const creationTimeString = await gitHelper.tagCreation(tagInfo.name) - const creationTime = moment(creationTimeString) - if (creationTimeString !== null && creationTime.isValid()) { - tagInfo.date = creationTime - core.info( - `ℹ️ Resolved tag creation time (${creationTimeString}) from 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}` - ) - } else { - core.info( - `⚠️ Could not retrieve tag creation time via git cli 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}'` - ) - } + tagInfo = await this.getTagByCreateTime(repositoryPath, tagInfo) } return tagInfo } +// helper function to add a special open label to prs not merged. + private attachSpecialLabels(status: 'open' | 'merged', labels: string[]): string[] { + labels.push(`--rcba-${status}`) + return labels + } + private mapPullRequest = (pr: PullData | Unpacked, status: 'open' | 'merged' = 'open'): PullRequestInfo => ({ + number: pr.number, + title: pr.title, + htmlURL: pr.html_url, + baseBranch: pr.base.ref, + branch: pr.head.ref, + createdAt: moment(pr.created_at), + mergedAt: pr.merged_at ? moment(pr.merged_at) : undefined, + mergeCommitSha: pr.merge_commit_sha || '', + author: pr.user?.login || '', + repoName: pr.base.repo.full_name, + labels: this.attachSpecialLabels(status, pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || []), + milestone: pr.milestone?.title || '', + body: pr.body || '', + assignees: pr.assignees?.map(asignee => asignee?.login || '') || [], + requestedReviewers: pr.requested_reviewers?.map(reviewer => reviewer?.login || '') || [], + approvedReviewers: [], + reviews: undefined, + status + }) + + private mapComment = (comment: Unpacked): CommentInfo => ({ + id: comment.id, + htmlURL: comment.html_url, + submittedAt: comment.submitted_at ? moment(comment.submitted_at) : undefined, + author: comment.user?.login || '', + body: comment.body, + state: comment.state + }) + private fetchedEnough(pullRequests: PullsListData, fromDate: moment.Moment): boolean { + for (let i = 0; i < Math.min(pullRequests.length, 3); i++) { + const firstPR = pullRequests[i] + if (!firstPR.merged_at) { + continue // no merged_at timestamp -> look for the next + } else if (fromDate.isAfter(moment(firstPR.merged_at))) { + return true + } else { + break // not enough PRs yet, go further + } + } + return false + } } \ No newline at end of file