@@ -13,6 +13,12 @@ import * as yaml from "yaml";
1313
1414import { OLDEST_SUPPORTED_MAJOR_VERSION } from "./config" ;
1515
16+ /** Identifies the CodeQL Action repository. */
17+ const codeqlActionRepo = {
18+ owner : "github" ,
19+ repo : "codeql-action" ,
20+ } ;
21+
1622/** Represents a configuration of which checks should not be set up as required checks. */
1723interface Exclusions {
1824 /** A list of strings that, if contained in a check name, are excluded. */
@@ -35,6 +41,86 @@ function getApiClient(token: string): ApiClient {
3541 return new githubUtils . GitHub ( opts ) ;
3642}
3743
44+ /**
45+ * Represents information about a check run. We track the `app_id` that generated the check,
46+ * because the API will require it in addition to the name in the future.
47+ */
48+ interface CheckInfo {
49+ /** The display name of the check. */
50+ context : string ;
51+ /** The ID of the app that generated the check. */
52+ app_id : number ;
53+ }
54+
55+ /** Removes entries from `checkInfos` based the configuration. */
56+ export function removeExcluded (
57+ exclusions : Exclusions ,
58+ checkInfos : CheckInfo [ ] ,
59+ ) : CheckInfo [ ] {
60+ console . log ( exclusions ) ;
61+
62+ return checkInfos . filter ( ( checkInfo ) => {
63+ if ( exclusions . is . includes ( checkInfo . context ) ) {
64+ console . info (
65+ `Excluding '${ checkInfo . context } ' because it is an exact exclusion.` ,
66+ ) ;
67+ return false ;
68+ }
69+
70+ for ( const containsStr of exclusions . contains ) {
71+ if ( checkInfo . context . includes ( containsStr ) ) {
72+ console . info (
73+ `Excluding '${ checkInfo . context } ' because it contains '${ containsStr } '.` ,
74+ ) ;
75+ return false ;
76+ }
77+ }
78+
79+ // Keep.
80+ return true ;
81+ } ) ;
82+ }
83+
84+ /** Gets a list of check run names for `ref`. */
85+ async function getChecksFor (
86+ client : ApiClient ,
87+ ref : string ,
88+ ) : Promise < CheckInfo [ ] > {
89+ console . info ( `Getting checks for '${ ref } '` ) ;
90+
91+ const response = await client . paginate (
92+ "GET /repos/{owner}/{repo}/commits/{ref}/check-runs" ,
93+ {
94+ ...codeqlActionRepo ,
95+ ref,
96+ } ,
97+ ) ;
98+
99+ if ( response . length === 0 ) {
100+ throw new Error ( `No checks found for '${ ref } '.` ) ;
101+ }
102+
103+ console . info ( `Retrieved ${ response . length } check runs.` ) ;
104+
105+ const notSkipped = response . filter (
106+ ( checkRun ) => checkRun . conclusion !== "skipped" ,
107+ ) ;
108+ console . info ( `Of those: ${ notSkipped . length } were not skipped.` ) ;
109+
110+ // We use the ID of the app that generated the check run when returned by the API,
111+ // but default to -1 to tell the API that any check with the given name should be
112+ // required.
113+ const checkInfos = notSkipped . map ( ( check ) => ( {
114+ context : check . name ,
115+ app_id : check . app ?. id || - 1 ,
116+ } ) ) ;
117+
118+ // Load the configuration for which checks to exclude and apply it before
119+ // returning the checks.
120+ const exclusions = loadExclusions ( ) ;
121+ return removeExcluded ( exclusions , checkInfos ) ;
122+ }
123+
38124async function main ( ) : Promise < void > {
39125 const { values : options } = parseArgs ( {
40126 options : {
@@ -69,6 +155,11 @@ async function main(): Promise<void> {
69155 // Initialise the API client.
70156 const client = getApiClient ( options . token ) ;
71157
158+ // Find the check runs for the specified `ref` that we will later set as the required checks
159+ // for the main and release branches.
160+ const checkInfos = await getChecksFor ( client , options . ref ) ;
161+ const checkNames = new Set ( checkInfos . map ( ( info ) => info . context ) ) ;
162+
72163 process . exit ( 0 ) ;
73164}
74165
0 commit comments