Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/tests/book_agent_dispatch.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
const workflow = fs.readFileSync(path.join(__dirname, '../workflows/book_agent_dispatch.yml'), 'utf8');
const script = workflow.split(' script: |\n')[1].split('\n').map(line => line.slice(12)).join('\n');
const run = new AsyncFunction('github', 'context', 'core', script);

async function dispatch({ author = 'sarrus1811', mergeable = false, event = 'pull_request_target', probe = false } = {}) {
const calls = [];
const pr = { number: 3300, state: 'open', user: { login: author }, mergeable, draft: false, body: '', head: { ref: 'proposal' }, created_at: new Date().toISOString() };
const github = {
rest: {
pulls: { get: async () => ({ data: pr }), list: 'pulls', listFiles: 'files' },
issues: { listComments: 'comments' },
repos: { compareCommits: async () => ({ data: { files: [{ filename: 'src/page.md' }] } }) },
actions: { createWorkflowDispatch: async args => calls.push(args) },
},
paginate: async endpoint => {
if (endpoint === 'pulls') return [pr];
if (endpoint === 'files') { calls.push('inspect-files'); return [{ filename: 'src/page.md' }]; }
return [];
},
};
const context = { repo: { owner: 'HackTricks-wiki', repo: 'hacktricks' }, eventName: event, payload: { inputs: { pr: '3300', probe: String(probe) }, pull_request: { number: 3300 }, before: 'a'.repeat(40), after: 'b'.repeat(40) } };
await run(github, context, { info() {}, warning() {} });
return calls;
}

for (const event of ['pull_request_target', 'push', 'schedule', 'workflow_dispatch']) {
test(`${event}: skip other authors before file inspection or dispatch`, async () => {
assert.deepEqual(await dispatch({ event }), []);
});
}
test('unknown mergeability does not delay or dispatch another author', async () => {
assert.deepEqual(await dispatch({ mergeable: null }), []);
});
test('manual connection probes cannot dispatch another author', async () => {
assert.deepEqual(await dispatch({ event: 'workflow_dispatch', probe: true }), []);
});
test('owner conflicts still dispatch the fixer', async () => {
const calls = await dispatch({ author: 'Carlospolop' });
assert.equal(calls.length, 1);
assert.equal(calls[0].workflow_id, 'book-conflict-fix.yml');
});
test('clean owner PRs still dispatch review', async () => {
const calls = await dispatch({ author: 'carlospolop', mergeable: true });
assert.equal(calls.length, 1);
assert.equal(calls[0].workflow_id, 'book-pr-review.yml');
});
10 changes: 7 additions & 3 deletions .github/workflows/book_agent_dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
let pr;
for (let attempt = 0; attempt < (waitForMergeability ? 20 : 1); attempt++) {
pr = (await github.rest.pulls.get({...source, pull_number: number})).data;
if (pr.mergeable !== null || pr.state !== 'open') break;
if (pr.user?.login?.toLowerCase() !== 'carlospolop' || pr.mergeable !== null || pr.state !== 'open') break;
await sleep(3000);
}
return pr;
Expand All @@ -60,7 +60,7 @@ jobs:
}
async function route(number, reviewNew) {
const pr = await inspect(number, reviewNew);
if (pr.state !== 'open') return;
if (pr.state !== 'open' || pr.user?.login?.toLowerCase() !== 'carlospolop') return;
if (pr.mergeable === false || (reviewNew && pr.mergeable === null)) {
await dispatch('book-conflict-fix.yml', number);
if (pr.mergeable === null) core.warning(`Mergeability is still unknown for #${number}; the fixer will check the merge directly.`);
Expand All @@ -77,7 +77,10 @@ jobs:
const number = Number(context.payload.inputs.pr);
if (!Number.isSafeInteger(number) || number < 1) throw new Error('A valid PR number is required');
if (context.payload.inputs.probe === 'true') {
await dispatch('book-pr-review.yml', number, true);
const pr = await inspect(number, false);
if (pr.state === 'open' && pr.user?.login?.toLowerCase() === 'carlospolop') {
await dispatch('book-pr-review.yml', number, true);
}
} else {
await route(number, true);
}
Expand All @@ -99,6 +102,7 @@ jobs:
}
}
for (const pr of prs) {
if (pr.user?.login?.toLowerCase() !== 'carlospolop') continue;
if (changed !== null) {
if (!changed.size) continue;
const files = await github.paginate(github.rest.pulls.listFiles, {
Expand Down
Loading