mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-01 02:00:10 +00:00
40fce9aba7
* fix(gerrit): resolve relative submodule URLs for nested project paths * Fix tests after rebase --------- Co-authored-by: Felipe Santos <felipe.santos@ericsson.com>
183 lines
5.4 KiB
TypeScript
183 lines
5.4 KiB
TypeScript
import { CONFIG_GIT_URL_UNAVAILABLE } from '../../../constants/error-messages.ts';
|
|
import { logger } from '../../../logger/index.ts';
|
|
import type { BranchStatus, PrState } from '../../../types/index.ts';
|
|
import { coerceArray } from '../../../util/array.ts';
|
|
import * as hostRules from '../../../util/host-rules.ts';
|
|
import { regEx } from '../../../util/regex.ts';
|
|
import { toLongCommitSha } from '../../../util/schema-utils/git.ts';
|
|
import { joinUrlParts, parseUrl } from '../../../util/url.ts';
|
|
import { hashBody } from '../pr-body.ts';
|
|
import type { GitUrlOption, Pr } from '../types.ts';
|
|
import type { GerritChange, GerritLabelTypeInfo } from './schema.ts';
|
|
import type { GerritChangeStatus, GerritRequestDetail } from './types.ts';
|
|
|
|
export const MIN_GERRIT_VERSION = '3.0.0';
|
|
|
|
export const TAG_PULL_REQUEST_BODY = 'pull-request';
|
|
|
|
const DEFAULT_SSH_PORT = `29418`;
|
|
|
|
/**
|
|
* Max comment size in Gerrit (16kiB by default)
|
|
* https://gerrit-review.googlesource.com/Documentation/config-gerrit.html#change:~:text=change.commentSizeLimit
|
|
*/
|
|
export const MAX_GERRIT_COMMENT_SIZE = 16 * 1024;
|
|
|
|
export const REQUEST_DETAILS_FOR_PRS: GerritRequestDetail[] = [
|
|
'MESSAGES', // to get the pr body
|
|
'LABELS', // to get the reviewers
|
|
'DETAILED_ACCOUNTS', // to get the reviewers usernames
|
|
'CURRENT_REVISION', // to get the commit message
|
|
'COMMIT_FOOTERS', // to get the commit message
|
|
] as const;
|
|
|
|
export function getGerritRepoUrl(
|
|
repository: string,
|
|
endpoint: string,
|
|
gitUrl: GitUrlOption | undefined,
|
|
username: string,
|
|
): string {
|
|
const endpointUrl = parseUrl(endpoint);
|
|
if (!endpointUrl) {
|
|
throw new Error(CONFIG_GIT_URL_UNAVAILABLE);
|
|
}
|
|
|
|
const url =
|
|
gitUrl === 'ssh'
|
|
? createSshUrl(endpointUrl, repository, username)
|
|
: createHttpUrl(endpointUrl, endpoint, repository);
|
|
logger.trace({ url }, 'using URL based on configured endpoint');
|
|
|
|
return url;
|
|
}
|
|
|
|
function createSshUrl(url: URL, repository: string, username: string): string {
|
|
return `ssh://${username}@${url.hostname}:${DEFAULT_SSH_PORT}/${repository}`;
|
|
}
|
|
|
|
function createHttpUrl(url: URL, endpoint: string, repository: string): string {
|
|
// Find options for current host and determine Git endpoint
|
|
const opts = hostRules.find({
|
|
hostType: 'gerrit',
|
|
url: endpoint,
|
|
});
|
|
|
|
if (!(opts.username && opts.password)) {
|
|
throw new Error(
|
|
'Init: You must configure a Gerrit Server username/password',
|
|
);
|
|
}
|
|
|
|
url.username = opts.username;
|
|
url.password = opts.password;
|
|
url.pathname = joinUrlParts(url.pathname, 'a', repository);
|
|
return url.toString();
|
|
}
|
|
|
|
export function mapPrStateToGerritFilter(state?: PrState): string | null {
|
|
switch (state) {
|
|
case 'merged':
|
|
return 'status:merged';
|
|
case 'open':
|
|
return 'status:open';
|
|
case 'closed':
|
|
return 'status:abandoned';
|
|
case '!open':
|
|
return '-status:open';
|
|
case 'all':
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function mapGerritChangeToPr(
|
|
change: GerritChange,
|
|
knownProperties?: {
|
|
sourceBranch?: string;
|
|
prBody?: string;
|
|
},
|
|
): Pr | null {
|
|
const sourceBranch =
|
|
knownProperties?.sourceBranch ?? extractSourceBranch(change);
|
|
if (!sourceBranch) {
|
|
return null;
|
|
}
|
|
return {
|
|
number: change._number,
|
|
state: mapGerritChangeStateToPrState(change.status),
|
|
sourceBranch,
|
|
targetBranch: change.branch,
|
|
title: change.subject,
|
|
createdAt: convertGerritDateToISO(change.created),
|
|
labels: change.hashtags,
|
|
reviewers: coerceArray(
|
|
change.reviewers?.REVIEWER?.map((reviewer) => reviewer.username!),
|
|
),
|
|
bodyStruct: {
|
|
hash: hashBody(knownProperties?.prBody ?? findPullRequestBody(change)),
|
|
},
|
|
sha: toLongCommitSha(change.current_revision),
|
|
};
|
|
}
|
|
|
|
export function mapGerritChangeStateToPrState(
|
|
state: GerritChangeStatus,
|
|
): 'merged' | 'open' | 'closed' {
|
|
switch (state) {
|
|
case 'NEW':
|
|
return 'open';
|
|
case 'MERGED':
|
|
return 'merged';
|
|
case 'ABANDONED':
|
|
return 'closed';
|
|
}
|
|
}
|
|
|
|
export function extractSourceBranch(change: GerritChange): string | undefined {
|
|
let sourceBranch: string | undefined = undefined;
|
|
|
|
if (change.current_revision) {
|
|
const re = regEx(/^Renovate-Branch: (?<branch>.+)$/m);
|
|
const currentRevision = change.revisions![change.current_revision];
|
|
const message = currentRevision.commit_with_footers;
|
|
// v8 ignore else -- TODO: add test #40625
|
|
if (message) {
|
|
sourceBranch = re.exec(message)?.groups?.branch;
|
|
}
|
|
}
|
|
|
|
return sourceBranch ?? undefined;
|
|
}
|
|
|
|
export function findPullRequestBody(change: GerritChange): string | undefined {
|
|
const msg = Array.from(coerceArray(change.messages))
|
|
.reverse()
|
|
.find((msg) => msg.tag === TAG_PULL_REQUEST_BODY);
|
|
if (msg) {
|
|
// Gerrit adds a "Patch Set X:" prefix to comments
|
|
return msg.message.replace(regEx(/^Patch Set \d+:\n\n/), '');
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function mapBranchStatusToLabel(
|
|
state: BranchStatus | 'UNKNOWN', // suppress default path code removal
|
|
label: GerritLabelTypeInfo,
|
|
): number {
|
|
const numbers = Object.keys(label.values).map((x) => parseInt(x, 10));
|
|
switch (state) {
|
|
case 'green':
|
|
return Math.max(...numbers);
|
|
case 'yellow':
|
|
case 'red':
|
|
return Math.min(...numbers);
|
|
}
|
|
/* v8 ignore next -- only reachable for the artificial 'UNKNOWN' state, which callers never pass */
|
|
return label.default_value;
|
|
}
|
|
|
|
// Convert Gerrit date format to ISO format
|
|
export function convertGerritDateToISO(date: string): string {
|
|
return date.replace(' ', 'T');
|
|
}
|