also looking at this
fix(ci): restore dependency bot scheduled job selection
#309
3 files
+72
-10
| @@ -0,0 +1,52 @@ | ||
| 1 | import { expect, test } from 'bun:test' | |
| 2 | import { mkdtempSync, readFileSync, rmSync } from 'node:fs' | |
| 3 | import { tmpdir } from 'node:os' | |
| 4 | import { join } from 'node:path' | |
| 5 | ||
| 6 | const workflow = Bun.YAML.parse(readFileSync(join(import.meta.dir, '../.github/workflows/buddy-bot.yml'), 'utf8')) as any | |
| 7 | const selector = workflow.jobs['determine-jobs'].steps.find((step: any) => step.id === 'determine') | |
| 8 | ||
| 9 | function select(event: string, schedule = '', job = '') { | |
| 10 | const directory = mkdtempSync(join(tmpdir(), 'craft-buddy-schedule-')) | |
| 11 | try { | |
| 12 | const output = join(directory, 'output') | |
| 13 | // Substitute the old workflow's expressions too, so this executes the | |
| 14 | // actual selector before and after its move to environment variables. | |
| 15 | const script = selector.run | |
| 16 | .replaceAll('$', event) | |
| 17 | .replaceAll('$', schedule) | |
| 18 | .replaceAll("$", job || 'all') | |
| 19 | const result = Bun.spawnSync(['/bin/bash', '-eo', 'pipefail', '-c', script], { | |
| 20 | env: { ...process.env, GITHUB_OUTPUT: output, EVENT_NAME: event, EVENT_SCHEDULE: schedule, REQUESTED_JOB: job }, | |
| 21 | stdout: 'pipe', stderr: 'pipe', | |
| 22 | }) | |
| 23 | const values = Object.fromEntries(readFileSync(output, 'utf8').trim().split('\n').map(line => line.split('='))) | |
| 24 | return { exitCode: result.exitCode, values } | |
| 25 | } | |
| 26 | finally { rmSync(directory, { recursive: true, force: true }) } | |
| 27 | } | |
| 28 | ||
| 29 | test('every declared schedule selects exactly its intended job', () => { | |
| 30 | const expected = { '0 * * * *': 'check', '0 3,15 * * *': 'update', '15 3,15 * * *': 'dashboard' } | |
| 31 | expect(workflow.on.schedule.map((item: any) => item.cron).sort()).toEqual(Object.keys(expected).sort()) | |
| 32 | for (const [cron, job] of Object.entries(expected)) { | |
| 33 | const result = select('schedule', cron) | |
| 34 | expect(result.exitCode).toBe(0) | |
| 35 | expect(result.values).toEqual({ run_check: String(job === 'check'), run_update: String(job === 'update'), run_dashboard: String(job === 'dashboard') }) | |
| 36 | } | |
| 37 | }) | |
| 38 | ||
| 39 | test('manual dispatch preserves individual jobs and the all/default choice', () => { | |
| 40 | expect(selector.env).toEqual({ EVENT_NAME: '$', EVENT_SCHEDULE: '$', REQUESTED_JOB: '$' }) | |
| 41 | expect(readFileSync(join(import.meta.dir, '../.github/workflows/buddy-bot.yml'), 'utf8')).not.toContain('github.event.inputs.pin') | |
| 42 | for (const job of ['', 'all', 'check', 'update', 'dashboard']) { | |
| 43 | const result = select('workflow_dispatch', '', job) | |
| 44 | expect(result.exitCode).toBe(0) | |
| 45 | expect(result.values).toEqual(Object.fromEntries(['check', 'update', 'dashboard'].map(name => [`run_${name}`, String(!job || job === 'all' || name === job)]))) | |
| 46 | } | |
| 47 | }) | |
| 48 | ||
| 49 | test('unknown schedules and jobs fail visibly instead of silently doing nothing', () => { | |
| 50 | expect(select('schedule', '*/1 * * * *').exitCode).not.toBe(0) | |
| 51 | expect(select('workflow_dispatch', '', 'typo').exitCode).not.toBe(0) | |
| 52 | }) | |