mirror of
https://github.com/actions/labeler
synced 2026-09-04 11:05:09 +02:00
* Preserve externally managed pull request labels Replace whole-set label writes with batched selective additions and removals so sync-labels only manages configured labels. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 44452010-1cd5-4e90-8abe-f03547c04182 * Reconcile ambiguous label addition failures Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 44452010-1cd5-4e90-8abe-f03547c04182 * Handle paginated label reconciliation Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 44452010-1cd5-4e90-8abe-f03547c04182 --------- Copilot-Session: 44452010-1cd5-4e90-8abe-f03547c04182
132 lines
4.2 KiB
TypeScript
132 lines
4.2 KiB
TypeScript
import {jest, describe, it, expect} from '@jest/globals';
|
|
import type {ClientType} from '../src/api/types.js';
|
|
|
|
jest.unstable_mockModule('@actions/github', () => ({
|
|
context: {
|
|
repo: {owner: 'monalisa', repo: 'helloworld'}
|
|
}
|
|
}));
|
|
|
|
const {addLabels} = await import('../src/api/add-labels.js');
|
|
|
|
const createClient = () => {
|
|
const addLabelsMock = jest.fn<any>();
|
|
const listLabelsOnIssueMock = jest.fn<any>();
|
|
const client = {
|
|
rest: {
|
|
issues: {
|
|
addLabels: addLabelsMock,
|
|
listLabelsOnIssue: listLabelsOnIssueMock
|
|
}
|
|
}
|
|
} as ClientType;
|
|
|
|
return {client, addLabelsMock, listLabelsOnIssueMock};
|
|
};
|
|
|
|
describe('addLabels', () => {
|
|
it('does not verify a successful addition', async () => {
|
|
const {client, addLabelsMock, listLabelsOnIssueMock} = createClient();
|
|
addLabelsMock.mockResolvedValue({data: []});
|
|
|
|
await addLabels(client, 123, ['bug']);
|
|
|
|
expect(addLabelsMock).toHaveBeenCalledWith({
|
|
owner: 'monalisa',
|
|
repo: 'helloworld',
|
|
issue_number: 123,
|
|
labels: ['bug'],
|
|
request: {retries: 0}
|
|
});
|
|
expect(listLabelsOnIssueMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('accepts a server error when every requested label was committed', async () => {
|
|
const {client, addLabelsMock, listLabelsOnIssueMock} = createClient();
|
|
const serverError = Object.assign(new Error('Bad Gateway'), {status: 502});
|
|
addLabelsMock.mockRejectedValue(serverError);
|
|
listLabelsOnIssueMock.mockResolvedValue({
|
|
data: [{name: 'BUG'}, {name: 'documentation'}],
|
|
headers: {}
|
|
});
|
|
|
|
await expect(
|
|
addLabels(client, 123, ['bug', 'documentation'])
|
|
).resolves.toBeUndefined();
|
|
expect(listLabelsOnIssueMock).toHaveBeenCalledWith({
|
|
owner: 'monalisa',
|
|
repo: 'helloworld',
|
|
issue_number: 123,
|
|
per_page: 100,
|
|
page: 1,
|
|
request: {retries: 0}
|
|
});
|
|
});
|
|
|
|
it('checks subsequent pages after a committed server error', async () => {
|
|
const {client, addLabelsMock, listLabelsOnIssueMock} = createClient();
|
|
const serverError = Object.assign(new Error('Bad Gateway'), {status: 502});
|
|
addLabelsMock.mockRejectedValue(serverError);
|
|
listLabelsOnIssueMock
|
|
.mockResolvedValueOnce({
|
|
data: Array.from({length: 100}, (_, index) => ({
|
|
name: `label-${index}`
|
|
})),
|
|
headers: {
|
|
link: '<https://api.github.com/issues/123/labels?page=2>; rel="next"'
|
|
}
|
|
})
|
|
.mockResolvedValueOnce({
|
|
data: [{name: 'documentation'}],
|
|
headers: {}
|
|
});
|
|
|
|
await expect(
|
|
addLabels(client, 123, ['label-0', 'documentation'])
|
|
).resolves.toBeUndefined();
|
|
expect(listLabelsOnIssueMock).toHaveBeenNthCalledWith(2, {
|
|
owner: 'monalisa',
|
|
repo: 'helloworld',
|
|
issue_number: 123,
|
|
per_page: 100,
|
|
page: 2,
|
|
request: {retries: 0}
|
|
});
|
|
});
|
|
|
|
it('preserves a server error when any requested label is missing', async () => {
|
|
const {client, addLabelsMock, listLabelsOnIssueMock} = createClient();
|
|
const serverError = Object.assign(new Error('Bad Gateway'), {status: 502});
|
|
addLabelsMock.mockRejectedValue(serverError);
|
|
listLabelsOnIssueMock.mockResolvedValue({
|
|
data: [{name: 'bug'}],
|
|
headers: {}
|
|
});
|
|
|
|
await expect(addLabels(client, 123, ['bug', 'documentation'])).rejects.toBe(
|
|
serverError
|
|
);
|
|
expect(listLabelsOnIssueMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('does not verify non-server errors', async () => {
|
|
const {client, addLabelsMock, listLabelsOnIssueMock} = createClient();
|
|
const validationError = Object.assign(new Error('Validation Failed'), {
|
|
status: 422
|
|
});
|
|
addLabelsMock.mockRejectedValue(validationError);
|
|
|
|
await expect(addLabels(client, 123, ['bug'])).rejects.toBe(validationError);
|
|
expect(listLabelsOnIssueMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('preserves the server error when verification fails', async () => {
|
|
const {client, addLabelsMock, listLabelsOnIssueMock} = createClient();
|
|
const serverError = Object.assign(new Error('Bad Gateway'), {status: 502});
|
|
addLabelsMock.mockRejectedValue(serverError);
|
|
listLabelsOnIssueMock.mockRejectedValue(new Error('Service unavailable'));
|
|
|
|
await expect(addLabels(client, 123, ['bug'])).rejects.toBe(serverError);
|
|
});
|
|
});
|