Files
release-changelog-builder-a…/src/repositories/GiteaRepository.ts
T
Mike PenzandGitHub 0e00e184e7 - improve formatting
- add some more comments
2023-11-05 10:30:10 +00:00

250 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {BaseRepository} from './BaseRepository'
import {TagInfo} from '../pr-collector/tags'
import {CommentInfo, PullRequestInfo} from '../pr-collector/pullRequests'
import {DiffInfo} from '../pr-collector/commits'
import {Api, PullRequest, PullReview, giteaApi} from 'gitea-js'
import moment from 'moment'
import * as core from '@actions/core'
import {createCommandManager} from '../pr-collector/gitHelper'
interface Pulls {
closed: PullRequest[]
open: PullRequest[]
}
export class GiteaRepository extends BaseRepository {
private api: Api<unknown>
get defaultUrl(): string {
return 'https://gitea.com'
}
get homeUrl(): string {
return 'https://gitea.com'
}
constructor(token: string, url: string | undefined, repositoryPath: string) {
super(token, url, repositoryPath)
this.url = url || this.defaultUrl
this.api = giteaApi(this.url, {
token
})
}
async fillTagInformation(repositoryPath: string, owner: string, repo: string, tagInfo: TagInfo): Promise<TagInfo> {
const response = await this.api.repos.repoGetTag(owner, repo, tagInfo.name)
if (response.error === null) {
if (response.data.commit) {
tagInfo.date = moment(response.data.commit.created)
core.info(`️ Retrieved information about the release associated with ${tagInfo.name} from the Gitea API`)
return tagInfo
}
}
return await this.getTagByCreateTime(repositoryPath, tagInfo)
}
async getBetweenDates(
owner: string,
repo: string,
fromDate: moment.Moment,
toDate: moment.Moment,
maxPullRequests: number
): Promise<PullRequestInfo[]> {
const mergedPRs: PullRequestInfo[] = []
await this.getAllPullRequest(owner, repo, 'closed', maxPullRequests)
for (const pr of GiteaRepository.pulls.closed.filter(p => !!p.merged_at)) {
if (moment(pr.closed_at) > fromDate && moment(pr.closed_at) < toDate) {
mergedPRs.push(this.mapPullRequest(pr, 'merged'))
}
}
return mergedPRs
}
private mapPullRequest(pr: PullRequest, status: 'open' | 'merged' = 'open'): PullRequestInfo {
return {
number: pr.number || 0,
title: pr.title || '',
htmlURL: pr.html_url || '',
baseBranch: pr.base?.repo?.default_branch || '',
branch: pr.merge_base || '',
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: pr.labels?.map(label => label.name) as string[],
milestone: pr.milestone?.title || '',
body: pr.body || '',
assignees: pr.assignees?.map(user => user.full_name) as string[],
requestedReviewers: pr.requested_reviewers?.map(user => user.full_name) as string[],
approvedReviewers: [],
createdAt: moment(pr.created_at),
status,
reviews: undefined
}
}
/**
* WARNING: This does not actually get the diff from the remote, as Gitea does not offer a compareable API.
* This uses the local repository to get the diff. NOTE: As such, gitea integration requires the repo available.
*/
async getDiffRemote(owner: string, repo: string, base: string, head: string): Promise<DiffInfo> {
let changedFilesCount = 0
let additionCount = 0
let deletionCount = 0
const changeCount = 0
let commitCount = 0
const gitHelper = await createCommandManager(this.repositoryPath)
// Get the diff stats between the two branches/commits
const diffStat = await gitHelper.execGit(['diff', '--stat', `${base}...${head}`])
const diffStatLines = diffStat.stdout.split('\n')
for (const line of diffStatLines) {
// Extract the addition and deletion counts from each line of the git diff output
const match = line.match(/(\d+) insertions?\(\+\), (\d+) deletions?\(-\)/)
if (match) {
additionCount += parseInt(match[1], 10)
deletionCount += parseInt(match[2], 10)
}
}
// Get the list of changed files
const diffNameOnly = await gitHelper.execGit(['diff', '--name-only', `${base}...${head}`])
const changedFiles = diffNameOnly.stdout.split('\n')
changedFilesCount = changedFiles.length - 1 // Subtract one for the empty line at the end
// Get the commit count between the two branches/commits
const logCount = await gitHelper.execGit(['rev-list', '--count', `${base}...${head}`])
commitCount = parseInt(logCount.stdout.trim(), 10)
// Now let's get the commit logs between the two branches/commits
const log = await gitHelper.execGit(['log', '--pretty=format:%H||||%an||||%ae||||%ad||||%cn||||%ce||||%cd||||%s', `${base}...${head}`])
const commitLogs = log.stdout.trim().split('\n')
// Process commit logs
const commitInfo = commitLogs.map(commitLog => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [sha, authorName, authorEmail, authorDate, committerName, committerEmail, committerDate, subject] = commitLog.split('||||')
return {
sha,
summary: subject,
message: '', // This would require another git command to get the full message if needed
author: authorName,
authorDate: moment(authorDate, 'ddd MMM DD HH:mm:ss YYYY ZZ', false),
committer: committerName,
commitDate: moment(committerDate, 'ddd MMM DD HH:mm:ss YYYY ZZ', false),
prNumber: undefined // This is not available directly from git, would require additional logic to associate commits with PRs
}
})
return {
changedFiles: changedFilesCount,
additions: additionCount,
deletions: deletionCount,
changes: changeCount,
commits: commitCount,
commitInfo
}
}
static pulls: Pulls = {
closed: [],
open: []
}
private async getAllPullRequest(owner: string, repo: string, state: 'closed' | 'open', maxPullRequests: number): Promise<void> {
if (GiteaRepository.pulls[state].length === 0) {
let page = 1
let count = 0
while (count < maxPullRequests) {
const limit = Math.min(50, maxPullRequests)
const response = await this.api.repos.repoListPullRequests(owner, repo, {
sort: 'recentupdate',
state,
limit,
page
})
if (response.error === null) {
GiteaRepository.pulls[state].push(...response.data)
} else {
core.error(`️ Some errors. ${response.error.message}`)
}
page++
count += response.data.length
if (response.data.length === 0) break
}
}
}
async getForCommitHash(owner: string, repo: string, commit_sha: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
const mergedPRs: PullRequestInfo[] = []
await this.getAllPullRequest(owner, repo, 'closed', maxPullRequests)
for (const pr of GiteaRepository.pulls.closed) {
if (pr.merge_commit_sha === commit_sha) {
mergedPRs.push(this.mapPullRequest(pr, pr.merged_at ? 'merged' : 'open'))
}
}
core.debug(`Completed fetching PRs from API. Fetched: ${mergedPRs.length}`)
return mergedPRs
}
async getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
await this.getAllPullRequest(owner, repo, 'open', maxPullRequests)
const openPrs: PullRequestInfo[] = []
for (const pr of GiteaRepository.pulls.open) {
openPrs.push(this.mapPullRequest(pr, 'open'))
}
return openPrs
}
async getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void> {
const prReviews: CommentInfo[] = []
const response = await this.api.repos.repoListPullReviews(owner, repo, pr.number, {})
if (response.error === null) {
for (const comment of response.data) {
prReviews.push(this.mapComment(comment))
}
} else {
core.error(`️ Some errors. ${response.error.message}`)
}
pr.reviews = prReviews
}
private mapComment = (comment: PullReview): CommentInfo => ({
id: comment.id || 0,
htmlURL: comment.html_url || '',
submittedAt: comment.submitted_at ? moment(comment.submitted_at) : undefined,
author: comment.user?.login || '',
body: comment.body || '',
state: comment.state
})
async getTags(owner: string, repo: string, maxTagsToFetch: number): Promise<TagInfo[]> {
core.debug(`Start to get tag from gitea`)
const response = await this.api.repos.repoListTags(owner, repo, {
limit: maxTagsToFetch
})
const tagsInfo: TagInfo[] = []
if (response.error === null) {
for (const tag of response.data) {
tagsInfo.push({
name: tag.name || '',
commit: tag.commit?.sha
})
}
} else {
core.error(`️ Some errors. ${response.error.message}`)
}
core.info(`️ Found ${tagsInfo.length} (fetching max: ${maxTagsToFetch}) tags from the GitHub API for ${owner}/${repo}`)
return tagsInfo
}
}