@@ -351,6 +351,122 @@ function getSetupSteps(checkSpecification: Specification): {
351351 return { inputs, steps } ;
352352}
353353
354+ /**
355+ * Generates an Actions job from the `checkSpecification`.
356+ *
357+ * @param specDocument
358+ * The raw YAML document of the PR check specification.
359+ * Used to extract `jobs` without losing the original formatting.
360+ * @param checkSpecification The PR check specification.
361+ * @returns The job and additional workflow inputs.
362+ */
363+ function generateJob (
364+ specDocument : yaml . Document ,
365+ checkSpecification : Specification ,
366+ ) {
367+ const matrix : Array < Record < string , any > > =
368+ generateJobMatrix ( checkSpecification ) ;
369+
370+ const useAllPlatformBundle = checkSpecification . useAllPlatformBundle
371+ ? checkSpecification . useAllPlatformBundle
372+ : "false" ;
373+
374+ // Determine which languages or frameworks have to be installed.
375+ const setupInfo = getSetupSteps ( checkSpecification ) ;
376+ const workflowInputs = setupInfo . inputs ;
377+
378+ // Construct the workflow steps needed for this check.
379+ const steps : any [ ] = [
380+ {
381+ name : "Check out repository" ,
382+ uses : "actions/checkout@v6" ,
383+ } ,
384+ {
385+ name : "Prepare test" ,
386+ id : "prepare-test" ,
387+ uses : "./.github/actions/prepare-test" ,
388+ with : {
389+ version : "${{ matrix.version }}" ,
390+ "use-all-platform-bundle" : useAllPlatformBundle ,
391+ // If the action is being run from a container, then do not setup kotlin.
392+ // This is because the kotlin binaries cannot be downloaded from the container.
393+ "setup-kotlin" : "container" in checkSpecification ? "false" : "true" ,
394+ } ,
395+ } ,
396+ ...setupInfo . steps ,
397+ ] ;
398+
399+ const installYq = checkSpecification . installYq ;
400+
401+ if ( installYq ) {
402+ steps . push ( {
403+ name : "Install yq" ,
404+ if : "runner.os == 'Windows'" ,
405+ env : {
406+ YQ_PATH : "${{ runner.temp }}/yq" ,
407+ // This is essentially an arbitrary version of `yq`, which happened to be the one that
408+ // `choco` fetched when we moved away from using that here.
409+ // See https://github.com/github/codeql-action/pull/3423
410+ YQ_VERSION : "v4.50.1" ,
411+ } ,
412+ run :
413+ 'gh release download --repo mikefarah/yq --pattern "yq_windows_amd64.exe" "$YQ_VERSION" -O "$YQ_PATH/yq.exe"\n' +
414+ 'echo "$YQ_PATH" >> "$GITHUB_PATH"' ,
415+ } ) ;
416+ }
417+
418+ // Extract the sequence of steps from the YAML document to persist as much formatting as possible.
419+ const specSteps = specDocument . get ( "steps" ) as yaml . YAMLSeq ;
420+
421+ // A handful of workflow specifications use double quotes for values, while we generally use single quotes.
422+ // This replaces double quotes with single quotes for consistency.
423+ yaml . visit ( specSteps , {
424+ Scalar ( _key , node ) {
425+ if ( node . type === "QUOTE_DOUBLE" ) {
426+ node . type = "QUOTE_SINGLE" ;
427+ }
428+ } ,
429+ } ) ;
430+
431+ // Add the generated steps in front of the ones from the specification.
432+ specSteps . items . unshift ( ...steps ) ;
433+
434+ const checkJob : Record < string , any > = {
435+ strategy : {
436+ "fail-fast" : false ,
437+ matrix : {
438+ include : matrix ,
439+ } ,
440+ } ,
441+ name : checkSpecification . name ,
442+ if : "github.triggering_actor != 'dependabot[bot]'" ,
443+ permissions : {
444+ contents : "read" ,
445+ "security-events" : "read" ,
446+ } ,
447+ "timeout-minutes" : 45 ,
448+ "runs-on" : "${{ matrix.os }}" ,
449+ steps : specSteps ,
450+ } ;
451+
452+ if ( checkSpecification . permissions ) {
453+ checkJob . permissions = checkSpecification . permissions ;
454+ }
455+
456+ for ( const key of [ "env" , "container" , "services" ] as const ) {
457+ if ( checkSpecification [ key ] !== undefined ) {
458+ checkJob [ key ] = checkSpecification [ key ] ;
459+ }
460+ }
461+
462+ checkJob . env = checkJob . env ?? { } ;
463+ if ( ! ( "CODEQL_ACTION_TEST_MODE" in checkJob . env ) ) {
464+ checkJob . env . CODEQL_ACTION_TEST_MODE = true ;
465+ }
466+
467+ return { checkJob, workflowInputs } ;
468+ }
469+
354470/**
355471 * Main entry point for the sync script.
356472 */
@@ -383,103 +499,10 @@ function main(): void {
383499
384500 console . log ( `Processing: ${ checkName } — "${ checkSpecification . name } "` ) ;
385501
386- const matrix : Array < Record < string , any > > = generateJobMatrix ( checkSpecification ) ;
387- const useAllPlatformBundle = checkSpecification . useAllPlatformBundle
388- ? checkSpecification . useAllPlatformBundle
389- : "false" ;
390-
391- // Determine which languages or frameworks have to be installed.
392- const setupInfo = getSetupSteps ( checkSpecification ) ;
393- const workflowInputs = setupInfo . inputs ;
394-
395- // Construct the workflow steps needed for this check.
396- const steps : any [ ] = [
397- {
398- name : "Check out repository" ,
399- uses : "actions/checkout@v6" ,
400- } ,
401- {
402- name : "Prepare test" ,
403- id : "prepare-test" ,
404- uses : "./.github/actions/prepare-test" ,
405- with : {
406- version : "${{ matrix.version }}" ,
407- "use-all-platform-bundle" : useAllPlatformBundle ,
408- // If the action is being run from a container, then do not setup kotlin.
409- // This is because the kotlin binaries cannot be downloaded from the container.
410- "setup-kotlin" : "container" in checkSpecification ? "false" : "true" ,
411- } ,
412- } ,
413- ...setupInfo . steps ,
414- ] ;
415-
416- const installYq = checkSpecification . installYq ;
417-
418- if ( installYq ) {
419- steps . push ( {
420- name : "Install yq" ,
421- if : "runner.os == 'Windows'" ,
422- env : {
423- YQ_PATH : "${{ runner.temp }}/yq" ,
424- // This is essentially an arbitrary version of `yq`, which happened to be the one that
425- // `choco` fetched when we moved away from using that here.
426- // See https://github.com/github/codeql-action/pull/3423
427- YQ_VERSION : "v4.50.1" ,
428- } ,
429- run :
430- 'gh release download --repo mikefarah/yq --pattern "yq_windows_amd64.exe" "$YQ_VERSION" -O "$YQ_PATH/yq.exe"\n' +
431- 'echo "$YQ_PATH" >> "$GITHUB_PATH"' ,
432- } ) ;
433- }
434-
435- // Extract the sequence of steps from the YAML document to persist as much formatting as possible.
436- const specSteps = specDocument . get ( "steps" ) as yaml . YAMLSeq ;
437-
438- // A handful of workflow specifications use double quotes for values, while we generally use single quotes.
439- // This replaces double quotes with single quotes for consistency.
440- yaml . visit ( specSteps , {
441- Scalar ( _key , node ) {
442- if ( node . type === "QUOTE_DOUBLE" ) {
443- node . type = "QUOTE_SINGLE" ;
444- }
445- } ,
446- } ) ;
447-
448- // Add the generated steps in front of the ones from the specification.
449- specSteps . items . unshift ( ...steps ) ;
450-
451- const checkJob : Record < string , any > = {
452- strategy : {
453- "fail-fast" : false ,
454- matrix : {
455- include : matrix ,
456- } ,
457- } ,
458- name : checkSpecification . name ,
459- if : "github.triggering_actor != 'dependabot[bot]'" ,
460- permissions : {
461- contents : "read" ,
462- "security-events" : "read" ,
463- } ,
464- "timeout-minutes" : 45 ,
465- "runs-on" : "${{ matrix.os }}" ,
466- steps : specSteps ,
467- } ;
468-
469- if ( checkSpecification . permissions ) {
470- checkJob . permissions = checkSpecification . permissions ;
471- }
472-
473- for ( const key of [ "env" , "container" , "services" ] as const ) {
474- if ( checkSpecification [ key ] !== undefined ) {
475- checkJob [ key ] = checkSpecification [ key ] ;
476- }
477- }
478-
479- checkJob . env = checkJob . env ?? { } ;
480- if ( ! ( "CODEQL_ACTION_TEST_MODE" in checkJob . env ) ) {
481- checkJob . env . CODEQL_ACTION_TEST_MODE = true ;
482- }
502+ const { checkJob, workflowInputs } = generateJob (
503+ specDocument ,
504+ checkSpecification ,
505+ ) ;
483506
484507 // If this check belongs to a named collection, record it.
485508 if ( checkSpecification . collection ) {
0 commit comments