Skip to content

Commit

Permalink
Simplify toolcache version number for semantically versioned bundles
Browse files Browse the repository at this point in the history
  • Loading branch information
henrymercer committed Aug 10, 2023
1 parent 9e4932e commit 76584bd
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 28 deletions.
15 changes: 15 additions & 0 deletions lib/codeql.test.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/codeql.test.js.map

Large diffs are not rendered by default.

41 changes: 29 additions & 12 deletions lib/setup-codeql.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/setup-codeql.js.map

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions src/codeql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,31 @@ test("downloads and caches explicitly requested bundles that aren't in the toolc
});
});

test("caches semantically versioned bundles using their semantic version number", async (t) => {
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
const url = mockBundleDownloadApi({
tagName: `codeql-bundle-v2.14.0`,
isPinned: false,
});
const result = await codeql.setupCodeQL(
url,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
getRunnerLogger(true),
false,
);

t.is(toolcache.findAllVersions("CodeQL").length, 1);
t.assert(toolcache.find("CodeQL", `2.14.0`));
t.is(result.toolsVersion, `2.14.0`);
t.is(result.toolsSource, ToolsSource.Download);
t.assert(Number.isInteger(result.toolsDownloadDurationMs));
});
});

test("downloads an explicitly requested bundle even if a different version is cached", async (t) => {
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
Expand Down
55 changes: 41 additions & 14 deletions src/setup-codeql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import * as api from "./api-client";
// creation scripts. Ensure that any changes to the format of this file are compatible with both of
// these dependents.
import * as defaults from "./defaults.json";
import { CodeQLDefaultVersionInfo } from "./feature-flags";
import {
CODEQL_VERSION_BUNDLE_SEMANTICALLY_VERSIONED,
CodeQLDefaultVersionInfo,
} from "./feature-flags";
import { Logger } from "./logging";
import * as util from "./util";
import { isGoodVersion, wrapError } from "./util";
Expand Down Expand Up @@ -610,20 +613,12 @@ export async function downloadCodeQL(
);
}

// Include both the CLI version and the bundle version in the toolcache version number. That way
// if the user requests the same URL again, we can get it from the cache without having to call
// any of the Releases API.
//
// Special case: If the CLI version is a pre-release or contains build metadata, then cache the
// bundle as `0.0.0-<bundleVersion>` to avoid the bundle being interpreted as containing a stable
// CLI release. In principle, it should be enough to just check that the CLI version isn't a
// pre-release, but the version numbers of CodeQL nightlies have the format `x.y.z+<timestamp>`,
// and we don't want these nightlies to override stable CLI versions in the toolcache.
const toolcacheVersion = maybeCliVersion?.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)
? `${maybeCliVersion}-${bundleVersion}`
: convertToSemVer(bundleVersion, logger);

logger.debug("Caching CodeQL bundle.");
const toolcacheVersion = getCanonicalToolcacheVersion(
maybeCliVersion,
bundleVersion,
logger,
);
const toolcachedBundlePath = await toolcache.cacheDir(
extractedBundlePath,
"CodeQL",
Expand Down Expand Up @@ -656,6 +651,38 @@ export function getCodeQLURLVersion(url: string): string {
return match[1];
}

/**
* Returns the toolcache version number to use to store the bundle with the associated CLI version
* and bundle version.
*
* This is the canonical version number, since toolcaches populated by different versions of the
* CodeQL Action or different runner image creation scripts may store the bundle using a different
* version number. Functions like `getCodeQLSource` that fetch the bundle from rather than save the
* bundle to the toolcache should handle these different version numbers.
*/
function getCanonicalToolcacheVersion(
cliVersion: string | undefined,
bundleVersion: string,
logger: Logger,
) {
// If the CLI version is a pre-release or contains build metadata, then cache the
// bundle as `0.0.0-<bundleVersion>` to avoid the bundle being interpreted as containing a stable
// CLI release. In principle, it should be enough to just check that the CLI version isn't a
// pre-release, but the version numbers of CodeQL nightlies have the format `x.y.z+<timestamp>`,
// and we don't want these nightlies to override stable CLI versions in the toolcache.
if (!cliVersion?.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)) {
return convertToSemVer(bundleVersion, logger);
}
// If the bundle is semantically versioned, it can be looked up based on just the CLI version
// number, so version it in the toolcache using just the CLI version number.
if (semver.gte(cliVersion, CODEQL_VERSION_BUNDLE_SEMANTICALLY_VERSIONED)) {
return cliVersion;
}
// Include both the CLI version and the bundle version in the toolcache version number. That way
// we can find the bundle in the toolcache based on either the CLI version or the bundle version.
return `${cliVersion}-${bundleVersion}`;
}

/**
* Obtains the CodeQL bundle, installs it in the toolcache if appropriate, and extracts it.
*
Expand Down

0 comments on commit 76584bd

Please sign in to comment.