@@ -16,6 +16,16 @@ const QUERIES_USES_PROPERTY = 'uses';
1616const PATHS_IGNORE_PROPERTY = 'paths-ignore' ;
1717const PATHS_PROPERTY = 'paths' ;
1818
19+ // All the languages supported by CodeQL
20+ const ALL_LANGUAGES = [ 'csharp' , 'cpp' , 'go' , 'java' , 'javascript' , 'python' ] as const ;
21+ type Language = ( typeof ALL_LANGUAGES ) [ number ] ;
22+
23+ // Some alternate names for languages
24+ const LANGUAGE_ALIASES : { [ name : string ] : Language } = {
25+ 'c' : 'cpp' ,
26+ 'typescript' : 'javascript' ,
27+ } ;
28+
1929/**
2030 * Format of the config file supplied by the user.
2131 */
@@ -37,7 +47,7 @@ export interface Config {
3747 /**
3848 * Set of languages to run analysis for.
3949 */
40- languages : string [ ] ;
50+ languages : Language [ ] ;
4151 /**
4252 * Map from language to query files.
4353 * Will only contain .ql files and not other kinds of files,
@@ -401,12 +411,21 @@ function getConfigFilePropertyError(configFile: string, property: string, error:
401411 return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error ;
402412}
403413
414+ export function getNoLanguagesError ( ) : string {
415+ return "Did not detect any languages to analyze. " +
416+ "Please update input in workflow or check that GitHub detects the correct languages in your repository." ;
417+ }
418+
419+ export function getUnknownLanguagesError ( languages : string [ ] ) : string {
420+ return "Did not recognise the following languages: " + languages . join ( ', ' ) ;
421+ }
422+
404423/**
405424 * Gets the set of languages in the current repository
406425 */
407- async function getLanguagesInRepo ( ) : Promise < string [ ] > {
426+ async function getLanguagesInRepo ( ) : Promise < Language [ ] > {
408427 // Translate between GitHub's API names for languages and ours
409- const codeqlLanguages = {
428+ const codeqlLanguages : { [ lang : string ] : Language } = {
410429 'C' : 'cpp' ,
411430 'C++' : 'cpp' ,
412431 'C#' : 'csharp' ,
@@ -422,18 +441,18 @@ async function getLanguagesInRepo(): Promise<string[]> {
422441 let repo = repo_nwo [ 1 ] ;
423442
424443 core . debug ( `GitHub repo ${ owner } ${ repo } ` ) ;
425- const response = await api . getApiClient ( true ) . request ( "GET / repos/:owner/:repo/languages" , ( {
444+ const response = await api . getApiClient ( true ) . repos . listLanguages ( {
426445 owner,
427446 repo
428- } ) ) ;
447+ } ) ;
429448
430449 core . debug ( "Languages API response: " + JSON . stringify ( response ) ) ;
431450
432451 // The GitHub API is going to return languages in order of popularity,
433452 // When we pick a language to autobuild we want to pick the most popular traced language
434453 // Since sets in javascript maintain insertion order, using a set here and then splatting it
435454 // into an array gives us an array of languages ordered by popularity
436- let languages : Set < string > = new Set ( ) ;
455+ let languages : Set < Language > = new Set ( ) ;
437456 for ( let lang in response . data ) {
438457 if ( lang in codeqlLanguages ) {
439458 languages . add ( codeqlLanguages [ lang ] ) ;
@@ -455,7 +474,7 @@ async function getLanguagesInRepo(): Promise<string[]> {
455474 * If no languages could be detected from either the workflow or the repository
456475 * then throw an error.
457476 */
458- async function getLanguages ( ) : Promise < string [ ] > {
477+ async function getLanguages ( ) : Promise < Language [ ] > {
459478
460479 // Obtain from action input 'languages' if set
461480 let languages = core . getInput ( 'languages' , { required : false } )
@@ -473,11 +492,32 @@ async function getLanguages(): Promise<string[]> {
473492 // If the languages parameter was not given and no languages were
474493 // detected then fail here as this is a workflow configuration error.
475494 if ( languages . length === 0 ) {
476- throw new Error ( "Did not detect any languages to analyze. " +
477- "Please update input in workflow or check that GitHub detects the correct languages in your repository." ) ;
495+ throw new Error ( getNoLanguagesError ( ) ) ;
496+ }
497+
498+ // Make sure they are supported
499+ const checkedLanguages : Language [ ] = [ ] ;
500+ const unknownLanguages : string [ ] = [ ] ;
501+ for ( let language of languages ) {
502+ // Normalise to lower case
503+ language = language . toLowerCase ( ) ;
504+ // Resolve any known aliases
505+ if ( language in LANGUAGE_ALIASES ) {
506+ language = LANGUAGE_ALIASES [ language ] ;
507+ }
508+
509+ const checkedLanguage = ALL_LANGUAGES . find ( l => l === language ) ;
510+ if ( checkedLanguage === undefined ) {
511+ unknownLanguages . push ( language ) ;
512+ } else if ( checkedLanguages . indexOf ( checkedLanguage ) === - 1 ) {
513+ checkedLanguages . push ( checkedLanguage ) ;
514+ }
515+ }
516+ if ( unknownLanguages . length > 0 ) {
517+ throw new Error ( getUnknownLanguagesError ( unknownLanguages ) ) ;
478518 }
479519
480- return languages ;
520+ return checkedLanguages ;
481521}
482522
483523/**
0 commit comments