diff --git a/.github/actions/prepare-test/action.yml b/.github/actions/prepare-test/action.yml index 8e8227c3a..ecabaa69f 100644 --- a/.github/actions/prepare-test/action.yml +++ b/.github/actions/prepare-test/action.yml @@ -2,7 +2,7 @@ name: "Prepare test" description: Performs some preparation to run tests inputs: version: - description: "The version of the CodeQL CLI to use. Can be 'linked', 'default', 'nightly-latest', 'nightly-YYYYMMDD', or 'stable-vX.Y.Z" + description: "The version of the CodeQL CLI to use. Can be 'linked', 'default', 'nightly', 'nightly-latest', 'nightly-YYYYMMDD', or 'stable-vX.Y.Z" required: true use-all-platform-bundle: description: "If true, we output a tools URL with codeql-bundle.tar.gz file rather than platform-specific URL" @@ -35,7 +35,10 @@ runs: run: | set -e # Fail this Action if `gh release list` fails. - if [[ "$VERSION" == "linked" ]]; then + if [[ "$VERSION" == "nightly" || "$VERSION" == "nightly-latest" ]]; then + echo "tools-url=nightly" >> "$GITHUB_OUTPUT" + exit 0 + elif [[ "$VERSION" == "linked" ]]; then echo "tools-url=linked" >> "$GITHUB_OUTPUT" exit 0 elif [[ "$VERSION" == "default" ]]; then @@ -43,29 +46,20 @@ runs: exit 0 fi - if [[ "$VERSION" == "nightly-latest" && "$RUNNER_OS" != "Windows" ]]; then - extension="tar.zst" - else - extension="tar.gz" - fi - if [[ "$USE_ALL_PLATFORM_BUNDLE" == "true" ]]; then - artifact_name="codeql-bundle.$extension" + artifact_name="codeql-bundle.tar.gz" elif [[ "$RUNNER_OS" == "Linux" ]]; then - artifact_name="codeql-bundle-linux64.$extension" + artifact_name="codeql-bundle-linux64.tar.gz" elif [[ "$RUNNER_OS" == "macOS" ]]; then - artifact_name="codeql-bundle-osx64.$extension" + artifact_name="codeql-bundle-osx64.tar.gz" elif [[ "$RUNNER_OS" == "Windows" ]]; then - artifact_name="codeql-bundle-win64.$extension" + artifact_name="codeql-bundle-win64.tar.gz" else echo "::error::Unrecognized OS $RUNNER_OS" exit 1 fi - if [[ "$VERSION" == "nightly-latest" ]]; then - tag=`gh release list --repo dsp-testing/codeql-cli-nightlies -L 1 | cut -f 3` - echo "tools-url=https://github.com/dsp-testing/codeql-cli-nightlies/releases/download/$tag/$artifact_name" >> $GITHUB_OUTPUT - elif [[ "$VERSION" == *"nightly"* ]]; then + if [[ "$VERSION" == *"nightly"* ]]; then version=`echo "$VERSION" | sed -e 's/^.*\-//'` echo "tools-url=https://github.com/dsp-testing/codeql-cli-nightlies/releases/download/codeql-bundle-$version/$artifact_name" >> $GITHUB_OUTPUT elif [[ "$VERSION" == *"stable"* ]]; then diff --git a/.github/workflows/__test-local-codeql.yml b/.github/workflows/__test-local-codeql.yml index 116e6dd0e..09e47d922 100644 --- a/.github/workflows/__test-local-codeql.yml +++ b/.github/workflows/__test-local-codeql.yml @@ -47,7 +47,7 @@ jobs: matrix: include: - os: ubuntu-latest - version: nightly-latest + version: linked name: Local CodeQL bundle permissions: contents: read @@ -69,11 +69,9 @@ jobs: with: go-version: ${{ inputs.go-version || '>=1.21.0' }} cache: false - - name: Fetch a CodeQL bundle - env: - CODEQL_URL: ${{ steps.prepare-test.outputs.tools-url }} + - name: Fetch latest CodeQL bundle run: | - wget "$CODEQL_URL" + wget https://github.com/github/codeql-action/releases/latest/download/codeql-bundle-linux64.tar.zst - id: init uses: ./../action/init with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1be12ea80..3cae4a75f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th - We have improved the CodeQL Action's ability to validate that the workflow it is used in does not use different versions of the CodeQL Action for different workflow steps. Mixing different versions of the CodeQL Action in the same workflow is unsupported and can lead to unpredictable results. A warning will now be emitted from the `codeql-action/init` step if different versions of the CodeQL Action are detected in the workflow file. Additionally, an error will now be thrown by the other CodeQL Action steps if they load a configuration file that was generated by a different version of the `codeql-action/init` step. [#3099](https://github.com/github/codeql-action/pull/3099) and [#3100](https://github.com/github/codeql-action/pull/3100) - We added support for reducing the size of dependency caches for Java analyses, which will reduce cache usage and speed up workflows. This will be enabled automatically at a later time. [#3107](https://github.com/github/codeql-action/pull/3107) +- You can now run the latest CodeQL nightly bundle by passing `tools: nightly` to the `init` action. In general, the nightly bundle is unstable and we only recommend running it when directed by GitHub staff. [#3130](https://github.com/github/codeql-action/pull/3130) ## 3.30.3 - 10 Sep 2025 diff --git a/init/action.yml b/init/action.yml index 49a3cc650..ba5d6efcc 100644 --- a/init/action.yml +++ b/init/action.yml @@ -12,6 +12,9 @@ inputs: - The URL of a CodeQL Bundle tarball GitHub release asset, or - A special value `linked` which uses the version of the CodeQL tools that the Action has been bundled with. + - A special value `nightly` which uses the latest nightly version of the + CodeQL tools. Note that this is unstable and not recommended for + production use. If not specified, the Action will check in several places until it finds the CodeQL tools. diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 86731e7d5..6f387f876 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -92053,7 +92053,10 @@ function sanitizeUrlForStatusReport(url2) { // src/setup-codeql.ts var CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; +var CODEQL_NIGHTLIES_REPOSITORY_OWNER = "dsp-testing"; +var CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies"; var CODEQL_BUNDLE_VERSION_ALIAS = ["linked", "latest"]; +var CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"]; function getCodeQLBundleExtension(compressionMethod) { switch (compressionMethod) { case "gzip": @@ -92196,7 +92199,7 @@ async function findOverridingToolsInCache(humanReadableVersion, logger) { return void 0; } async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, variant, tarSupportsZstd, logger) { - if (toolsInput && !CODEQL_BUNDLE_VERSION_ALIAS.includes(toolsInput) && !toolsInput.startsWith("http")) { + if (toolsInput && !isReservedToolsValue(toolsInput) && !toolsInput.startsWith("http")) { logger.info(`Using CodeQL CLI from local path ${toolsInput}`); const compressionMethod2 = inferCompressionMethod(toolsInput); if (compressionMethod2 === void 0) { @@ -92225,6 +92228,12 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian let cliVersion2; let tagName; let url2; + if (toolsInput !== void 0 && CODEQL_NIGHTLY_TOOLS_INPUTS.includes(toolsInput)) { + logger.info( + `Using the latest CodeQL CLI nightly, as requested by 'tools: ${toolsInput}'.` + ); + toolsInput = await getNightlyToolsUrl(logger); + } if (forceShippedTools) { cliVersion2 = cliVersion; tagName = bundleVersion; @@ -92508,6 +92517,34 @@ async function useZstdBundle(cliVersion2, tarSupportsZstd) { function getTempExtractionDir(tempDir) { return path12.join(tempDir, v4_default()); } +async function getNightlyToolsUrl(logger) { + const zstdAvailability = await isZstdAvailable(logger); + const compressionMethod = await useZstdBundle( + CODEQL_VERSION_ZSTD_BUNDLE, + zstdAvailability.available + ) ? "zstd" : "gzip"; + try { + const release3 = await getApiClient().rest.repos.listReleases({ + owner: CODEQL_NIGHTLIES_REPOSITORY_OWNER, + repo: CODEQL_NIGHTLIES_REPOSITORY_NAME, + per_page: 1, + page: 1, + prerelease: true + }); + const latestRelease = release3.data[0]; + if (!latestRelease) { + throw new Error("Could not find the latest nightly release."); + } + return `https://github.com/${CODEQL_NIGHTLIES_REPOSITORY_OWNER}/${CODEQL_NIGHTLIES_REPOSITORY_NAME}/releases/download/${latestRelease.tag_name}/${getCodeQLBundleName(compressionMethod)}`; + } catch (e) { + throw new Error( + `Failed to retrieve the latest nightly release: ${wrapError(e)}` + ); + } +} +function isReservedToolsValue(tools) { + return CODEQL_BUNDLE_VERSION_ALIAS.includes(tools) || CODEQL_NIGHTLY_TOOLS_INPUTS.includes(tools); +} // src/tracer-config.ts var fs13 = __toESM(require("fs")); diff --git a/lib/init-action-post.js b/lib/init-action-post.js index b1ae22586..aa4369743 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -129996,7 +129996,10 @@ function sanitizeUrlForStatusReport(url2) { // src/setup-codeql.ts var CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; +var CODEQL_NIGHTLIES_REPOSITORY_OWNER = "dsp-testing"; +var CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies"; var CODEQL_BUNDLE_VERSION_ALIAS = ["linked", "latest"]; +var CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"]; function getCodeQLBundleExtension(compressionMethod) { switch (compressionMethod) { case "gzip": @@ -130139,7 +130142,7 @@ async function findOverridingToolsInCache(humanReadableVersion, logger) { return void 0; } async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, variant, tarSupportsZstd, logger) { - if (toolsInput && !CODEQL_BUNDLE_VERSION_ALIAS.includes(toolsInput) && !toolsInput.startsWith("http")) { + if (toolsInput && !isReservedToolsValue(toolsInput) && !toolsInput.startsWith("http")) { logger.info(`Using CodeQL CLI from local path ${toolsInput}`); const compressionMethod2 = inferCompressionMethod(toolsInput); if (compressionMethod2 === void 0) { @@ -130168,6 +130171,12 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian let cliVersion2; let tagName; let url2; + if (toolsInput !== void 0 && CODEQL_NIGHTLY_TOOLS_INPUTS.includes(toolsInput)) { + logger.info( + `Using the latest CodeQL CLI nightly, as requested by 'tools: ${toolsInput}'.` + ); + toolsInput = await getNightlyToolsUrl(logger); + } if (forceShippedTools) { cliVersion2 = cliVersion; tagName = bundleVersion; @@ -130451,6 +130460,34 @@ async function useZstdBundle(cliVersion2, tarSupportsZstd) { function getTempExtractionDir(tempDir) { return path12.join(tempDir, v4_default()); } +async function getNightlyToolsUrl(logger) { + const zstdAvailability = await isZstdAvailable(logger); + const compressionMethod = await useZstdBundle( + CODEQL_VERSION_ZSTD_BUNDLE, + zstdAvailability.available + ) ? "zstd" : "gzip"; + try { + const release3 = await getApiClient().rest.repos.listReleases({ + owner: CODEQL_NIGHTLIES_REPOSITORY_OWNER, + repo: CODEQL_NIGHTLIES_REPOSITORY_NAME, + per_page: 1, + page: 1, + prerelease: true + }); + const latestRelease = release3.data[0]; + if (!latestRelease) { + throw new Error("Could not find the latest nightly release."); + } + return `https://github.com/${CODEQL_NIGHTLIES_REPOSITORY_OWNER}/${CODEQL_NIGHTLIES_REPOSITORY_NAME}/releases/download/${latestRelease.tag_name}/${getCodeQLBundleName(compressionMethod)}`; + } catch (e) { + throw new Error( + `Failed to retrieve the latest nightly release: ${wrapError(e)}` + ); + } +} +function isReservedToolsValue(tools) { + return CODEQL_BUNDLE_VERSION_ALIAS.includes(tools) || CODEQL_NIGHTLY_TOOLS_INPUTS.includes(tools); +} // src/tracer-config.ts async function shouldEnableIndirectTracing(codeql, config) { diff --git a/lib/init-action.js b/lib/init-action.js index aec214d0f..7054966f0 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -88709,7 +88709,10 @@ function sanitizeUrlForStatusReport(url) { // src/setup-codeql.ts var CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; +var CODEQL_NIGHTLIES_REPOSITORY_OWNER = "dsp-testing"; +var CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies"; var CODEQL_BUNDLE_VERSION_ALIAS = ["linked", "latest"]; +var CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"]; function getCodeQLBundleExtension(compressionMethod) { switch (compressionMethod) { case "gzip": @@ -88852,7 +88855,7 @@ async function findOverridingToolsInCache(humanReadableVersion, logger) { return void 0; } async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, variant, tarSupportsZstd, logger) { - if (toolsInput && !CODEQL_BUNDLE_VERSION_ALIAS.includes(toolsInput) && !toolsInput.startsWith("http")) { + if (toolsInput && !isReservedToolsValue(toolsInput) && !toolsInput.startsWith("http")) { logger.info(`Using CodeQL CLI from local path ${toolsInput}`); const compressionMethod2 = inferCompressionMethod(toolsInput); if (compressionMethod2 === void 0) { @@ -88881,6 +88884,12 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian let cliVersion2; let tagName; let url; + if (toolsInput !== void 0 && CODEQL_NIGHTLY_TOOLS_INPUTS.includes(toolsInput)) { + logger.info( + `Using the latest CodeQL CLI nightly, as requested by 'tools: ${toolsInput}'.` + ); + toolsInput = await getNightlyToolsUrl(logger); + } if (forceShippedTools) { cliVersion2 = cliVersion; tagName = bundleVersion; @@ -89164,6 +89173,34 @@ async function useZstdBundle(cliVersion2, tarSupportsZstd) { function getTempExtractionDir(tempDir) { return path14.join(tempDir, v4_default()); } +async function getNightlyToolsUrl(logger) { + const zstdAvailability = await isZstdAvailable(logger); + const compressionMethod = await useZstdBundle( + CODEQL_VERSION_ZSTD_BUNDLE, + zstdAvailability.available + ) ? "zstd" : "gzip"; + try { + const release3 = await getApiClient().rest.repos.listReleases({ + owner: CODEQL_NIGHTLIES_REPOSITORY_OWNER, + repo: CODEQL_NIGHTLIES_REPOSITORY_NAME, + per_page: 1, + page: 1, + prerelease: true + }); + const latestRelease = release3.data[0]; + if (!latestRelease) { + throw new Error("Could not find the latest nightly release."); + } + return `https://github.com/${CODEQL_NIGHTLIES_REPOSITORY_OWNER}/${CODEQL_NIGHTLIES_REPOSITORY_NAME}/releases/download/${latestRelease.tag_name}/${getCodeQLBundleName(compressionMethod)}`; + } catch (e) { + throw new Error( + `Failed to retrieve the latest nightly release: ${wrapError(e)}` + ); + } +} +function isReservedToolsValue(tools) { + return CODEQL_BUNDLE_VERSION_ALIAS.includes(tools) || CODEQL_NIGHTLY_TOOLS_INPUTS.includes(tools); +} // src/tracer-config.ts var fs13 = __toESM(require("fs")); diff --git a/lib/upload-lib.js b/lib/upload-lib.js index fe2660b72..f587a2f2c 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -89824,7 +89824,10 @@ function sanitizeUrlForStatusReport(url2) { // src/setup-codeql.ts var CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; +var CODEQL_NIGHTLIES_REPOSITORY_OWNER = "dsp-testing"; +var CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies"; var CODEQL_BUNDLE_VERSION_ALIAS = ["linked", "latest"]; +var CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"]; function getCodeQLBundleExtension(compressionMethod) { switch (compressionMethod) { case "gzip": @@ -89967,7 +89970,7 @@ async function findOverridingToolsInCache(humanReadableVersion, logger) { return void 0; } async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, variant, tarSupportsZstd, logger) { - if (toolsInput && !CODEQL_BUNDLE_VERSION_ALIAS.includes(toolsInput) && !toolsInput.startsWith("http")) { + if (toolsInput && !isReservedToolsValue(toolsInput) && !toolsInput.startsWith("http")) { logger.info(`Using CodeQL CLI from local path ${toolsInput}`); const compressionMethod2 = inferCompressionMethod(toolsInput); if (compressionMethod2 === void 0) { @@ -89996,6 +89999,12 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian let cliVersion2; let tagName; let url2; + if (toolsInput !== void 0 && CODEQL_NIGHTLY_TOOLS_INPUTS.includes(toolsInput)) { + logger.info( + `Using the latest CodeQL CLI nightly, as requested by 'tools: ${toolsInput}'.` + ); + toolsInput = await getNightlyToolsUrl(logger); + } if (forceShippedTools) { cliVersion2 = cliVersion; tagName = bundleVersion; @@ -90279,6 +90288,34 @@ async function useZstdBundle(cliVersion2, tarSupportsZstd) { function getTempExtractionDir(tempDir) { return path11.join(tempDir, v4_default()); } +async function getNightlyToolsUrl(logger) { + const zstdAvailability = await isZstdAvailable(logger); + const compressionMethod = await useZstdBundle( + CODEQL_VERSION_ZSTD_BUNDLE, + zstdAvailability.available + ) ? "zstd" : "gzip"; + try { + const release = await getApiClient().rest.repos.listReleases({ + owner: CODEQL_NIGHTLIES_REPOSITORY_OWNER, + repo: CODEQL_NIGHTLIES_REPOSITORY_NAME, + per_page: 1, + page: 1, + prerelease: true + }); + const latestRelease = release.data[0]; + if (!latestRelease) { + throw new Error("Could not find the latest nightly release."); + } + return `https://github.com/${CODEQL_NIGHTLIES_REPOSITORY_OWNER}/${CODEQL_NIGHTLIES_REPOSITORY_NAME}/releases/download/${latestRelease.tag_name}/${getCodeQLBundleName(compressionMethod)}`; + } catch (e) { + throw new Error( + `Failed to retrieve the latest nightly release: ${wrapError(e)}` + ); + } +} +function isReservedToolsValue(tools) { + return CODEQL_BUNDLE_VERSION_ALIAS.includes(tools) || CODEQL_NIGHTLY_TOOLS_INPUTS.includes(tools); +} // src/tracer-config.ts async function shouldEnableIndirectTracing(codeql, config) { diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 6ef1a81f2..8445dd976 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -90525,7 +90525,10 @@ function sanitizeUrlForStatusReport(url2) { // src/setup-codeql.ts var CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; +var CODEQL_NIGHTLIES_REPOSITORY_OWNER = "dsp-testing"; +var CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies"; var CODEQL_BUNDLE_VERSION_ALIAS = ["linked", "latest"]; +var CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"]; function getCodeQLBundleExtension(compressionMethod) { switch (compressionMethod) { case "gzip": @@ -90668,7 +90671,7 @@ async function findOverridingToolsInCache(humanReadableVersion, logger) { return void 0; } async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, variant, tarSupportsZstd, logger) { - if (toolsInput && !CODEQL_BUNDLE_VERSION_ALIAS.includes(toolsInput) && !toolsInput.startsWith("http")) { + if (toolsInput && !isReservedToolsValue(toolsInput) && !toolsInput.startsWith("http")) { logger.info(`Using CodeQL CLI from local path ${toolsInput}`); const compressionMethod2 = inferCompressionMethod(toolsInput); if (compressionMethod2 === void 0) { @@ -90697,6 +90700,12 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian let cliVersion2; let tagName; let url2; + if (toolsInput !== void 0 && CODEQL_NIGHTLY_TOOLS_INPUTS.includes(toolsInput)) { + logger.info( + `Using the latest CodeQL CLI nightly, as requested by 'tools: ${toolsInput}'.` + ); + toolsInput = await getNightlyToolsUrl(logger); + } if (forceShippedTools) { cliVersion2 = cliVersion; tagName = bundleVersion; @@ -90980,6 +90989,34 @@ async function useZstdBundle(cliVersion2, tarSupportsZstd) { function getTempExtractionDir(tempDir) { return path12.join(tempDir, v4_default()); } +async function getNightlyToolsUrl(logger) { + const zstdAvailability = await isZstdAvailable(logger); + const compressionMethod = await useZstdBundle( + CODEQL_VERSION_ZSTD_BUNDLE, + zstdAvailability.available + ) ? "zstd" : "gzip"; + try { + const release3 = await getApiClient().rest.repos.listReleases({ + owner: CODEQL_NIGHTLIES_REPOSITORY_OWNER, + repo: CODEQL_NIGHTLIES_REPOSITORY_NAME, + per_page: 1, + page: 1, + prerelease: true + }); + const latestRelease = release3.data[0]; + if (!latestRelease) { + throw new Error("Could not find the latest nightly release."); + } + return `https://github.com/${CODEQL_NIGHTLIES_REPOSITORY_OWNER}/${CODEQL_NIGHTLIES_REPOSITORY_NAME}/releases/download/${latestRelease.tag_name}/${getCodeQLBundleName(compressionMethod)}`; + } catch (e) { + throw new Error( + `Failed to retrieve the latest nightly release: ${wrapError(e)}` + ); + } +} +function isReservedToolsValue(tools) { + return CODEQL_BUNDLE_VERSION_ALIAS.includes(tools) || CODEQL_NIGHTLY_TOOLS_INPUTS.includes(tools); +} // src/tracer-config.ts async function shouldEnableIndirectTracing(codeql, config) { diff --git a/pr-checks/checks/test-local-codeql.yml b/pr-checks/checks/test-local-codeql.yml index a3c2c6a9c..1e41e5dd3 100644 --- a/pr-checks/checks/test-local-codeql.yml +++ b/pr-checks/checks/test-local-codeql.yml @@ -1,14 +1,12 @@ name: "Local CodeQL bundle" description: "Tests using a CodeQL bundle from a local file rather than a URL" -versions: ["nightly-latest"] +versions: ["linked"] operatingSystems: ["ubuntu"] installGo: true steps: - - name: Fetch a CodeQL bundle - env: - CODEQL_URL: ${{ steps.prepare-test.outputs.tools-url }} + - name: Fetch latest CodeQL bundle run: | - wget "$CODEQL_URL" + wget https://github.com/github/codeql-action/releases/latest/download/codeql-bundle-linux64.tar.zst - id: init uses: ./../action/init with: diff --git a/src/setup-codeql.ts b/src/setup-codeql.ts index e64a032c9..5a0f671fa 100644 --- a/src/setup-codeql.ts +++ b/src/setup-codeql.ts @@ -33,8 +33,11 @@ export enum ToolsSource { } export const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; +const CODEQL_NIGHTLIES_REPOSITORY_OWNER = "dsp-testing"; +const CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies"; const CODEQL_BUNDLE_VERSION_ALIAS: string[] = ["linked", "latest"]; +const CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"]; function getCodeQLBundleExtension( compressionMethod: tar.CompressionMethod, @@ -276,7 +279,7 @@ export async function getCodeQLSource( ): Promise { if ( toolsInput && - !CODEQL_BUNDLE_VERSION_ALIAS.includes(toolsInput) && + !isReservedToolsValue(toolsInput) && !toolsInput.startsWith("http") ) { logger.info(`Using CodeQL CLI from local path ${toolsInput}`); @@ -331,6 +334,16 @@ export async function getCodeQLSource( */ let url: string | undefined; + if ( + toolsInput !== undefined && + CODEQL_NIGHTLY_TOOLS_INPUTS.includes(toolsInput) + ) { + logger.info( + `Using the latest CodeQL CLI nightly, as requested by 'tools: ${toolsInput}'.`, + ); + toolsInput = await getNightlyToolsUrl(logger); + } + if (forceShippedTools) { cliVersion = defaults.cliVersion; tagName = defaults.bundleVersion; @@ -771,3 +784,46 @@ async function useZstdBundle( function getTempExtractionDir(tempDir: string) { return path.join(tempDir, uuidV4()); } + +/** + * Get the URL of the latest nightly CodeQL bundle. + */ +async function getNightlyToolsUrl(logger: Logger) { + const zstdAvailability = await tar.isZstdAvailable(logger); + // The nightly is guaranteed to have a zstd bundle + const compressionMethod = (await useZstdBundle( + CODEQL_VERSION_ZSTD_BUNDLE, + zstdAvailability.available, + )) + ? "zstd" + : "gzip"; + + try { + // Since nightlies are prereleases, we can't just download the latest release + // on the repository. So instead we need to find the latest pre-release + // version and construct the download URL from that. + const release = await api.getApiClient().rest.repos.listReleases({ + owner: CODEQL_NIGHTLIES_REPOSITORY_OWNER, + repo: CODEQL_NIGHTLIES_REPOSITORY_NAME, + per_page: 1, + page: 1, + prerelease: true, + }); + const latestRelease = release.data[0]; + if (!latestRelease) { + throw new Error("Could not find the latest nightly release."); + } + return `https://github.com/${CODEQL_NIGHTLIES_REPOSITORY_OWNER}/${CODEQL_NIGHTLIES_REPOSITORY_NAME}/releases/download/${latestRelease.tag_name}/${getCodeQLBundleName(compressionMethod)}`; + } catch (e) { + throw new Error( + `Failed to retrieve the latest nightly release: ${util.wrapError(e)}`, + ); + } +} + +function isReservedToolsValue(tools: string): boolean { + return ( + CODEQL_BUNDLE_VERSION_ALIAS.includes(tools) || + CODEQL_NIGHTLY_TOOLS_INPUTS.includes(tools) + ); +}