refactor: Extract github platform resolver
This commit is contained in:
@@ -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[] {
|
function sortPrs(pullRequests: PullRequestInfo[]): PullRequestInfo[] {
|
||||||
return sortPullRequests(pullRequests, {
|
return sortPullRequests(pullRequests, {
|
||||||
@@ -294,38 +282,3 @@ export function retrieveProperty(pr: PullRequestInfo, property: Property, useCas
|
|||||||
return value
|
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<PullsListData>, 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<PullReviewsData>): 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
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import {DiffInfo} from "../pr-collector/commits";
|
|||||||
import {Options} from "../pr-collector/prCollector";
|
import {Options} from "../pr-collector/prCollector";
|
||||||
import moment from "moment/moment";
|
import moment from "moment/moment";
|
||||||
import {PullRequestInfo} from "../pr-collector/pullRequests";
|
import {PullRequestInfo} from "../pr-collector/pullRequests";
|
||||||
|
import * as core from "@actions/core";
|
||||||
|
import {createCommandManager} from "../pr-collector/gitHelper";
|
||||||
|
|
||||||
export abstract class BaseRepository {
|
export abstract class BaseRepository {
|
||||||
proxy?: string;
|
proxy?: string;
|
||||||
@@ -11,7 +13,7 @@ export abstract class BaseRepository {
|
|||||||
// Define an abstract getter for the default URL
|
// Define an abstract getter for the default URL
|
||||||
abstract get defaultUrl(): string;
|
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
|
this.proxy = process.env.https_proxy || process.env.HTTPS_PROXY
|
||||||
const noProxy = process.env.no_proxy || process.env.NO_PROXY
|
const noProxy = process.env.no_proxy || process.env.NO_PROXY
|
||||||
this.noProxyArray = []
|
this.noProxyArray = []
|
||||||
@@ -34,4 +36,24 @@ export abstract class BaseRepository {
|
|||||||
abstract getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]>
|
abstract getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]>
|
||||||
|
|
||||||
abstract getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void>
|
abstract getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void>
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -4,16 +4,13 @@ import {HttpsProxyAgent} from "https-proxy-agent";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import {TagInfo} from "../pr-collector/tags";
|
import {TagInfo} from "../pr-collector/tags";
|
||||||
import moment from "moment/moment";
|
import moment from "moment/moment";
|
||||||
import {createCommandManager} from "../pr-collector/gitHelper";
|
|
||||||
import {DiffInfo} from "../pr-collector/commits";
|
import {DiffInfo} from "../pr-collector/commits";
|
||||||
import {
|
import {
|
||||||
CommentInfo,
|
CommentInfo, PullData,
|
||||||
fetchedEnough,
|
|
||||||
mapComment,
|
|
||||||
mapPullRequest,
|
|
||||||
PullRequestInfo,
|
PullRequestInfo,
|
||||||
PullReviewsData, PullsListData
|
PullReviewsData, PullsListData
|
||||||
} from "../pr-collector/pullRequests";
|
} from "../pr-collector/pullRequests";
|
||||||
|
import {Unpacked} from "../pr-collector/utils";
|
||||||
|
|
||||||
export class GithubRepository extends BaseRepository {
|
export class GithubRepository extends BaseRepository {
|
||||||
|
|
||||||
@@ -90,11 +87,12 @@ export class GithubRepository extends BaseRepository {
|
|||||||
const prs: PullsListData = response.data as PullsListData
|
const prs: PullsListData = response.data as PullsListData
|
||||||
|
|
||||||
for (const pr of prs) {
|
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
|
return mergedPRs
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBetweenDates(owner: string, repo: string, fromDate: moment.Moment, toDate: moment.Moment, maxPullRequests: number): Promise<PullRequestInfo[]> {
|
async getBetweenDates(owner: string, repo: string, fromDate: moment.Moment, toDate: moment.Moment, maxPullRequests: number): Promise<PullRequestInfo[]> {
|
||||||
const mergedPRs: PullRequestInfo[] = []
|
const mergedPRs: PullRequestInfo[] = []
|
||||||
const options = this.octokit.pulls.list.endpoint.merge({
|
const options = this.octokit.pulls.list.endpoint.merge({
|
||||||
@@ -109,13 +107,13 @@ export class GithubRepository extends BaseRepository {
|
|||||||
const prs: PullsListData = response.data as PullsListData
|
const prs: PullsListData = response.data as PullsListData
|
||||||
|
|
||||||
for (const pr of prs.filter(p => !!p.merged_at)) {
|
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) {
|
if (mergedPRs.length >= maxPullRequests) {
|
||||||
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests} (1)`)
|
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests} (1)`)
|
||||||
break // bail out early to not keep iterating forever
|
break // bail out early to not keep iterating forever
|
||||||
} else if (prs.length > 0) {
|
} 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
|
return mergedPRs // bail out early to not keep iterating on PRs super old
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -125,6 +123,7 @@ export class GithubRepository extends BaseRepository {
|
|||||||
}
|
}
|
||||||
return mergedPRs
|
return mergedPRs
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
|
async getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
|
||||||
const openPrs: PullRequestInfo[] = []
|
const openPrs: PullRequestInfo[] = []
|
||||||
const options = this.octokit.pulls.list.endpoint.merge({
|
const options = this.octokit.pulls.list.endpoint.merge({
|
||||||
@@ -140,7 +139,7 @@ export class GithubRepository extends BaseRepository {
|
|||||||
const prs: PullsListData = response.data as PullsListData
|
const prs: PullsListData = response.data as PullsListData
|
||||||
|
|
||||||
for (const pr of prs) {
|
for (const pr of prs) {
|
||||||
openPrs.push(mapPullRequest(pr, 'open'))
|
openPrs.push(this.mapPullRequest(pr, 'open'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstPR = prs[0]
|
const firstPR = prs[0]
|
||||||
@@ -153,6 +152,7 @@ export class GithubRepository extends BaseRepository {
|
|||||||
}
|
}
|
||||||
return openPrs
|
return openPrs
|
||||||
}
|
}
|
||||||
|
|
||||||
async getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void> {
|
async getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void> {
|
||||||
const options = this.octokit.pulls.listReviews.endpoint.merge({
|
const options = this.octokit.pulls.listReviews.endpoint.merge({
|
||||||
owner,
|
owner,
|
||||||
@@ -166,17 +166,20 @@ export class GithubRepository extends BaseRepository {
|
|||||||
const comments: PullReviewsData = response.data as PullReviewsData
|
const comments: PullReviewsData = response.data as PullReviewsData
|
||||||
|
|
||||||
for (const comment of comments) {
|
for (const comment of comments) {
|
||||||
prReviews.push(mapComment(comment))
|
prReviews.push(this.mapComment(comment))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pr.reviews = prReviews
|
pr.reviews = prReviews
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultUrl(): string {
|
get defaultUrl(): string {
|
||||||
return "https://api.example.com";
|
return "https://api.github.com";
|
||||||
}
|
}
|
||||||
private octokit:Octokit
|
|
||||||
constructor(token: string, url?: string) {
|
private octokit: Octokit
|
||||||
super(token, url);
|
|
||||||
|
constructor(token: string, url: string|undefined,repositoryPath:string) {
|
||||||
|
super(token, url,repositoryPath);
|
||||||
this.url = url || this.defaultUrl
|
this.url = url || this.defaultUrl
|
||||||
|
|
||||||
// load octokit instance
|
// load octokit instance
|
||||||
@@ -240,23 +243,57 @@ export class GithubRepository extends BaseRepository {
|
|||||||
tagInfo.date = moment(release.created_at)
|
tagInfo.date = moment(release.created_at)
|
||||||
core.info(`ℹ️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`)
|
core.info(`ℹ️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.info(`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`)
|
tagInfo = await this.getTagByCreateTime(repositoryPath, tagInfo)
|
||||||
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
|
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<PullsListData>, 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<PullReviewsData>): 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user