[ci-jobs] Add the optional property for jobs (#47261)

This commit is contained in:
Adrian Moldovan 2024-05-09 12:22:44 +03:00 committed by GitHub
parent 18e83a2467
commit 5591b25367
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 236 additions and 27 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Add the optional property for ci jobs

View File

@ -239,6 +239,7 @@
"name": "Core API tests", "name": "Core API tests",
"testType": "api", "testType": "api",
"command": "test:api-pw", "command": "test:api-pw",
"optional": false,
"changes": [ "changes": [
"client/admin/config/*.json", "client/admin/config/*.json",
"composer.lock", "composer.lock",
@ -259,6 +260,7 @@
"name": "Core API tests - HPOS disabled", "name": "Core API tests - HPOS disabled",
"testType": "api", "testType": "api",
"command": "test:api-pw", "command": "test:api-pw",
"optional": false,
"changes": [ "changes": [
"client/admin/config/*.json", "client/admin/config/*.json",
"composer.lock", "composer.lock",
@ -280,6 +282,7 @@
"name": "Core Performance tests (K6)", "name": "Core Performance tests (K6)",
"testType": "performance", "testType": "performance",
"command": "test:perf", "command": "test:perf",
"optional": true,
"changes": [ "changes": [
"client/admin/config/*.json", "client/admin/config/*.json",
"composer.lock", "composer.lock",
@ -299,6 +302,7 @@
"name": "Metrics", "name": "Metrics",
"testType": "performance", "testType": "performance",
"command": "test:metrics:ci", "command": "test:metrics:ci",
"optional": true,
"changes": [ "changes": [
"client/admin/config/*.json", "client/admin/config/*.json",
"composer.lock", "composer.lock",

File diff suppressed because one or more lines are too long

View File

@ -77,7 +77,10 @@ const program = new Command( 'ci-jobs' )
if ( jobs.lint.length > 0 ) { if ( jobs.lint.length > 0 ) {
Logger.notice( 'Lint Jobs' ); Logger.notice( 'Lint Jobs' );
for ( const job of jobs.lint ) { for ( const job of jobs.lint ) {
Logger.notice( `- ${ job.projectName } - ${ job.command }` ); const optional = job.optional ? '(optional)' : '';
Logger.notice(
`- ${ job.projectName } - ${ job.command }${ optional }`
);
} }
} else { } else {
Logger.notice( 'No lint jobs to run.' ); Logger.notice( 'No lint jobs to run.' );
@ -87,7 +90,10 @@ const program = new Command( 'ci-jobs' )
if ( jobs[ `${ type }Test` ].length > 0 ) { if ( jobs[ `${ type }Test` ].length > 0 ) {
Logger.notice( `${ type } test Jobs` ); Logger.notice( `${ type } test Jobs` );
for ( const job of jobs[ `${ type }Test` ] ) { for ( const job of jobs[ `${ type }Test` ] ) {
Logger.notice( `- ${ job.projectName } - ${ job.name }` ); const optional = job.optional ? ' (optional)' : '';
Logger.notice(
`- ${ job.projectName } - ${ job.name }${ optional }`
);
} }
} else { } else {
Logger.notice( `No ${ type } test jobs to run.` ); Logger.notice( `No ${ type } test jobs to run.` );

View File

@ -348,5 +348,90 @@ describe( 'Config', () => {
} ); } );
} }
); );
it( 'should return default optional value for jobs', () => {
const parsed = parseCIConfig( {
name: 'foo',
config: {
ci: {
lint: {
changes: [],
command: 'foo',
},
tests: [
{
name: 'default',
changes: [],
command: 'foo',
},
],
},
},
} );
expect( parsed ).toMatchObject( {
jobs: [
{
type: JobType.Lint,
optional: false,
},
{
type: JobType.Test,
optional: false,
},
],
} );
} );
it.each( [
[ true, true ],
[ false, false ],
] )(
'should parse config with values for the optional property',
( input, result ) => {
const parsed = parseCIConfig( {
name: 'foo',
config: {
ci: {
lint: {
changes: '/src/**/*.{js,jsx,ts,tsx}',
command: 'foo',
optional: input,
},
},
},
} );
expect( parsed ).toMatchObject( {
jobs: [
{
type: JobType.Lint,
optional: result,
},
],
} );
}
);
it.each( [ [ 'bad', 1, undefined ] ] )(
'should error for config with invalid values for the optional property',
( input ) => {
const expectation = () => {
parseCIConfig( {
name: 'foo',
config: {
ci: {
lint: {
changes: [],
command: 'some command',
optional: input,
},
},
},
} );
};
expect( expectation ).toThrow();
}
);
} ); } );
} ); } );

View File

@ -1085,6 +1085,94 @@ describe( 'Job Processing', () => {
expect( jobs.lint ).toHaveLength( 0 ); expect( jobs.lint ).toHaveLength( 0 );
expect( jobs.test ).toHaveLength( 0 ); expect( jobs.test ).toHaveLength( 0 );
} ); } );
it( 'should create non-optional lint job', async () => {
const jobs = await createJobsForChanges(
{
name: 'test',
path: 'test',
ciConfig: {
jobs: [
{
type: JobType.Lint,
changes: [ /test.js$/ ],
command: 'test-lint <baseRef>',
events: [],
optional: false,
},
],
},
dependencies: [],
},
{
test: [ 'test.js' ],
},
{
commandVars: {
baseRef: 'test-base-ref',
event: 'foo',
},
}
);
expect( jobs.lint ).toHaveLength( 1 );
expect( jobs.lint ).toContainEqual( {
projectName: 'test',
projectPath: 'test',
command: 'test-lint test-base-ref',
optional: false,
} );
expect( jobs.test ).toHaveLength( 0 );
} );
it( 'should create optional test job', async () => {
const testType = 'default';
const jobs = await createJobsForChanges(
{
name: 'test',
path: 'test',
ciConfig: {
jobs: [
{
type: JobType.Test,
testType,
name: 'Default',
shardingArguments: [],
changes: [ /test.js$/ ],
command: 'test-cmd <baseRef>',
optional: true,
events: [],
},
],
},
dependencies: [],
},
{
test: [ 'test.js' ],
},
{
commandVars: {
baseRef: 'test-base-ref',
event: 'foo',
},
}
);
expect( jobs.lint ).toHaveLength( 0 );
expect( jobs[ `${ testType }Test` ] ).toHaveLength( 1 );
expect( jobs[ `${ testType }Test` ] ).toContainEqual( {
projectName: 'test',
projectPath: 'test',
name: 'Default',
command: 'test-cmd test-base-ref',
shardNumber: 0,
testEnv: {
shouldCreate: false,
envVars: {},
},
optional: true,
} );
} );
} ); } );
describe( 'getShardedJobs', () => { describe( 'getShardedJobs', () => {
@ -1100,6 +1188,7 @@ describe( 'Job Processing', () => {
shouldCreate: false, shouldCreate: false,
envVars: {}, envVars: {},
}, },
optional: false,
}, },
{ {
type: JobType.Test, type: JobType.Test,
@ -1121,6 +1210,7 @@ describe( 'Job Processing', () => {
name: 'Default 1/2', name: 'Default 1/2',
command: 'test-cmd --shard-arg-1', command: 'test-cmd --shard-arg-1',
shardNumber: 1, shardNumber: 1,
optional: false,
testEnv: { testEnv: {
shouldCreate: false, shouldCreate: false,
envVars: {}, envVars: {},
@ -1132,6 +1222,7 @@ describe( 'Job Processing', () => {
name: 'Default 2/2', name: 'Default 2/2',
command: 'test-cmd --shard-arg-2', command: 'test-cmd --shard-arg-2',
shardNumber: 2, shardNumber: 2,
optional: false,
testEnv: { testEnv: {
shouldCreate: false, shouldCreate: false,
envVars: {}, envVars: {},
@ -1155,6 +1246,7 @@ describe( 'Job Processing', () => {
shouldCreate: false, shouldCreate: false,
envVars: {}, envVars: {},
}, },
optional: false,
}, },
{ {
type: JobType.Test, type: JobType.Test,
@ -1174,6 +1266,7 @@ describe( 'Job Processing', () => {
name: 'Default', name: 'Default',
command: 'test-cmd', command: 'test-cmd',
shardNumber: 0, shardNumber: 0,
optional: false,
testEnv: { testEnv: {
shouldCreate: false, shouldCreate: false,
envVars: {}, envVars: {},

View File

@ -60,6 +60,11 @@ interface BaseJobConfig {
*/ */
events: string[]; events: string[];
/**
* Indicates whether a job should be required to pass in CI for merging to be allowed.
*/
optional?: boolean;
/** /**
* Indicates whether or not a job has been created for this config. * Indicates whether or not a job has been created for this config.
*/ */
@ -166,30 +171,52 @@ function validateCommandVars( command: string ) {
} }
/** /**
* Parses the lint job configuration. * Parses the base job configuration.
* *
* @param {Object} raw The raw config to parse. * @param {Object} raw The raw config to parse.
*/ */
function parseLintJobConfig( raw: any ): LintJobConfig { function parseBaseJobConfig( raw: any ): BaseJobConfig {
if ( ! raw.changes ) { if ( ! raw.changes ) {
throw new ConfigError( throw new ConfigError( 'A "changes" option is required for the job.' );
'A "changes" option is required for the lint job.'
);
} }
if ( ! raw.command || typeof raw.command !== 'string' ) { if ( ! raw.command || typeof raw.command !== 'string' ) {
throw new ConfigError( throw new ConfigError(
'A string "command" option is required for the lint job.' 'A string "command" option is required for the job.'
); );
} }
validateCommandVars( raw.command ); validateCommandVars( raw.command );
let optional = false;
if ( raw.optional ) {
if ( typeof raw.optional !== 'boolean' ) {
throw new ConfigError(
'The "optional" property must be a boolean.'
);
}
optional = raw.optional;
}
return { return {
type: JobType.Lint, type: null,
changes: parseChangesConfig( raw.changes, [ 'package.json' ] ), changes: parseChangesConfig( raw.changes, [ 'package.json' ] ),
command: raw.command, command: raw.command,
events: raw.events || [], events: raw.events || [],
optional,
};
}
/**
* Parses the lint job configuration.
*
* @param {Object} raw The raw config to parse.
*/
function parseLintJobConfig( raw: any ): LintJobConfig {
const baseJob = parseBaseJobConfig( raw );
return {
...baseJob,
type: JobType.Lint,
}; };
} }
@ -325,24 +352,14 @@ function parseTestCascade( raw: unknown ): string[] {
* @param {Object} raw The raw config to parse. * @param {Object} raw The raw config to parse.
*/ */
function parseTestJobConfig( raw: any ): TestJobConfig { function parseTestJobConfig( raw: any ): TestJobConfig {
const baseJob = parseBaseJobConfig( raw );
if ( ! raw.name || typeof raw.name !== 'string' ) { if ( ! raw.name || typeof raw.name !== 'string' ) {
throw new ConfigError( throw new ConfigError(
'A string "name" option is required for test jobs.' 'A string "name" option is required for test jobs.'
); );
} }
if ( ! raw.changes ) {
throw new ConfigError(
'A "changes" option is required for the test jobs.'
);
}
if ( ! raw.command || typeof raw.command !== 'string' ) {
throw new ConfigError(
'A string "command" option is required for the test jobs.'
);
}
let testType: ( typeof testTypes )[ number ] = 'default'; let testType: ( typeof testTypes )[ number ] = 'default';
if ( if (
raw.testType && raw.testType &&
@ -351,16 +368,12 @@ function parseTestJobConfig( raw: any ): TestJobConfig {
testType = raw.testType.toLowerCase(); testType = raw.testType.toLowerCase();
} }
validateCommandVars( raw.command );
const config: TestJobConfig = { const config: TestJobConfig = {
...baseJob,
type: JobType.Test, type: JobType.Test,
testType, testType,
shardingArguments: raw.shardingArguments || [], shardingArguments: raw.shardingArguments || [],
events: raw.events || [],
name: raw.name, name: raw.name,
changes: parseChangesConfig( raw.changes, [ 'package.json' ] ),
command: raw.command,
}; };
if ( raw.testEnv ) { if ( raw.testEnv ) {

View File

@ -19,6 +19,7 @@ interface LintJob {
projectName: string; projectName: string;
projectPath: string; projectPath: string;
command: string; command: string;
optional: boolean;
} }
/** /**
@ -40,6 +41,7 @@ interface TestJob {
command: string; command: string;
testEnv: TestJobEnv; testEnv: TestJobEnv;
shardNumber: number; shardNumber: number;
optional: boolean;
} }
/** /**
@ -153,6 +155,7 @@ function createLintJob(
projectName, projectName,
projectPath, projectPath,
command: replaceCommandVars( config.command, options ), command: replaceCommandVars( config.command, options ),
optional: config.optional,
}; };
} }
@ -228,6 +231,7 @@ async function createTestJob(
envVars: {}, envVars: {},
}, },
shardNumber, shardNumber,
optional: config.optional,
}; };
// We want to make sure that we're including the configuration for // We want to make sure that we're including the configuration for