feat(resolve-check-config): add ability to use a config file to adjust jobs (#255)

This commit is contained in:
Damien Retzinger
2026-05-17 17:15:09 -04:00
parent 0c7d14d885
commit b98313e100
26 changed files with 1324 additions and 0 deletions
@@ -0,0 +1,66 @@
import { EXTENSION_JOBS, KNOWN_JOBS_EXTENSION, resolveExtensionConfig } from './extension';
import { Matrix } from '../types';
const MATRIX: Matrix = {
include: [{
php: '8.3',
services: {
mysql: { image: 'mysql:8' },
opensearch: { image: 'opensearchproject/opensearch:2' },
},
}],
};
describe('EXTENSION_JOBS', () => {
it('declares the check-extension jobs', () => {
expect(Object.keys(EXTENSION_JOBS).sort()).toEqual([
'coding-standard',
'compile-extension',
'integration_test',
'unit-test-extension',
]);
});
it('keeps KNOWN_JOBS_EXTENSION in sync with the map keys', () => {
expect([...KNOWN_JOBS_EXTENSION].sort()).toEqual(Object.keys(EXTENSION_JOBS).sort());
});
});
describe('resolveExtensionConfig', () => {
it('emits every known job', () => {
const resolved = resolveExtensionConfig({}, MATRIX);
expect(Object.keys(resolved).sort()).toEqual([
'coding-standard',
'compile-extension',
'integration_test',
'unit-test-extension',
]);
});
it('emits services={} for every job under the current defaults', () => {
const resolved = resolveExtensionConfig({}, MATRIX);
for (const name of Object.keys(resolved)) {
expect(resolved[name].matrix.include[0].services).toEqual({});
}
});
it('still accepts a caller-supplied services override', () => {
const resolved = resolveExtensionConfig(
{ jobs: { integration_test: { services: ['search'] } } },
MATRIX,
);
expect(Object.keys(resolved['integration_test'].matrix.include[0].services!)).toEqual(['opensearch']);
});
it('throws on a typo in the job name', () => {
expect(() => resolveExtensionConfig({ jobs: { 'inteegration_test': false } }, MATRIX)).toThrowError(
/unknown job "inteegration_test" for kind "extension"/
);
});
it('throws when a store-only job name is used', () => {
expect(() => resolveExtensionConfig({ jobs: { 'smoke-test': false } }, MATRIX)).toThrowError(
/unknown job "smoke-test" for kind "extension"/
);
});
});
@@ -0,0 +1,26 @@
import { resolveJobs } from '../parse';
import { JobDefaults, Matrix, RawConfig, ResolvedConfig } from '../types';
/**
* Per-job defaults for the `check-extension.yaml` reusable workflow.
* Edit this map when a job is added, removed, or renamed in that
* workflow — keys are validated against caller config and the values
* supply the default tier list used when the caller doesn't override
* `services` themselves.
*/
export const EXTENSION_JOBS: Record<string, JobDefaults> = {
'unit-test-extension': { services: [] },
'compile-extension': { services: [] },
'coding-standard': { services: [] },
'integration_test': { services: [] },
};
export const KNOWN_JOBS_EXTENSION: readonly string[] = Object.keys(EXTENSION_JOBS);
/**
* Resolves a parsed config file + supported-version matrix against
* the check-extension job list. Thin wrapper that binds the kind and
* the per-job defaults so callers don't repeat the wiring.
*/
export const resolveExtensionConfig = (raw: RawConfig, matrix: Matrix): ResolvedConfig =>
resolveJobs(raw, 'extension', EXTENSION_JOBS, matrix);
@@ -0,0 +1,93 @@
import { KNOWN_JOBS_STORE, resolveStoreConfig, STORE_JOBS } from './store';
import { Matrix } from '../types';
const MATRIX: Matrix = {
include: [{
php: '8.3',
services: {
mysql: { image: 'mysql:8' },
opensearch: { image: 'opensearchproject/opensearch:2' },
rabbitmq: { image: 'rabbitmq:3' },
valkey: { image: 'valkey:8' },
nginx: { image: 'nginx:1.27' },
'php-fpm': { image: 'php:8.3-fpm' },
},
}],
};
describe('STORE_JOBS', () => {
it('declares the check-store jobs', () => {
expect(Object.keys(STORE_JOBS).sort()).toEqual(['coding-standard', 'smoke-test', 'unit-test']);
});
it('declares smoke-test required tiers (end-user cannot toggle)', () => {
expect(STORE_JOBS['smoke-test'].services).toEqual([]);
expect([...STORE_JOBS['smoke-test'].requiredServices!].sort()).toEqual([
'cache',
'db',
'queue',
'search',
'web',
]);
});
it('exposes empty service defaults for unit-test and coding-standard', () => {
expect(STORE_JOBS['unit-test'].services).toEqual([]);
expect(STORE_JOBS['coding-standard'].services).toEqual([]);
});
it('keeps KNOWN_JOBS_STORE in sync with the map keys', () => {
expect([...KNOWN_JOBS_STORE].sort()).toEqual(Object.keys(STORE_JOBS).sort());
});
});
describe('resolveStoreConfig', () => {
it('emits every known job with default tier expansion, always including mysql for smoke-test', () => {
const resolved = resolveStoreConfig({}, MATRIX);
expect(Object.keys(resolved).sort()).toEqual(['coding-standard', 'smoke-test', 'unit-test']);
expect(resolved['unit-test'].matrix.include[0].services).toEqual({});
expect(Object.keys(resolved['smoke-test'].matrix.include[0].services!).sort()).toEqual([
'mysql',
'nginx',
'opensearch',
'php-fpm',
'rabbitmq',
'valkey',
]);
});
it('keeps every required service even when caller overrides smoke-test services to []', () => {
const resolved = resolveStoreConfig(
{ jobs: { 'smoke-test': { services: [] } } },
MATRIX,
);
expect(Object.keys(resolved['smoke-test'].matrix.include[0].services!).sort()).toEqual([
'mysql',
'nginx',
'opensearch',
'php-fpm',
'rabbitmq',
'valkey',
]);
});
it('honors enabled=false for a job', () => {
const resolved = resolveStoreConfig(
{ jobs: { 'smoke-test': false } },
MATRIX,
);
expect(resolved['smoke-test'].enabled).toBe(false);
});
it('throws on a typo in the job name', () => {
expect(() => resolveStoreConfig({ jobs: { 'smkoe-test': false } }, MATRIX)).toThrowError(
/unknown job "smkoe-test" for kind "store"/
);
});
it('throws when an extension-only job name is used', () => {
expect(() => resolveStoreConfig({ jobs: { 'unit-test-extension': false } }, MATRIX)).toThrowError(
/unknown job "unit-test-extension" for kind "store"/
);
});
});
+28
View File
@@ -0,0 +1,28 @@
import { resolveJobs } from '../parse';
import { JobDefaults, Matrix, RawConfig, ResolvedConfig } from '../types';
/**
* Per-job defaults for the `check-store.yaml` reusable workflow.
* Edit this map when a job is added, removed, or renamed in that
* workflow — keys are validated against caller config and the values
* supply the default tier list used when the caller doesn't override
* `services` themselves.
*/
export const STORE_JOBS: Record<string, JobDefaults> = {
'unit-test': { services: [] },
'coding-standard': { services: [] },
'smoke-test': {
services: [],
requiredServices: ['db', 'search', 'queue', 'cache', 'web'],
},
};
export const KNOWN_JOBS_STORE: readonly string[] = Object.keys(STORE_JOBS);
/**
* Resolves a parsed config file + supported-version matrix against
* the check-store job list. Thin wrapper that binds the kind and the
* per-job defaults so callers don't repeat the wiring.
*/
export const resolveStoreConfig = (raw: RawConfig, matrix: Matrix): ResolvedConfig =>
resolveJobs(raw, 'store', STORE_JOBS, matrix);