Add approval rule management (#1233)

See: https://docs.gitlab.com/ee/api/merge_request_approvals.html

* Move Approval API into MergeRequestApprovals

Breaking change, see https://github.com/jdalrymple/gitbeaker/pull/1233#issuecomment-709262998
This commit is contained in:
Niklas Lochschmidt 2020-10-15 18:15:58 +00:00 committed by GitHub
parent bc827d88c4
commit d3cd35c5f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 425 additions and 183 deletions

View File

@ -250,6 +250,7 @@ IssueAwardEmojis
Jobs
Labels
MergeRequests
MergeRequestApprovals
MergeRequestAwardEmojis
MergeRequestDiscussions
MergeRequestNotes
@ -334,6 +335,7 @@ IssueAwardEmojis
Jobs
Labels
MergeRequests
MergeRequestApprovals
MergeRequestAwardEmojis
MergeRequestDiscussions
MergeRequestNotes

View File

@ -47,6 +47,7 @@ export const {
Jobs,
Labels,
MergeRequests,
MergeRequestApprovals,
MergeRequestAwardEmojis,
MergeRequestDiscussions,
MergeRequestNotes,

View File

@ -54,6 +54,7 @@ export const ProjectsBundle = bundler({
Jobs: APIServices.Jobs,
Labels: APIServices.Labels,
MergeRequests: APIServices.MergeRequests,
MergeRequestApprovals: APIServices.MergeRequestApprovals,
MergeRequestAwardEmojis: APIServices.MergeRequestAwardEmojis,
MergeRequestDiscussions: APIServices.MergeRequestDiscussions,
MergeRequestNotes: APIServices.MergeRequestNotes,

View File

@ -0,0 +1,179 @@
import { BaseService } from '@gitbeaker/requester-utils';
import { BaseRequestOptions, RequestHelper, Sudo } from '../infrastructure';
export type ApprovalRulesRequestOptions = {
userIds?: number[];
groupIds?: number[];
protectedBranchIds?: number[];
};
export class MergeRequestApprovals extends BaseService {
addApprovalRule(
projectId: string | number,
name: string,
approvalsRequired: number,
{
mergerequestIid,
...options
}: { mergerequestIid?: number } & ApprovalRulesRequestOptions & BaseRequestOptions,
) {
const pId = encodeURIComponent(projectId);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approval_rules`;
} else {
url = `projects/${pId}/approval_rules`;
}
return RequestHelper.post(this, url, { name, approvalsRequired, ...options });
}
approvalRules(
projectId: string | number,
{ mergerequestIid, ...options }: { mergerequestIid?: number } & BaseRequestOptions = {},
) {
const pId = encodeURIComponent(projectId);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approval_rules`;
} else {
url = `projects/${pId}/approval_rules`;
}
return RequestHelper.get(this, url, options);
}
approvals(
projectId: string | number,
{ mergerequestIid, ...options }: { mergerequestIid?: number } & BaseRequestOptions = {},
) {
const pId = encodeURIComponent(projectId);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approvals`;
} else {
url = `projects/${pId}/approvals`;
}
return RequestHelper.get(this, url, options);
}
approvalState(
projectId: string | number,
mergerequestIid: number,
options?: { sha?: string } & BaseRequestOptions,
) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);
return RequestHelper.get(
this,
`projects/${pId}/merge_requests/${mIid}/approval_state`,
options,
);
}
approve(
projectId: string | number,
mergerequestIid: number,
options?: { sha?: string } & BaseRequestOptions,
) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);
return RequestHelper.post(this, `projects/${pId}/merge_requests/${mIid}/approve`, options);
}
approvers(
projectId: string | number,
approverIds: number[],
approverGroupIds: (string | number)[],
{ mergerequestIid, ...options }: { mergerequestIid?: number } & BaseRequestOptions = {},
) {
const pId = encodeURIComponent(projectId);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approvers`;
} else {
url = `projects/${pId}/approvers`;
}
return RequestHelper.put(this, url, { approverIds, approverGroupIds, ...options });
}
editApprovalRule(
projectId: string | number,
approvalRuleId: number,
name: string,
approvalsRequired: number,
{
mergerequestIid,
...options
}: { mergerequestIid?: number } & ApprovalRulesRequestOptions & BaseRequestOptions = {},
) {
const [pId, aId] = [projectId, approvalRuleId].map(encodeURIComponent);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approval_rules/${aId}`;
} else {
url = `projects/${pId}/approval_rules/${aId}`;
}
return RequestHelper.put(this, url, { name, approvalsRequired, ...options });
}
editApprovals(
projectId: string | number,
{ mergerequestIid, ...options }: { mergerequestIid?: number } & BaseRequestOptions = {},
) {
const pId = encodeURIComponent(projectId);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approvals`;
} else {
url = `projects/${pId}/approvals`;
}
return RequestHelper.post(this, url, options);
}
removeApprovalRule(
projectId: string | number,
approvalRuleId: number,
{ mergerequestIid, ...options }: { mergerequestIid?: number } & BaseRequestOptions = {},
) {
const [pId, aId] = [projectId, approvalRuleId].map(encodeURIComponent);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approval_rules/${aId}`;
} else {
url = `projects/${pId}/approval_rules/${aId}`;
}
return RequestHelper.del(this, url, options);
}
unapprove(projectId: string | number, mergerequestIid: number, options?: Sudo) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);
return RequestHelper.post(this, `projects/${pId}/merge_requests/${mIid}/unapprove`, options);
}
}

View File

@ -131,68 +131,6 @@ export class MergeRequests extends BaseService {
return RequestHelper.get(this, url, options);
}
approve(
projectId: string | number,
mergerequestIid: number,
options?: { sha?: string } & BaseRequestOptions,
) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);
return RequestHelper.post(this, `projects/${pId}/merge_requests/${mIid}/approve`, options);
}
approvals(
projectId: string | number,
{ mergerequestIid, ...options }: { mergerequestIid?: number } & BaseRequestOptions = {},
) {
const pId = encodeURIComponent(projectId);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approvals`;
} else {
url = `projects/${pId}/approvals`;
}
return RequestHelper.get(this, url, options);
}
approvalState(
projectId: string | number,
mergerequestIid: number,
options?: { sha?: string } & BaseRequestOptions,
) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);
return RequestHelper.get(
this,
`projects/${pId}/merge_requests/${mIid}/approval_state`,
options,
);
}
approvers(
projectId: string | number,
approverIds: number[],
approverGroupIds: (string | number)[],
{ mergerequestIid, ...options }: { mergerequestIid?: number } & BaseRequestOptions = {},
) {
const pId = encodeURIComponent(projectId);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approvers`;
} else {
url = `projects/${pId}/approvers`;
}
return RequestHelper.put(this, url, { approverIds, approverGroupIds, ...options });
}
cancelOnPipelineSucess(projectId: string | number, mergerequestIid: number, options?: Sudo) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);
@ -249,24 +187,6 @@ export class MergeRequests extends BaseService {
return RequestHelper.put(this, `projects/${pId}/merge_requests/${mIid}`, options);
}
editApprovals(
projectId: string | number,
{ mergerequestIid, ...options }: { mergerequestIid?: number } & BaseRequestOptions = {},
) {
const pId = encodeURIComponent(projectId);
let url;
if (mergerequestIid) {
const mIid = encodeURIComponent(mergerequestIid);
url = `projects/${pId}/merge_requests/${mIid}/approvals`;
} else {
url = `projects/${pId}/approvals`;
}
return RequestHelper.post(this, url, options);
}
participants(projectId: string | number, mergerequestIid: number, options?: Sudo) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);
@ -349,12 +269,6 @@ export class MergeRequests extends BaseService {
return RequestHelper.get(this, `projects/${pId}/merge_requests/${mIid}/versions`, options);
}
unapprove(projectId: string | number, mergerequestIid: number, options?: Sudo) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);
return RequestHelper.post(this, `projects/${pId}/merge_requests/${mIid}/unapprove`, options);
}
unsubscribe(projectId: string | number, mergerequestIid: number, options?: Sudo) {
const [pId, mIid] = [projectId, mergerequestIid].map(encodeURIComponent);

View File

@ -41,6 +41,7 @@ export { IssueAwardEmojis } from './IssueAwardEmojis';
export { Jobs } from './Jobs';
export { Labels } from './Labels';
export { MergeRequests } from './MergeRequests';
export { MergeRequestApprovals } from './MergeRequestApprovals';
export { MergeRequestAwardEmojis } from './MergeRequestAwardEmojis';
export { MergeRequestDiscussions } from './MergeRequestDiscussions';
export { MergeRequestNotes } from './MergeRequestNotes';

View File

@ -17,6 +17,7 @@ test('All the correct service keys are included in the projects bundle', async (
'Jobs',
'Labels',
'MergeRequests',
'MergeRequestApprovals',
'MergeRequestAwardEmojis',
'MergeRequestDiscussions',
'MergeRequestNotes',

View File

@ -0,0 +1,239 @@
import { RequesterType } from '@gitbeaker/requester-utils';
import { RequestHelper } from '../../../src/infrastructure';
import { MergeRequestApprovals } from '../../../src';
jest.mock('../../../src/infrastructure/RequestHelper');
let service: MergeRequestApprovals;
beforeEach(() => {
const requester = {
get: jest.fn(() => Promise.resolve([])),
post: jest.fn(() => Promise.resolve({})),
put: jest.fn(() => Promise.resolve({})),
delete: jest.fn(() => Promise.resolve({})),
} as RequesterType;
service = new MergeRequestApprovals({
requester,
token: 'abcdefg',
requestTimeout: 3000,
});
});
describe('Instantiating MergeRequestApprovals service', () => {
it('should create a valid service object', async () => {
expect(service).toBeInstanceOf(MergeRequestApprovals);
expect(service.url).toBeDefined();
expect(service.rejectUnauthorized).toBeTruthy();
expect(service.headers).toMatchObject({ 'private-token': 'abcdefg' });
expect(service.requestTimeout).toBe(3000);
});
});
describe('MergeRequests.addApprovalRules', () => {
it('should request POST /projects/:id/approval_rules', async () => {
await service.addApprovalRule(2, 'Some rule', 5, {
userIds: [1, 2],
groupIds: [3, 4],
protectedBranchIds: [5, 6],
});
expect(RequestHelper.post).toHaveBeenCalledWith(service, 'projects/2/approval_rules', {
name: 'Some rule',
approvalsRequired: 5,
userIds: [1, 2],
groupIds: [3, 4],
protectedBranchIds: [5, 6],
});
});
it('should request POST /projects/:id/merge_requests/:merge_request_iid/approval_rules when mergerequestIid is passed', async () => {
await service.addApprovalRule(2, 'Some rule', 5, {
mergerequestIid: 3,
userIds: [1, 2],
groupIds: [3, 4],
});
expect(RequestHelper.post).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/approval_rules',
{
name: 'Some rule',
approvalsRequired: 5,
userIds: [1, 2],
groupIds: [3, 4],
},
);
});
});
describe('MergeRequests.approvals', () => {
it('should request GET /projects/:id/approvals', async () => {
await service.approvals(3);
expect(RequestHelper.get).toHaveBeenCalledWith(service, 'projects/3/approvals', {});
});
it('should request GET /projects/:id/merge_requests/:merge_request_iid/approvals when mergerequestIid Id is passed', async () => {
await service.approvals(3, { mergerequestIid: 1 });
expect(RequestHelper.get).toHaveBeenCalledWith(
service,
'projects/3/merge_requests/1/approvals',
{},
);
});
});
describe('MergeRequests.approvalRules', () => {
it('should request GET /projects/:id/approval_rules', async () => {
await service.approvalRules(2);
expect(RequestHelper.get).toHaveBeenCalledWith(service, 'projects/2/approval_rules', {});
});
it('should request GET /projects/:id/merge_requests/:merge_request_iid/approval_rules when mergerequestIid Id is passed', async () => {
await service.approvalRules(2, { mergerequestIid: 3 });
expect(RequestHelper.get).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/approval_rules',
{},
);
});
});
describe('MergeRequests.approvalState', () => {
it('should request GET /projects/:id/merge_requests/:merge_request_iid/approval_state', async () => {
await service.approvalState(2, 3);
expect(RequestHelper.get).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/approval_state',
undefined,
);
});
});
describe('MergeRequests.approve', () => {
it('should request POST /projects/:id/merge_requests/:merge_request_iid/approve', async () => {
await service.approve(2, 3);
expect(RequestHelper.post).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/approve',
undefined,
);
});
});
describe('MergeRequests.approvers', () => {
it('should request PUT /projects/:id/approvers', async () => {
await service.approvers(3, [4, 5], [6, 7]);
expect(RequestHelper.put).toHaveBeenCalledWith(service, 'projects/3/approvers', {
approverIds: [4, 5],
approverGroupIds: [6, 7],
});
});
it('should request PUT /projects/:id/merge_requests/:merge_request_iid/approvers when mergerequestIid Id is passed', async () => {
await service.approvers(3, [4, 5], [6, 7], {
approverIds: [4, 5],
approverGroupIds: [6, 7],
mergerequestIid: 1,
});
expect(RequestHelper.put).toHaveBeenCalledWith(
service,
'projects/3/merge_requests/1/approvers',
{ approverIds: [4, 5], approverGroupIds: [6, 7] },
);
});
});
describe('MergeRequests.editApprovalRules', () => {
it('should request PUT /projects/:id/approval_rules/:approval_rule_id', async () => {
await service.editApprovalRule(2, 30, 'Some rule', 5, {
userIds: [1, 2],
groupIds: [3, 4],
protectedBranchIds: [5, 6],
});
expect(RequestHelper.put).toHaveBeenCalledWith(service, 'projects/2/approval_rules/30', {
name: 'Some rule',
approvalsRequired: 5,
userIds: [1, 2],
groupIds: [3, 4],
protectedBranchIds: [5, 6],
});
});
it('should request PUT /projects/:id/merge_requests/:merge_request_iid/approval_rules/:approval_rule_id when mergerequestIid is passed', async () => {
await service.editApprovalRule(2, 30, 'Some rule', 5, {
mergerequestIid: 3,
userIds: [1, 2],
groupIds: [3, 4],
});
expect(RequestHelper.put).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/approval_rules/30',
{
name: 'Some rule',
approvalsRequired: 5,
userIds: [1, 2],
groupIds: [3, 4],
},
);
});
});
describe('MergeRequests.editApprovals', () => {
it('should request POST /projects/:id/approvals', async () => {
await service.editApprovals(3, { prop: 4 });
expect(RequestHelper.post).toHaveBeenCalledWith(service, 'projects/3/approvals', { prop: 4 });
});
it('should request POST /projects/:id/merge_requests/:merge_request_iid/approvals when mergerequestIid Id is passed', async () => {
await service.editApprovals(3, { mergerequestIid: 1, prop: 4 });
expect(RequestHelper.post).toHaveBeenCalledWith(
service,
'projects/3/merge_requests/1/approvals',
{ prop: 4 },
);
});
});
describe('MergeRequests.removeApprovalRules', () => {
it('should request DELETE /projects/:id/approval_rules/:approval_rule_id', async () => {
await service.removeApprovalRule(2, 30);
expect(RequestHelper.del).toHaveBeenCalledWith(service, 'projects/2/approval_rules/30', {});
});
it('should request DELETE /projects/:id/merge_requests/:merge_request_iid/approval_rules/:approval_rule_id when mergerequestIid is passed', async () => {
await service.removeApprovalRule(2, 30, { mergerequestIid: 3 });
expect(RequestHelper.del).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/approval_rules/30',
{},
);
});
});
describe('MergeRequests.unapprove', () => {
it('should request POST /projects/:id/merge_requests/:merge_request_iid/unapprove', async () => {
await service.unapprove(2, 3);
expect(RequestHelper.post).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/unapprove',
undefined,
);
});
});

View File

@ -91,73 +91,6 @@ describe('MergeRequests.all', () => {
});
});
describe('MergeRequests.approve', () => {
it('should request POST projects/:id/merge_requests:id/approve', async () => {
await service.approve(2, 3);
expect(RequestHelper.post).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/approve',
undefined,
);
});
});
describe('MergeRequests.approvals', () => {
it('should request GET /projects/:id/approvals', async () => {
await service.approvals(3);
expect(RequestHelper.get).toHaveBeenCalledWith(service, 'projects/3/approvals', {});
});
it('should request GET /projects/:id/merge_requests/:id when mergerequestIid Id is passed', async () => {
await service.approvals(3, { mergerequestIid: 1 });
expect(RequestHelper.get).toHaveBeenCalledWith(
service,
'projects/3/merge_requests/1/approvals',
{},
);
});
});
describe('MergeRequests.approvalState', () => {
it('should request GET projects/:id/merge_requests/:id/approval_state', async () => {
await service.approvalState(2, 3);
expect(RequestHelper.get).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/approval_state',
undefined,
);
});
});
describe('MergeRequests.approvers', () => {
it('should request PUT /projects/:id/approvers', async () => {
await service.approvers(3, [4, 5], [6, 7]);
expect(RequestHelper.put).toHaveBeenCalledWith(service, 'projects/3/approvers', {
approverIds: [4, 5],
approverGroupIds: [6, 7],
});
});
it('should request PUT /projects/:id/merge_requests/:id when mergerequestIid Id is passed', async () => {
await service.approvers(3, [4, 5], [6, 7], {
approverIds: [4, 5],
approverGroupIds: [6, 7],
mergerequestIid: 1,
});
expect(RequestHelper.put).toHaveBeenCalledWith(
service,
'projects/3/merge_requests/1/approvers',
{ approverIds: [4, 5], approverGroupIds: [6, 7] },
);
});
});
describe('MergeRequests.cancelOnPipelineSucess', () => {
it('should request PUT projects/:id/merge_requests/:id/cancel_merge_when_pipeline_succeeds', async () => {
await service.cancelOnPipelineSucess(2, 3);
@ -230,24 +163,6 @@ describe('MergeRequests.edit', () => {
});
});
describe('MergeRequests.editApprovals', () => {
it('should request POST /projects/:id/approvals', async () => {
await service.editApprovals(3, { prop: 4 });
expect(RequestHelper.post).toHaveBeenCalledWith(service, 'projects/3/approvals', { prop: 4 });
});
it('should request POST /projects/:id/merge_requests/:id when mergerequestIid Id is passed', async () => {
await service.editApprovals(3, { mergerequestIid: 1, prop: 4 });
expect(RequestHelper.post).toHaveBeenCalledWith(
service,
'projects/3/merge_requests/1/approvals',
{ prop: 4 },
);
});
});
describe('MergeRequests.participants', () => {
it('should request GET /projects/:id/merge_requests/:id/participants', async () => {
await service.participants(1, 2);
@ -368,18 +283,6 @@ describe('MergeRequests.versions', () => {
});
});
describe('MergeRequests.unapprove', () => {
it('should request POST projects/:id/merge_requests/:iid/unapprove', async () => {
await service.unapprove(2, 3);
expect(RequestHelper.post).toHaveBeenCalledWith(
service,
'projects/2/merge_requests/3/unapprove',
undefined,
);
});
});
describe('MergeRequests.unsubscribe', () => {
it('should request DEL projects/:id/merge_requests/:iid/unsubscribe', async () => {
await service.unsubscribe(2, 3);

View File

@ -47,6 +47,7 @@ export const {
Jobs,
Labels,
MergeRequests,
MergeRequestApprovals,
MergeRequestAwardEmojis,
MergeRequestDiscussions,
MergeRequestNotes,