Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 41x 41x 41x 41x 41x 41x 41x 41x 41x 1x 38x 38x 38x 1x 1x 1x 1x 1x 1x 1x 1x 38x 38x 6x 6x 6x 6x 32x 32x 38x 12x 1x 1x 12x 31x 31x 38x 20x 3x 3x 20x 28x 28x 38x 2x 2x 2x 2x 2x 26x 26x 38x 1x 1x 25x 25x 38x 1x | /**
* Acceptance Checker
*
* Evaluates whether a job should be accepted based on configured
* acceptance rules (recipe patterns, repository patterns, duration, Docker).
*/
import { AcceptanceRules } from './config/types.js';
export interface JobCandidate {
recipe?: string;
repository?: string;
estimatedDurationMinutes?: number;
requiresDocker?: boolean;
}
export interface AcceptanceDecision {
accepted: boolean;
reason?: string;
}
/**
* Simple glob matcher supporting * and ? wildcards.
* Avoids external dependency on minimatch.
*/
function globMatch(pattern: string, value: string): boolean {
// Convert glob to regex
const escaped = pattern
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex special chars (except * and ?)
.replace(/\*/g, '.*')
.replace(/\?/g, '.');
const regex = new RegExp(`^${escaped}$`, 'i');
return regex.test(value);
}
function matchesAny(patterns: string[], value: string): boolean {
return patterns.some(p => globMatch(p, value));
}
export class AcceptanceChecker {
constructor(private rules: AcceptanceRules) {}
/**
* Check if a job should be accepted based on the configured acceptance rules.
*/
shouldAccept(job: JobCandidate): AcceptanceDecision {
// Check blocked recipes first (takes precedence)
if (job.recipe && this.rules.blockedRecipes.length > 0) {
if (matchesAny(this.rules.blockedRecipes, job.recipe)) {
return { accepted: false, reason: `Recipe "${job.recipe}" is blocked` };
}
}
// Check allowed recipes
if (job.recipe && this.rules.allowedRecipes.length > 0) {
if (!matchesAny(this.rules.allowedRecipes, job.recipe)) {
return { accepted: false, reason: `Recipe "${job.recipe}" is not in allowed list` };
}
}
// Check allowed repositories
if (job.repository && this.rules.allowedRepositories.length > 0) {
if (!matchesAny(this.rules.allowedRepositories, job.repository)) {
return { accepted: false, reason: `Repository "${job.repository}" is not in allowed list` };
}
}
// Check max duration
if (job.estimatedDurationMinutes !== undefined && job.estimatedDurationMinutes > this.rules.maxJobDurationMinutes) {
return {
accepted: false,
reason: `Estimated duration (${job.estimatedDurationMinutes}m) exceeds max (${this.rules.maxJobDurationMinutes}m)`
};
}
// Check Docker requirement
if (this.rules.requireDocker && job.requiresDocker === false) {
return { accepted: false, reason: 'Agent requires Docker but job does not use Docker' };
}
return { accepted: true };
}
}
|