paginate app operations and refine runtime settings layout
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -11,6 +11,8 @@ GITEA_APP_ORG=platform
|
||||
GITEA_ADMIN_TOKEN=
|
||||
GITEA_RELEASE_PUSH_WHITELIST=
|
||||
GITEA_RELEASE_MERGE_WHITELIST=
|
||||
GITEA_RELEASE_PUSH_WHITELIST_TEAMS=
|
||||
GITEA_RELEASE_MERGE_WHITELIST_TEAMS=
|
||||
BUILD_REGISTRY=localhost:5000
|
||||
BUILD_ARTIFACT_INSTALL_COMMAND=npm ci
|
||||
LAUNCHER_BUILD_COMMAND="npm ci && npm run build:linux"
|
||||
|
||||
+38
-16
@@ -640,6 +640,11 @@ export class AppsService {
|
||||
|
||||
if (byRepository.size === 0) return;
|
||||
|
||||
const gitBin = this.configService.get<string>('GIT_BIN', 'git');
|
||||
const isUnrelatedHistoryError = (message: string) => {
|
||||
const normalized = message.toLowerCase();
|
||||
return normalized.includes('refusing to merge unrelated histories') || normalized.includes('not possible to fast-forward');
|
||||
};
|
||||
const workRoot = path.join(os.tmpdir(), 'studio-admin-release-promotions');
|
||||
await fs.mkdir(workRoot, { recursive: true });
|
||||
|
||||
@@ -647,38 +652,59 @@ export class AppsService {
|
||||
const workDir = path.join(workRoot, `${sanitizeImageName(repository)}-${Date.now()}`);
|
||||
try {
|
||||
await fs.rm(workDir, { recursive: true, force: true });
|
||||
await execFileAsync(this.configService.get<string>('GIT_BIN', 'git'), [
|
||||
await execFileAsync(gitBin, [
|
||||
'clone',
|
||||
'--no-checkout',
|
||||
await this.getAuthenticatedHttpCloneUrl(repository),
|
||||
workDir,
|
||||
]);
|
||||
await execFileAsync(this.configService.get<string>('GIT_BIN', 'git'), [
|
||||
await execFileAsync(gitBin, [
|
||||
'fetch',
|
||||
'origin',
|
||||
sourceBranch,
|
||||
], { cwd: workDir });
|
||||
await execFileAsync(this.configService.get<string>('GIT_BIN', 'git'), [
|
||||
await execFileAsync(gitBin, [
|
||||
'fetch',
|
||||
'origin',
|
||||
targetBranch,
|
||||
], { cwd: workDir }).catch(() => undefined);
|
||||
|
||||
const targetExists = await gitRefExists(workDir, `refs/remotes/origin/${targetBranch}`, this.configService.get<string>('GIT_BIN', 'git'));
|
||||
const pushArgs: string[] = ['push', 'origin', `HEAD:refs/heads/${targetBranch}`];
|
||||
|
||||
const targetExists = await gitRefExists(workDir, `refs/remotes/origin/${targetBranch}`, gitBin);
|
||||
if (targetExists) {
|
||||
await execFileAsync(this.configService.get<string>('GIT_BIN', 'git'), [
|
||||
await execFileAsync(gitBin, [
|
||||
'checkout',
|
||||
'-B',
|
||||
targetBranch,
|
||||
`origin/${targetBranch}`,
|
||||
], { cwd: workDir });
|
||||
await execFileAsync(this.configService.get<string>('GIT_BIN', 'git'), [
|
||||
'merge',
|
||||
'--ff-only',
|
||||
commitSha,
|
||||
], { cwd: workDir });
|
||||
let forcePush = false;
|
||||
try {
|
||||
await execFileAsync(gitBin, [
|
||||
'merge',
|
||||
'--ff-only',
|
||||
commitSha,
|
||||
], { cwd: workDir });
|
||||
} catch (error) {
|
||||
const message = String(error instanceof Error ? error.message : error);
|
||||
if (!isUnrelatedHistoryError(message)) {
|
||||
throw error;
|
||||
}
|
||||
forcePush = true;
|
||||
await execFileAsync(gitBin, [
|
||||
'checkout',
|
||||
'-B',
|
||||
targetBranch,
|
||||
commitSha,
|
||||
], { cwd: workDir });
|
||||
}
|
||||
|
||||
if (forcePush) {
|
||||
pushArgs.splice(0, pushArgs.length, 'push', '--force-with-lease', 'origin', `HEAD:refs/heads/${targetBranch}`);
|
||||
}
|
||||
} else {
|
||||
await execFileAsync(this.configService.get<string>('GIT_BIN', 'git'), [
|
||||
await execFileAsync(gitBin, [
|
||||
'checkout',
|
||||
'-B',
|
||||
targetBranch,
|
||||
@@ -686,11 +712,7 @@ export class AppsService {
|
||||
], { cwd: workDir });
|
||||
}
|
||||
|
||||
await execFileAsync(this.configService.get<string>('GIT_BIN', 'git'), [
|
||||
'push',
|
||||
'origin',
|
||||
`HEAD:refs/heads/${targetBranch}`,
|
||||
], { cwd: workDir });
|
||||
await execFileAsync(gitBin, pushArgs, { cwd: workDir });
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown git promotion failure';
|
||||
throw new BadRequestException(`${repository} release 브랜치 승격 실패: ${message}`);
|
||||
|
||||
+19
-20
@@ -36,6 +36,8 @@ export class GiteaService {
|
||||
private readonly token?: string;
|
||||
private readonly releaseBranchPushUsers: string[];
|
||||
private readonly releaseBranchMergeUsers: string[];
|
||||
private readonly releaseBranchPushTeams: string[];
|
||||
private readonly releaseBranchMergeTeams: string[];
|
||||
|
||||
constructor(configService: ConfigService) {
|
||||
this.baseUrl = configService
|
||||
@@ -49,6 +51,12 @@ export class GiteaService {
|
||||
this.releaseBranchMergeUsers = parseWhiteList(
|
||||
configService.get<string>('GITEA_RELEASE_MERGE_WHITELIST'),
|
||||
);
|
||||
this.releaseBranchPushTeams = parseWhiteList(
|
||||
configService.get<string>('GITEA_RELEASE_PUSH_WHITELIST_TEAMS'),
|
||||
);
|
||||
this.releaseBranchMergeTeams = parseWhiteList(
|
||||
configService.get<string>('GITEA_RELEASE_MERGE_WHITELIST_TEAMS'),
|
||||
);
|
||||
}
|
||||
|
||||
async getVersion() {
|
||||
@@ -258,23 +266,22 @@ export class GiteaService {
|
||||
}
|
||||
|
||||
private async protectReleaseBranch(owner: string, repo: string) {
|
||||
const me = await this.getAuthenticatedUser();
|
||||
const pushUsernames = uniqueUsers([
|
||||
...this.releaseBranchPushUsers,
|
||||
...(me?.login ? [me.login] : []),
|
||||
]);
|
||||
const mergeUsernames = uniqueUsers([
|
||||
...this.releaseBranchMergeUsers,
|
||||
...(me?.login ? [me.login] : []),
|
||||
]);
|
||||
const pushUsernames = uniqueUsers(this.releaseBranchPushUsers);
|
||||
const mergeUsernames = uniqueUsers(this.releaseBranchMergeUsers);
|
||||
const pushTeams = uniqueUsers(this.releaseBranchPushTeams);
|
||||
const mergeTeams = uniqueUsers(this.releaseBranchMergeTeams);
|
||||
const hasPushWhitelist = pushUsernames.length > 0 || pushTeams.length > 0;
|
||||
const hasMergeWhitelist = mergeUsernames.length > 0 || mergeTeams.length > 0;
|
||||
|
||||
const body = {
|
||||
branch_name: 'release',
|
||||
enable_push: true,
|
||||
enable_push_whitelist: true,
|
||||
enable_push_whitelist: hasPushWhitelist,
|
||||
push_whitelist_usernames: pushUsernames,
|
||||
enable_merge_whitelist: true,
|
||||
merge_whitelist_usernames: mergeUsernames,
|
||||
push_whitelist_teams: pushTeams,
|
||||
enable_merge_whitelist: hasMergeWhitelist,
|
||||
merge_whitelist_usernames: hasMergeWhitelist ? mergeUsernames : [],
|
||||
merge_whitelist_teams: hasMergeWhitelist ? mergeTeams : [],
|
||||
enable_force_push: false,
|
||||
};
|
||||
|
||||
@@ -285,14 +292,6 @@ export class GiteaService {
|
||||
});
|
||||
}
|
||||
|
||||
private async getAuthenticatedUser() {
|
||||
try {
|
||||
return await this.request<{ login: string }>('/api/v1/user');
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async request<T>(
|
||||
path: string,
|
||||
init?: RequestInit & { allowedStatuses?: number[] },
|
||||
|
||||
Reference in New Issue
Block a user