Files

127 lines
3.9 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { coordinate } from '../dispatch-comment-builds.mjs';
import { readReceipt } from '../comment-queue.mjs';
// The queue asks the API for this Issue's own PRs (by head) and for the open
// PRs on a non-shared target branch (by base), instead of listing every PR of
// the repository on each reconcile.
const bot = { login: 'github-actions[bot]', type: 'Bot' };
const owner = { login: 'gchust', type: 'User' };
const issue = {
number: 2,
state: 'open',
user: owner,
author_association: 'OWNER',
body: '### 目标分支\napps/demo\n### 任务类型\n创建新系统\n### 业务需求\nOriginal\n### 验收要求\nWorks',
};
const pulls = [
{
number: 10,
state: 'open',
head: { ref: 'agent/issue-2', repo: { full_name: 'gchust/nb3-factory' } },
base: { ref: 'apps/demo' },
},
{
number: 11,
state: 'open',
head: { ref: 'agent/issue-7', repo: { full_name: 'gchust/nb3-factory' } },
base: { ref: 'apps/demo' },
},
{
number: 12,
state: 'closed',
head: { ref: 'agent/issue-9', repo: { full_name: 'gchust/nb3-factory' } },
base: { ref: 'develop' },
},
];
function fixture() {
const comments = [
{
id: 22,
body: '/build\nFeature 22',
user: owner,
author_association: 'OWNER',
},
];
const calls = [];
const client = {
repository: 'gchust/nb3-factory',
getIssue: async () => issue,
getRepository: async () => ({ default_branch: 'develop' }),
getRef: async () => null,
async addComment(number, body) {
const value = { id: 1000 + comments.length, body, user: bot };
comments.push(value);
return value;
},
async request(method, route, options = {}) {
calls.push({ method, route, ...options });
if (route === '/issues/2/comments') return [...comments];
if (method === 'PATCH' && route.startsWith('/issues/comments/')) {
const comment = comments.find(
(item) => item.id === Number(route.split('/').pop()),
);
comment.body = options.body.body;
return comment;
}
if (route === '/actions/workflows/code-agent-task.yml/runs')
return {
workflow_runs: [
{
id: 1,
display_title: 'Factory issue #2 build 0',
status: 'completed',
conclusion: 'success',
run_attempt: 1,
},
],
};
if (route.endsWith('/jobs')) return { jobs: [] };
if (route === '/pulls') {
const { head, base, state } = options.query ?? {};
return pulls.filter(
(pull) =>
(!head || head === `gchust:${pull.head.ref}`) &&
(!base || base === pull.base.ref) &&
(state === 'all' || pull.state === state),
);
}
if (route === '/dispatches') return null;
throw new Error(`Unexpected request ${method} ${route}`);
},
};
return { client, comments, calls };
}
test('the comment queue asks only for its own PRs and the open PRs on its branch', async () => {
const f = fixture();
await coordinate(f.client, 2, 0);
const listings = f.calls.filter((call) => call.route === '/pulls');
assert.ok(listings.length >= 1);
for (const call of listings)
assert.ok(
call.query.head || call.query.base,
`unfiltered PR listing: ${JSON.stringify(call.query)}`,
);
assert.ok(
listings.some(
(call) =>
call.query.head === 'gchust:agent/issue-2' &&
call.query.state === 'all',
),
);
assert.ok(
listings.some(
(call) => call.query.base === 'apps/demo' && call.query.state === 'open',
),
);
// Another Issue's open PR on the same non-shared branch still holds the queue.
assert.equal(
f.calls.filter((call) => call.route === '/dispatches').length,
0,
);
assert.equal(f.comments.map(readReceipt).filter(Boolean)[0].status, 'queued');
});