Merge pull request #28686 from acierto/publish-gitlab-mr

Making publish:gitlab:merge-request idempotent
This commit is contained in:
Ben Lambert
2025-02-18 09:20:49 +01:00
committed by GitHub
4 changed files with 102 additions and 68 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
---
Making publish:gitlab:merge-request idempotent.
@@ -34,7 +34,7 @@ const mockGitlabClient = {
create: jest.fn(),
},
Commits: {
create: jest.fn(),
create: jest.fn(() => ({ id: 'mockId' })),
},
MergeRequests: {
create: jest.fn(async (_: any) => {
@@ -48,7 +48,7 @@ const mockGitlabClient = {
}),
},
Commits: {
create: jest.fn(),
create: jest.fn(() => ({ id: 'mockId' })),
},
MergeRequests: {
create: jest.fn(async (repoId: string) => {
@@ -287,7 +287,10 @@ describe('createGitLabMergeRequest', () => {
irrelevant: { 'bar.txt': 'Nothing to see here' },
},
});
const ctx = createMockActionContext({ input, workspacePath });
const ctx = createMockActionContext({
input,
workspacePath,
});
await instance.handler(ctx);
expect(mockGitlabClient.Projects.show).not.toHaveBeenCalled();
@@ -21,12 +21,12 @@ import {
serializeDirectoryContents,
} from '@backstage/plugin-scaffolder-node';
import {
Camelize,
CommitAction,
ExpandedMergeRequestSchema,
Gitlab,
RepositoryTreeSchema,
CommitAction,
SimpleUserSchema,
ExpandedMergeRequestSchema,
Camelize,
} from '@gitbeaker/rest';
import path from 'path';
import { ScmIntegrationRegistry } from '@backstage/integration';
@@ -302,7 +302,7 @@ which uses additional API calls in order to detect whether to 'create', 'update'
repoUrl,
});
let assigneeId = undefined;
let assigneeId: number | undefined = undefined;
if (assignee !== undefined) {
try {
@@ -439,74 +439,100 @@ which uses additional API calls in order to detect whether to 'create', 'update'
);
}
}
if (actions.length) {
try {
await api.Commits.create(repoID, branchName, title, actions);
} catch (e) {
throw new InputError(
`Committing the changes to ${branchName} failed. Please check that none of the files created by the template already exists. ${getErrorMessage(
e,
)}`,
);
}
}
try {
let mergeRequest = await api.MergeRequests.create(
repoID,
branchName,
String(targetBranch),
title,
{
description,
removeSourceBranch: removeSourceBranch ? removeSourceBranch : false,
assigneeId,
reviewerIds,
},
);
if (ctx.input.assignReviewersFromApprovalRules) {
try {
const reviewersFromApprovalRules =
await getReviewersFromApprovalRules(
api,
mergeRequest.iid,
await ctx.checkpoint({
key: `commit.to.${repoID}.${branchName}`,
fn: async () => {
if (actions.length) {
try {
const commit = await api.Commits.create(
repoID,
ctx,
branchName,
title,
actions,
);
if (reviewersFromApprovalRules.length > 0) {
const eligibleUserIds = new Set([
...reviewersFromApprovalRules,
...(reviewerIds ?? []),
]);
mergeRequest = await api.MergeRequests.edit(
repoID,
mergeRequest.iid,
{
reviewerIds: Array.from(eligibleUserIds),
},
return commit.id;
} catch (e) {
throw new InputError(
`Committing the changes to ${branchName} failed. Please check that none of the files created by the template already exists. ${getErrorMessage(
e,
)}`,
);
}
}
return null;
},
});
const { mrId, mrWebUrl } = await ctx.checkpoint({
key: `create.mr.${repoID}.${branchName}`,
fn: async () => {
try {
const mergeRequest = await api.MergeRequests.create(
repoID,
branchName,
String(targetBranch),
title,
{
description,
removeSourceBranch: removeSourceBranch
? removeSourceBranch
: false,
assigneeId,
reviewerIds,
},
);
return {
mrId: mergeRequest.iid,
mrWebUrl: mergeRequest.web_url ?? mergeRequest.webUrl,
};
} catch (e) {
ctx.logger.warn(
`Failed to assign reviewers from approval rules: ${getErrorMessage(
e,
)}.`,
throw new InputError(
`Merge request creation failed. ${getErrorMessage(e)}`,
);
}
}
ctx.output('projectid', repoID);
ctx.output('targetBranchName', targetBranch);
ctx.output('projectPath', repoID);
ctx.output(
'mergeRequestUrl',
mergeRequest.web_url ?? mergeRequest.webUrl,
);
} catch (e) {
throw new InputError(
`Merge request creation failed. ${getErrorMessage(e)}`,
);
}
},
});
await ctx.checkpoint({
key: `create.mr.assign.reviewers.${repoID}.${branchName}`,
fn: async () => {
if (ctx.input.assignReviewersFromApprovalRules) {
try {
const reviewersFromApprovalRules =
await getReviewersFromApprovalRules(api, mrId, repoID, ctx);
if (reviewersFromApprovalRules.length > 0) {
const eligibleUserIds = new Set([
...reviewersFromApprovalRules,
...(reviewerIds ?? []),
]);
const mergeRequest = await api.MergeRequests.edit(
repoID,
mrId,
{
reviewerIds: Array.from(eligibleUserIds),
},
);
return {
mrWebUrl: mergeRequest.web_url ?? mergeRequest.webUrl,
};
}
} catch (e) {
ctx.logger.warn(
`Failed to assign reviewers from approval rules: ${getErrorMessage(
e,
)}.`,
);
}
}
return { mrWebUrl };
},
});
ctx.output('projectid', repoID);
ctx.output('targetBranchName', targetBranch);
ctx.output('projectPath', repoID);
ctx.output('mergeRequestUrl', mrWebUrl);
},
});
};