mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 17:47:40 +00:00
62 lines
2.6 KiB
JavaScript
62 lines
2.6 KiB
JavaScript
import { readFileSync } from 'node:fs'
|
|
import { runInNewContext } from 'node:vm'
|
|
import { expect, it, vi } from 'vitest'
|
|
import { parse } from 'yaml'
|
|
|
|
const workflow = parse(readFileSync('.github/workflows/ci-branch-cache-sweep.yml', 'utf8'))
|
|
const step = workflow.jobs.sweep.steps[0]
|
|
const hoursAgo = (hours) => new Date(Date.now() - hours * 3600000).toISOString()
|
|
|
|
function sweep(caches, { dryRun = false, remove = vi.fn().mockResolvedValue(undefined) } = {}) {
|
|
const result = runInNewContext(`(async () => { ${step.with.script} })()`, {
|
|
context: { repo: { owner: 'owner', repo: 'repo' } },
|
|
github: {
|
|
paginate: vi.fn().mockResolvedValue(caches),
|
|
rest: { actions: { getActionsCacheList: vi.fn(), deleteActionsCacheById: remove } }
|
|
},
|
|
core: { info: vi.fn() },
|
|
process: { env: { DRY_RUN: String(dryRun) } }
|
|
})
|
|
return { result, remove }
|
|
}
|
|
|
|
it('runs trusted code on a schedule and only dry-runs by default when dispatched', () => {
|
|
expect(Object.keys(workflow.on)).toEqual(['schedule', 'workflow_dispatch'])
|
|
expect(workflow.on.workflow_dispatch.inputs.dry_run.default).toBe(true)
|
|
expect(workflow.permissions).toEqual({ actions: 'write' })
|
|
expect(workflow.jobs.sweep.steps).toHaveLength(1)
|
|
expect(step.env.DRY_RUN).toBe("${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}")
|
|
})
|
|
|
|
it('deletes only idle caches on non-default branches', async () => {
|
|
const { result, remove } = sweep([
|
|
{ id: 1, ref: 'refs/heads/scratch', last_accessed_at: hoursAgo(7) },
|
|
{ id: 2, ref: 'refs/heads/scratch', last_accessed_at: hoursAgo(1) },
|
|
{ id: 3, ref: 'refs/heads/main', last_accessed_at: hoursAgo(48) },
|
|
{ id: 4, ref: 'refs/pull/9/merge', last_accessed_at: hoursAgo(48) },
|
|
{ id: 5, ref: 'refs/tags/mobile-ios-v1.0.0', last_accessed_at: hoursAgo(48) },
|
|
{ id: 6, ref: 'refs/heads/other', last_accessed_at: 'not a date' }
|
|
])
|
|
await result
|
|
expect(remove.mock.calls).toEqual([[{ owner: 'owner', repo: 'repo', cache_id: 1 }]])
|
|
})
|
|
|
|
it('lists without deleting on a dry run', async () => {
|
|
const { result, remove } = sweep(
|
|
[{ id: 1, ref: 'refs/heads/scratch', last_accessed_at: hoursAgo(7) }],
|
|
{ dryRun: true }
|
|
)
|
|
await result
|
|
expect(remove).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('tolerates an eviction race but surfaces permission failures', async () => {
|
|
const idle = [{ id: 1, ref: 'refs/heads/scratch', last_accessed_at: hoursAgo(7) }]
|
|
await expect(
|
|
sweep(idle, { remove: vi.fn().mockRejectedValue({ status: 404 }) }).result
|
|
).resolves.toBeUndefined()
|
|
await expect(
|
|
sweep(idle, { remove: vi.fn().mockRejectedValue({ status: 403 }) }).result
|
|
).rejects.toEqual({ status: 403 })
|
|
})
|