From 40e0374c6ff49c0db274f85701672747de3fa15e Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Mon, 12 Sep 2022 18:24:46 +0100 Subject: [PATCH] Ensure backwards compat for multi-language builds with Go reconciliation --- lib/autobuild.js | 50 ++++++++++++++++++++++++++++++++++----- lib/autobuild.js.map | 2 +- src/autobuild.ts | 56 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 95 insertions(+), 13 deletions(-) diff --git a/lib/autobuild.js b/lib/autobuild.js index 51ec26315..9665f6d02 100644 --- a/lib/autobuild.js +++ b/lib/autobuild.js @@ -30,18 +30,56 @@ async function determineAutobuildLanguages(config, featureFlags, logger) { // The languages are sorted in order specified by user or by lines of code if we got // them from the GitHub API, so try to build the first language on the list. const autobuildLanguages = config.languages.filter((l) => (0, languages_1.isTracedLanguage)(l, isGoExtractionReconciliationEnabled, logger)); - const language = autobuildLanguages[0]; - if (!language) { + if (!autobuildLanguages) { logger.info("None of the languages in this project require extra build steps"); return undefined; } - logger.debug(`Detected dominant traced language: ${language}`); - if (autobuildLanguages.length > 1) { - logger.warning(`We will only automatically build ${language} code. If you wish to scan ${autobuildLanguages + /** + * Additionally autobuild Go in the autobuild Action to ensure backwards + * compatibility for users performing a multi-language build within a single + * job. + * + * For example, consider a user with the following workflow file: + * + * ```yml + * - uses: github/codeql-action/init@v2 + * with: + * languages: go, java + * - uses: github/codeql-action/autobuild@v2 + * - uses: github/codeql-action/analyze@v2 + * ``` + * + * - With Go extraction disabled, we will run the Java autobuilder in the + * autobuild Action, ensuring we extract both Java and Go code. + * - With Go extraction enabled, taking the previous behavior we'd run the Go + * autobuilder, since Go is first on the list of languages. We wouldn't run + * the Java autobuilder at all and so we'd only extract Go code. + * + * We therefore introduce a special case here such that we'll autobuild Go + * in addition to the primary non-Go traced language in the autobuild Action. + * + * This special case behavior should be removed as part of the next major + * version of the CodeQL Action. + */ + const autobuildLanguagesNoGo = autobuildLanguages.filter((l) => l !== languages_1.Language.go); + const languages = []; + // First run the autobuilder for the first non-Go traced language, if one + // exists. + if (autobuildLanguagesNoGo[0] !== undefined) { + languages.push(autobuildLanguagesNoGo[0]); + } + // If Go is requested, run the Go autobuilder last to ensure it doesn't + // interfere with the other autobuilder. + if (autobuildLanguages.length !== autobuildLanguagesNoGo.length) { + languages.push(languages_1.Language.go); + } + logger.debug(`Will autobuild ${languages.join(" and ")}.`); + if (autobuildLanguagesNoGo.length > 1) { + logger.warning(`We will only automatically build ${languages.join(" and ")} code. If you wish to scan ${autobuildLanguagesNoGo .slice(1) .join(" and ")}, you must replace this call with custom build steps.`); } - return [language]; + return languages; } exports.determineAutobuildLanguages = determineAutobuildLanguages; async function runAutobuild(language, config, logger) { diff --git a/lib/autobuild.js.map b/lib/autobuild.js.map index 3dbc53b79..558339d81 100644 --- a/lib/autobuild.js.map +++ b/lib/autobuild.js.map @@ -1 +1 @@ -{"version":3,"file":"autobuild.js","sourceRoot":"","sources":["../src/autobuild.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAqC;AAGrC,2CAAyD;AAEzD,6CAA+B;AAExB,KAAK,UAAU,2BAA2B,CAC/C,MAA0B,EAC1B,YAA0B,EAC1B,MAAc;IAEd,MAAM,mCAAmC,GACvC,MAAM,IAAI,CAAC,mCAAmC,CAAC,YAAY,CAAC,CAAC;IAC/D,0CAA0C;IAC1C,mFAAmF;IACnF,oFAAoF;IACpF,4EAA4E;IAC5E,MAAM,kBAAkB,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACvD,IAAA,4BAAgB,EAAC,CAAC,EAAE,mCAAmC,EAAE,MAAM,CAAC,CACjE,CAAC;IACF,MAAM,QAAQ,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAEvC,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,CAAC,IAAI,CACT,iEAAiE,CAClE,CAAC;QACF,OAAO,SAAS,CAAC;KAClB;IAED,MAAM,CAAC,KAAK,CAAC,sCAAsC,QAAQ,EAAE,CAAC,CAAC;IAE/D,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE;QACjC,MAAM,CAAC,OAAO,CACZ,oCAAoC,QAAQ,8BAA8B,kBAAkB;aACzF,KAAK,CAAC,CAAC,CAAC;aACR,IAAI,CAAC,OAAO,CAAC,uDAAuD,CACxE,CAAC;KACH;IAED,OAAO,CAAC,QAAQ,CAAC,CAAC;AACpB,CAAC;AAlCD,kEAkCC;AAEM,KAAK,UAAU,YAAY,CAChC,QAAkB,EAClB,MAA0B,EAC1B,MAAc;IAEd,MAAM,CAAC,UAAU,CAAC,qCAAqC,QAAQ,OAAO,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,MAAM,IAAA,kBAAS,EAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,CAAC,QAAQ,EAAE,CAAC;AACpB,CAAC;AATD,oCASC"} \ No newline at end of file +{"version":3,"file":"autobuild.js","sourceRoot":"","sources":["../src/autobuild.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAqC;AAGrC,2CAAyD;AAEzD,6CAA+B;AAExB,KAAK,UAAU,2BAA2B,CAC/C,MAA0B,EAC1B,YAA0B,EAC1B,MAAc;IAEd,MAAM,mCAAmC,GACvC,MAAM,IAAI,CAAC,mCAAmC,CAAC,YAAY,CAAC,CAAC;IAC/D,0CAA0C;IAC1C,mFAAmF;IACnF,oFAAoF;IACpF,4EAA4E;IAC5E,MAAM,kBAAkB,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACvD,IAAA,4BAAgB,EAAC,CAAC,EAAE,mCAAmC,EAAE,MAAM,CAAC,CACjE,CAAC;IAEF,IAAI,CAAC,kBAAkB,EAAE;QACvB,MAAM,CAAC,IAAI,CACT,iEAAiE,CAClE,CAAC;QACF,OAAO,SAAS,CAAC;KAClB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,MAAM,sBAAsB,GAAG,kBAAkB,CAAC,MAAM,CACtD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,oBAAQ,CAAC,EAAE,CACzB,CAAC;IAEF,MAAM,SAAS,GAAe,EAAE,CAAC;IACjC,yEAAyE;IACzE,UAAU;IACV,IAAI,sBAAsB,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE;QAC3C,SAAS,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;KAC3C;IACD,uEAAuE;IACvE,wCAAwC;IACxC,IAAI,kBAAkB,CAAC,MAAM,KAAK,sBAAsB,CAAC,MAAM,EAAE;QAC/D,SAAS,CAAC,IAAI,CAAC,oBAAQ,CAAC,EAAE,CAAC,CAAC;KAC7B;IAED,MAAM,CAAC,KAAK,CAAC,kBAAkB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAE3D,IAAI,sBAAsB,CAAC,MAAM,GAAG,CAAC,EAAE;QACrC,MAAM,CAAC,OAAO,CACZ,oCAAoC,SAAS,CAAC,IAAI,CAChD,OAAO,CACR,8BAA8B,sBAAsB;aAClD,KAAK,CAAC,CAAC,CAAC;aACR,IAAI,CAAC,OAAO,CAAC,uDAAuD,CACxE,CAAC;KACH;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AA9ED,kEA8EC;AAEM,KAAK,UAAU,YAAY,CAChC,QAAkB,EAClB,MAA0B,EAC1B,MAAc;IAEd,MAAM,CAAC,UAAU,CAAC,qCAAqC,QAAQ,OAAO,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,MAAM,IAAA,kBAAS,EAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,CAAC,QAAQ,EAAE,CAAC;AACpB,CAAC;AATD,oCASC"} \ No newline at end of file diff --git a/src/autobuild.ts b/src/autobuild.ts index 96eac7647..7866e00f0 100644 --- a/src/autobuild.ts +++ b/src/autobuild.ts @@ -19,26 +19,70 @@ export async function determineAutobuildLanguages( const autobuildLanguages = config.languages.filter((l) => isTracedLanguage(l, isGoExtractionReconciliationEnabled, logger) ); - const language = autobuildLanguages[0]; - if (!language) { + if (!autobuildLanguages) { logger.info( "None of the languages in this project require extra build steps" ); return undefined; } - logger.debug(`Detected dominant traced language: ${language}`); + /** + * Additionally autobuild Go in the autobuild Action to ensure backwards + * compatibility for users performing a multi-language build within a single + * job. + * + * For example, consider a user with the following workflow file: + * + * ```yml + * - uses: github/codeql-action/init@v2 + * with: + * languages: go, java + * - uses: github/codeql-action/autobuild@v2 + * - uses: github/codeql-action/analyze@v2 + * ``` + * + * - With Go extraction disabled, we will run the Java autobuilder in the + * autobuild Action, ensuring we extract both Java and Go code. + * - With Go extraction enabled, taking the previous behavior we'd run the Go + * autobuilder, since Go is first on the list of languages. We wouldn't run + * the Java autobuilder at all and so we'd only extract Go code. + * + * We therefore introduce a special case here such that we'll autobuild Go + * in addition to the primary non-Go traced language in the autobuild Action. + * + * This special case behavior should be removed as part of the next major + * version of the CodeQL Action. + */ + const autobuildLanguagesNoGo = autobuildLanguages.filter( + (l) => l !== Language.go + ); + + const languages: Language[] = []; + // First run the autobuilder for the first non-Go traced language, if one + // exists. + if (autobuildLanguagesNoGo[0] !== undefined) { + languages.push(autobuildLanguagesNoGo[0]); + } + // If Go is requested, run the Go autobuilder last to ensure it doesn't + // interfere with the other autobuilder. + if (autobuildLanguages.length !== autobuildLanguagesNoGo.length) { + languages.push(Language.go); + } + + logger.debug(`Will autobuild ${languages.join(" and ")}.`); - if (autobuildLanguages.length > 1) { + if (autobuildLanguagesNoGo.length > 1) { logger.warning( - `We will only automatically build ${language} code. If you wish to scan ${autobuildLanguages + `We will only automatically build ${languages.join( + " and " + )} code. If you wish to scan ${autobuildLanguagesNoGo .slice(1) .join(" and ")}, you must replace this call with custom build steps.` ); } - return [language]; + return languages; } export async function runAutobuild(