# This is a combination of 4 commits.

# This is the 1st commit message:

Add logic to download codeql platform-language pkg

* Add `bundleName` argument to `getCodeQLBundleDownloadURL`
* Add `languages` argument to `setupCodeQL`.

The logic now tries to find the platform-language pkg before defaulting
to the full bundle. We keep the toolcache clean by adding the pl version
to the tool version.

# The commit message #2 will be skipped:

# add test

# The commit message #3 will be skipped:

# cleanup

# The commit message #4 will be skipped:

# linter
This commit is contained in:
Marco Gario
2020-09-09 13:52:28 +02:00
parent 3f5bb98d7e
commit d3d7dd4600
8 changed files with 160 additions and 49 deletions
+100 -13
View File
@@ -1,9 +1,14 @@
import * as github from "@actions/github";
import * as toolcache from '@actions/tool-cache';
import test from 'ava';
import nock from 'nock';
import * as path from 'path';
import sinon from 'sinon';
import * as api from './api-client';
import * as codeql from './codeql';
import * as defaults from './defaults.json'; // Referenced from codeql-action-sync-tool!
import { Language } from './languages';
import { getRunnerLogger } from './logging';
import {setupTests} from './testing-utils';
@@ -12,7 +17,8 @@ import * as util from './util';
setupTests(test);
test('download codeql bundle cache', async t => {
test('download and populate codeql bundle cache', async t => {
await util.withTmpDir(async tmpDir => {
const versions = ['20200601', '20200610'];
const languages: Language[][] = [
@@ -24,16 +30,15 @@ test('download codeql bundle cache', async t => {
process.platform === 'linux' ? 'linux64' :
process.platform === 'darwin' ? 'osx64' : undefined;
for (let i = 0; i < versions.length; i++) {
for (let j = 0; j < languages.length; j++) {
const version = versions[i];
const plVersion = (languages[j].length === 1) ? `${platform}-${languages[j][0]}` : undefined;
const pkg = plVersion ? `codeql-${plVersion}.tar.gz` : `codeql-bundle.tar.gz`;
nock('https://example.com')
.get(`/download/codeql-bundle-${version}/${pkg}`)
.replyWithFile(200, path.join(__dirname, `/../src/testdata/codeql-bundle.tar.gz`));
.get(`/download/codeql-bundle-${version}/codeql-bundle.tar.gz`)
.replyWithFile(200, path.join(__dirname, `/../src/testdata/codeql-bundle.tar.gz`));
await codeql.setupCodeQL(
`https://example.com/download/codeql-bundle-${version}/codeql-bundle.tar.gz`,
@@ -46,19 +51,81 @@ test('download codeql bundle cache', async t => {
getRunnerLogger(true));
const toolcacheVersion = plVersion ? `0.0.0-${version}-${plVersion}` : `0.0.0-${version}`;
t.assert(toolcache.find('CodeQL', toolcacheVersion), `Looking for ${toolcacheVersion} - ${plVersion}`);
t.assert(toolcache.find('CodeQL', toolcacheVersion), `Looking for ${toolcacheVersion}`);
}
}
const cachedVersions = toolcache.findAllVersions('CodeQL');
t.is(cachedVersions.length, 4);
});
});
test('use codeql bundle cache if pl version is not available', async t => {
// If we look for a pl version but find in cache the bundle, we use the bundle
test('download small codeql bundle if analyzing only one language', async t => {
// Note: We do not specify a codeqlURL in this test, thus testing that
// the logic for constructing the URL takes into account the
// language being analyzed
await util.withTmpDir(async tmpDir => {
const languages: Language[][] = [
[Language.cpp],
[Language.cpp, Language.python] // Multi-language requires the full bundle
];
const platform = process.platform === 'win32' ? 'win64' :
process.platform === 'linux' ? 'linux64' :
process.platform === 'darwin' ? 'osx64' : undefined;
for (let i = 0; i < languages.length; i++) {
const plVersion = (languages[i].length === 1) ? `${platform}-${languages[i][0]}` : undefined;
const pkg = plVersion ? `codeql-bundle-${plVersion}.tar.gz` : 'codeql-bundle.tar.gz';
// Mock the API client
let client = new github.GitHub('123');
const response = {
data: {
'assets': [
{
'name': `codeql-bundle-${platform}-cpp.tar.gz`,
'url': `https://github.example.com/url/codeql-bundle-${platform}-cpp.tar.gz`
},
{
'name': 'codeql-bundle.tar.gz',
'url': 'https://github.example.com/url/codeql-bundle.tar.gz'
},
]
},
};
sinon.stub(client.repos, "getReleaseByTag").resolves(response as any);
sinon.stub(api, "getApiClient").value(() => client);
nock('https://github.example.com')
.get(`/url/${pkg}`)
.replyWithFile(200, path.join(__dirname, `/../src/testdata/codeql-bundle.tar.gz`));
await codeql.setupCodeQL(
undefined,
languages[i],
'token',
'https://github.example.com',
tmpDir,
tmpDir,
'runner',
getRunnerLogger(true));
const parsedVersion = codeql.getCodeQLURLVersion(`/${defaults.bundleVersion}/`, getRunnerLogger(true));
const toolcacheVersion = plVersion ? `${parsedVersion}-${plVersion}` : parsedVersion;
t.assert(toolcache.find('CodeQL', toolcacheVersion), `Looking for ${toolcacheVersion} - ${plVersion}`);
}
const cachedVersions = toolcache.findAllVersions('CodeQL');
t.is(cachedVersions.length, 2);
});
});
test('use full codeql bundle cache if smaller bundle is not available', async t => {
// If we look for a platform-language version but find the full bundle in the cache,
// we use the full bundle
await util.withTmpDir(async tmpDir => {
const version = '20200601';
@@ -96,12 +163,32 @@ test('use codeql bundle cache if pl version is not available', async t => {
});
});
// test('use larger bundles if smaller ones are unavailble', async t => {
// // TODO: This should check the fallback behavior of getCodeQLBundleDownloadURL
// t.fail()
// });
test('use larger bundles if smaller ones are not released', async t => {
// Mock the API client
let client = new github.GitHub('123');
const response = {
data: {
'assets': [
{ 'name': 'full-bundle', 'url': 'url/file.gz' },
]
},
};
let getReleaseByTagMock = sinon.stub(client.repos, "getReleaseByTag").resolves(response as any);
sinon.stub(api, "getApiClient").value(() => client);
// Setting this env is required by a dependency of getCodeQLBundleDownloadURL
process.env['RUNNER_TEMP'] = "abc";
let codeqlURL = await codeql.getCodeQLBundleDownloadURL(
['small-bundle', 'full-bundle'],
"",
"",
'actions',
getRunnerLogger(true));
t.deepEqual(codeqlURL, 'url/file.gz');
t.assert(getReleaseByTagMock.called);
});
test('parse codeql bundle url version', t => {
+23 -13
View File
@@ -126,7 +126,7 @@ function getCodeQLActionRepository(mode: util.Mode): string {
return relativeScriptPathParts[0] + "/" + relativeScriptPathParts[1];
}
async function getCodeQLBundleDownloadURL(
export async function getCodeQLBundleDownloadURL(
bundleNames: string[],
githubAuth: string,
githubUrl: string,
@@ -211,7 +211,20 @@ export async function setupCodeQL(
process.env['RUNNER_TEMP'] = tempDir;
process.env['RUNNER_TOOL_CACHE'] = toolsDir;
// Compute package version
// The URL identifies the release version. E.g., codeql-20200901 .
// The plVersion identifies the platform-language combination of the package
// within the release. E.g., `linux64-cpp` in `codeql-linux64-cpp.tar.gz`.
// We expect the codeqlUrl (when given) to always point to the main bundle
// `codeql-bundle.tar.gz`
//
// The logic is as follows:
// - Always use the Toolcache if available.
// - If we would like a platform-language package, but have the
// full bundle in the cache, use that.
// - If codeqlURL is specified, use that.
// - If a single language is being analyzed, try to download the platform-language package.
// - If it is not available in the release assets, fallback to the full bundle
// - If multiple languages are being anlyzed, use the full bundle
let plVersion: string | undefined = undefined;
let platform: string;
if (process.platform === 'win32') {
@@ -228,12 +241,6 @@ export async function setupCodeQL(
}
try {
// The URL identifies the release version. E.g., codeql-20200901 .
// The plVersion identifies the platform-language combination of the package
// within the release. E.g., `linux64-cpp` in `codeql-linux64-cpp.tar.gz`.
// We expect the codeqlUrl (when given) to always point to the main bundle
// `codeql-bundle.tar.gz`
const codeqlURLVersion = getCodeQLURLVersion(codeqlURL || `/${CODEQL_BUNDLE_VERSION}/`, logger);
let codeqlFolder;
@@ -257,11 +264,14 @@ export async function setupCodeQL(
const codeqlToolcacheVersion = plVersion ? `${codeqlURLVersion}-${plVersion}` : codeqlURLVersion;
logger.debug(`CodeQL not found in cache`);
if (!codeqlURL) {
const bundles = [
CODEQL_BUNDLE_NAME.replace("-bundle", `-bundle-${plVersion}`),
CODEQL_BUNDLE_NAME.replace("-bundle", `-bundle-${platform}`),
CODEQL_BUNDLE_NAME,
];
// Provide a few options, from smaller to bigger
let bundles: string[] = [];
if (plVersion) {
bundles.push(CODEQL_BUNDLE_NAME.replace("-bundle", `-bundle-${plVersion}`));
}
bundles.push(CODEQL_BUNDLE_NAME.replace("-bundle", `-bundle-${platform}`));
bundles.push(CODEQL_BUNDLE_NAME);
codeqlURL = await getCodeQLBundleDownloadURL(bundles, githubAuth, githubUrl, mode, logger);
}
logger.debug(`Using CodeQL URL: ${codeqlURL}`);