@@ -17,6 +17,16 @@ const QUERIES_USES_PROPERTY = 'uses';
1717const PATHS_IGNORE_PROPERTY = 'paths-ignore' ;
1818const PATHS_PROPERTY = 'paths' ;
1919
20+ // All the languages supported by CodeQL
21+ const ALL_LANGUAGES = [ 'csharp' , 'cpp' , 'go' , 'java' , 'javascript' , 'python' ] as const ;
22+ type Language = ( typeof ALL_LANGUAGES ) [ number ] ;
23+
24+ // Some alternate names for languages
25+ const LANGUAGE_ALIASES : { [ name : string ] : Language } = {
26+ 'c' : 'cpp' ,
27+ 'typescript' : 'javascript' ,
28+ } ;
29+
2030/**
2131 * Format of the config file supplied by the user.
2232 */
@@ -38,7 +48,7 @@ export interface Config {
3848 /**
3949 * Set of languages to run analysis for.
4050 */
41- languages : string [ ] ;
51+ languages : Language [ ] ;
4252 /**
4353 * Map from language to query files.
4454 * Will only contain .ql files and not other kinds of files,
@@ -402,12 +412,21 @@ function getConfigFilePropertyError(configFile: string, property: string, error:
402412 return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error ;
403413}
404414
415+ export function getNoLanguagesError ( ) : string {
416+ return "Did not detect any languages to analyze. " +
417+ "Please update input in workflow or check that GitHub detects the correct languages in your repository." ;
418+ }
419+
420+ export function getUnknownLanguagesError ( languages : string [ ] ) : string {
421+ return "Did not recognise the following languages: " + languages . join ( ', ' ) ;
422+ }
423+
405424/**
406425 * Gets the set of languages in the current repository
407426 */
408- async function getLanguagesInRepo ( ) : Promise < string [ ] > {
427+ async function getLanguagesInRepo ( ) : Promise < Language [ ] > {
409428 // Translate between GitHub's API names for languages and ours
410- const codeqlLanguages = {
429+ const codeqlLanguages : { [ lang : string ] : Language } = {
411430 'C' : 'cpp' ,
412431 'C++' : 'cpp' ,
413432 'C#' : 'csharp' ,
@@ -423,18 +442,18 @@ async function getLanguagesInRepo(): Promise<string[]> {
423442 let repo = repo_nwo [ 1 ] ;
424443
425444 core . debug ( `GitHub repo ${ owner } ${ repo } ` ) ;
426- const response = await api . getApiClient ( true ) . request ( "GET / repos/:owner/:repo/languages" , ( {
445+ const response = await api . getApiClient ( true ) . repos . listLanguages ( {
427446 owner,
428447 repo
429- } ) ) ;
448+ } ) ;
430449
431450 core . debug ( "Languages API response: " + JSON . stringify ( response ) ) ;
432451
433452 // The GitHub API is going to return languages in order of popularity,
434453 // When we pick a language to autobuild we want to pick the most popular traced language
435454 // Since sets in javascript maintain insertion order, using a set here and then splatting it
436455 // into an array gives us an array of languages ordered by popularity
437- let languages : Set < string > = new Set ( ) ;
456+ let languages : Set < Language > = new Set ( ) ;
438457 for ( let lang in response . data ) {
439458 if ( lang in codeqlLanguages ) {
440459 languages . add ( codeqlLanguages [ lang ] ) ;
@@ -456,7 +475,7 @@ async function getLanguagesInRepo(): Promise<string[]> {
456475 * If no languages could be detected from either the workflow or the repository
457476 * then throw an error.
458477 */
459- async function getLanguages ( ) : Promise < string [ ] > {
478+ async function getLanguages ( ) : Promise < Language [ ] > {
460479
461480 // Obtain from action input 'languages' if set
462481 let languages = core . getInput ( 'languages' , { required : false } )
@@ -474,11 +493,32 @@ async function getLanguages(): Promise<string[]> {
474493 // If the languages parameter was not given and no languages were
475494 // detected then fail here as this is a workflow configuration error.
476495 if ( languages . length === 0 ) {
477- throw new Error ( "Did not detect any languages to analyze. " +
478- "Please update input in workflow or check that GitHub detects the correct languages in your repository." ) ;
496+ throw new Error ( getNoLanguagesError ( ) ) ;
497+ }
498+
499+ // Make sure they are supported
500+ const checkedLanguages : Language [ ] = [ ] ;
501+ const unknownLanguages : string [ ] = [ ] ;
502+ for ( let language of languages ) {
503+ // Normalise to lower case
504+ language = language . toLowerCase ( ) ;
505+ // Resolve any known aliases
506+ if ( language in LANGUAGE_ALIASES ) {
507+ language = LANGUAGE_ALIASES [ language ] ;
508+ }
509+
510+ const checkedLanguage = ALL_LANGUAGES . find ( l => l === language ) ;
511+ if ( checkedLanguage === undefined ) {
512+ unknownLanguages . push ( language ) ;
513+ } else if ( checkedLanguages . indexOf ( checkedLanguage ) === - 1 ) {
514+ checkedLanguages . push ( checkedLanguage ) ;
515+ }
516+ }
517+ if ( unknownLanguages . length > 0 ) {
518+ throw new Error ( getUnknownLanguagesError ( unknownLanguages ) ) ;
479519 }
480520
481- return languages ;
521+ return checkedLanguages ;
482522}
483523
484524/**
0 commit comments