mirror of
https://github.com/github/codeql-action.git
synced 2025-12-06 15:58:06 +08:00
Compare commits
2 Commits
codeql-bun
...
daverlo/ge
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a50226279 | ||
|
|
382c51457f |
27
lib/config-utils.js
generated
27
lib/config-utils.js
generated
@@ -275,14 +275,10 @@ function getConfigFileRepoFormatInvalidMessage(configFile) {
|
||||
return error;
|
||||
}
|
||||
exports.getConfigFileRepoFormatInvalidMessage = getConfigFileRepoFormatInvalidMessage;
|
||||
function getConfigFileFormatInvalidMessage(configFile) {
|
||||
return 'The configuration file "' + configFile + '" could not be read';
|
||||
function getConfigFileFormatInvalidMessage(configFile, reason) {
|
||||
return 'The configuration file "' + configFile + '" could not be read. Reason: ' + reason;
|
||||
}
|
||||
exports.getConfigFileFormatInvalidMessage = getConfigFileFormatInvalidMessage;
|
||||
function getConfigFileDirectoryGivenMessage(configFile) {
|
||||
return 'The configuration file "' + configFile + '" looks like a directory, not a file';
|
||||
}
|
||||
exports.getConfigFileDirectoryGivenMessage = getConfigFileDirectoryGivenMessage;
|
||||
function getConfigFilePropertyError(configFile, property, error) {
|
||||
return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error;
|
||||
}
|
||||
@@ -538,23 +534,14 @@ async function getRemoteConfig(configFile) {
|
||||
if (pieces === null || pieces.groups === undefined || pieces.length < 5) {
|
||||
throw new Error(getConfigFileRepoFormatInvalidMessage(configFile));
|
||||
}
|
||||
const response = await api.getActionsApiClient(true).repos.getContents({
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
ref: pieces.groups.ref,
|
||||
});
|
||||
let fileContents;
|
||||
if ("content" in response.data && response.data.content !== undefined) {
|
||||
fileContents = response.data.content;
|
||||
try {
|
||||
fileContents = await util.getFileContentsUsingAPI(pieces.groups.owner, pieces.groups.repo, pieces.groups.path, pieces.groups.ref);
|
||||
}
|
||||
else if (Array.isArray(response.data)) {
|
||||
throw new Error(getConfigFileDirectoryGivenMessage(configFile));
|
||||
catch (err) {
|
||||
throw new Error(getConfigFileFormatInvalidMessage(configFile, err.message));
|
||||
}
|
||||
else {
|
||||
throw new Error(getConfigFileFormatInvalidMessage(configFile));
|
||||
}
|
||||
return yaml.safeLoad(Buffer.from(fileContents, 'base64').toString('binary'));
|
||||
return yaml.safeLoad(fileContents);
|
||||
}
|
||||
/**
|
||||
* Get the file path where the parsed config will be stored.
|
||||
|
||||
File diff suppressed because one or more lines are too long
26
lib/config-utils.test.js
generated
26
lib/config-utils.test.js
generated
@@ -18,9 +18,9 @@ const sinon_1 = __importDefault(require("sinon"));
|
||||
const api = __importStar(require("./api-client"));
|
||||
const CodeQL = __importStar(require("./codeql"));
|
||||
const configUtils = __importStar(require("./config-utils"));
|
||||
const testing_utils_1 = require("./testing-utils");
|
||||
const testingUtils = __importStar(require("./testing-utils"));
|
||||
const util = __importStar(require("./util"));
|
||||
testing_utils_1.setupTests(ava_1.default);
|
||||
testingUtils.setupTests(ava_1.default);
|
||||
function setInput(name, value) {
|
||||
// Transformation copied from
|
||||
// https://github.com/actions/toolkit/blob/05e39f551d33e1688f61b209ab5cdd335198f1b8/packages/core/src/core.ts#L69
|
||||
@@ -32,16 +32,6 @@ function setInput(name, value) {
|
||||
delete process.env[envVar];
|
||||
}
|
||||
}
|
||||
function mockGetContents(content) {
|
||||
// Passing an auth token is required, so we just use a dummy value
|
||||
let client = new github.GitHub('123');
|
||||
const response = {
|
||||
data: content
|
||||
};
|
||||
const spyGetContents = sinon_1.default.stub(client.repos, "getContents").resolves(response);
|
||||
sinon_1.default.stub(api, "getApiClient").value(() => client);
|
||||
return spyGetContents;
|
||||
}
|
||||
function mockListLanguages(languages) {
|
||||
// Passing an auth token is required, so we just use a dummy value
|
||||
let client = new github.GitHub('123');
|
||||
@@ -270,7 +260,7 @@ ava_1.default("API client used when reading remote config", async (t) => {
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = mockGetContents(dummyResponse);
|
||||
const spyGetContents = testingUtils.mockGetContents(dummyResponse, 200);
|
||||
// Create checkout directory for remote queries repository
|
||||
fs.mkdirSync(path.join(tmpDir, 'foo/bar'), { recursive: true });
|
||||
setInput('config-file', 'octo-org/codeql-config/config.yaml@main');
|
||||
@@ -284,7 +274,7 @@ ava_1.default("Remote config handles the case where a directory is provided", as
|
||||
process.env['RUNNER_TEMP'] = tmpDir;
|
||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||
const dummyResponse = []; // directories are returned as arrays
|
||||
mockGetContents(dummyResponse);
|
||||
testingUtils.mockGetContents(dummyResponse, 200);
|
||||
const repoReference = 'octo-org/codeql-config/config.yaml@main';
|
||||
setInput('config-file', repoReference);
|
||||
try {
|
||||
@@ -292,7 +282,8 @@ ava_1.default("Remote config handles the case where a directory is provided", as
|
||||
throw new Error('initConfig did not throw error');
|
||||
}
|
||||
catch (err) {
|
||||
t.deepEqual(err, new Error(configUtils.getConfigFileDirectoryGivenMessage(repoReference)));
|
||||
const reason = util.fileIsADirectoryError(repoReference);
|
||||
t.deepEqual(err, new Error(configUtils.getConfigFileFormatInvalidMessage(repoReference, reason)));
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -303,7 +294,7 @@ ava_1.default("Invalid format of remote config handled correctly", async (t) =>
|
||||
const dummyResponse = {
|
||||
// note no "content" property here
|
||||
};
|
||||
mockGetContents(dummyResponse);
|
||||
testingUtils.mockGetContents(dummyResponse, 400);
|
||||
const repoReference = 'octo-org/codeql-config/config.yaml@main';
|
||||
setInput('config-file', repoReference);
|
||||
try {
|
||||
@@ -311,7 +302,8 @@ ava_1.default("Invalid format of remote config handled correctly", async (t) =>
|
||||
throw new Error('initConfig did not throw error');
|
||||
}
|
||||
catch (err) {
|
||||
t.deepEqual(err, new Error(configUtils.getConfigFileFormatInvalidMessage(repoReference)));
|
||||
const reason = util.fileDownloadError(repoReference);
|
||||
t.deepEqual(err, new Error(configUtils.getConfigFileFormatInvalidMessage(repoReference, reason)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
20
lib/testing-utils.js
generated
20
lib/testing-utils.js
generated
@@ -1,7 +1,4 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
@@ -9,8 +6,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const github = __importStar(require("@actions/github"));
|
||||
const sinon_1 = __importDefault(require("sinon"));
|
||||
const api = __importStar(require("./api-client"));
|
||||
const CodeQL = __importStar(require("./codeql"));
|
||||
function wrapOutput(context) {
|
||||
// Function signature taken from Socket.write.
|
||||
@@ -75,4 +77,16 @@ function setupTests(test) {
|
||||
});
|
||||
}
|
||||
exports.setupTests = setupTests;
|
||||
function mockGetContents(content, status) {
|
||||
// Passing an auth token is required, so we just use a dummy value
|
||||
let client = new github.GitHub('123');
|
||||
const response = {
|
||||
data: content,
|
||||
status: status
|
||||
};
|
||||
const spyGetContents = sinon_1.default.stub(client.repos, "getContents").resolves(response);
|
||||
sinon_1.default.stub(api, "getApiClient").value(() => client);
|
||||
return spyGetContents;
|
||||
}
|
||||
exports.mockGetContents = mockGetContents;
|
||||
//# sourceMappingURL=testing-utils.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"testing-utils.js","sourceRoot":"","sources":["../src/testing-utils.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"testing-utils.js","sourceRoot":"","sources":["../src/testing-utils.ts"],"names":[],"mappings":"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"}
|
||||
32
lib/util.js
generated
32
lib/util.js
generated
@@ -378,4 +378,36 @@ function getCodeQLDatabasesDir() {
|
||||
return path.resolve(getRequiredEnvParam('RUNNER_TEMP'), 'codeql_databases');
|
||||
}
|
||||
exports.getCodeQLDatabasesDir = getCodeQLDatabasesDir;
|
||||
function fileDownloadError(file) {
|
||||
return 'Error while trying to download `' + file + '`';
|
||||
}
|
||||
exports.fileDownloadError = fileDownloadError;
|
||||
function fileIsADirectoryError(file) {
|
||||
return '`' + file + '` is a directory';
|
||||
}
|
||||
exports.fileIsADirectoryError = fileIsADirectoryError;
|
||||
async function getFileContentsUsingAPI(owner, repo, path, ref) {
|
||||
const response = await api.getActionsApiClient(true).repos.getContents({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
path: path,
|
||||
ref: ref,
|
||||
});
|
||||
const file = [owner, repo, path].join('/') + '@' + ref;
|
||||
if (response.status !== 200) {
|
||||
throw new Error(fileDownloadError(file));
|
||||
}
|
||||
if (Array.isArray(response.data)) {
|
||||
throw new Error(fileIsADirectoryError(file));
|
||||
}
|
||||
let fileContents;
|
||||
if ("content" in response.data && response.data.content !== undefined) {
|
||||
fileContents = response.data.content;
|
||||
}
|
||||
else {
|
||||
throw new Error(fileDownloadError(file));
|
||||
}
|
||||
return Buffer.from(fileContents, 'base64').toString('binary');
|
||||
}
|
||||
exports.getFileContentsUsingAPI = getFileContentsUsingAPI;
|
||||
//# sourceMappingURL=util.js.map
|
||||
File diff suppressed because one or more lines are too long
37
lib/util.test.js
generated
37
lib/util.test.js
generated
@@ -13,9 +13,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ava_1 = __importDefault(require("ava"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const os = __importStar(require("os"));
|
||||
const testing_utils_1 = require("./testing-utils");
|
||||
const testingUtils = __importStar(require("./testing-utils"));
|
||||
const util = __importStar(require("./util"));
|
||||
testing_utils_1.setupTests(ava_1.default);
|
||||
testingUtils.setupTests(ava_1.default);
|
||||
ava_1.default('getToolNames', t => {
|
||||
const input = fs.readFileSync(__dirname + '/../src/testdata/tool-names.sarif', 'utf8');
|
||||
const toolNames = util.getToolNames(input);
|
||||
@@ -113,4 +113,37 @@ ava_1.default('getExtraOptionsEnvParam() fails on invalid JSON', t => {
|
||||
t.throws(util.getExtraOptionsEnvParam);
|
||||
process.env.CODEQL_ACTION_EXTRA_OPTIONS = origExtraOptions;
|
||||
});
|
||||
ava_1.default('getFileContentsUsingAPI() throws if the request does not succeed', async (t) => {
|
||||
const spyGetContents = testingUtils.mockGetContents({}, 400);
|
||||
try {
|
||||
await util.getFileContentsUsingAPI('github', 'codeql-action', 'non-existing-file', 'main');
|
||||
throw new Error('initConfig did not throw error');
|
||||
}
|
||||
catch (err) {
|
||||
t.assert(spyGetContents.called);
|
||||
t.deepEqual(err, new Error(util.fileDownloadError('github/codeql-action/non-existing-file@main')));
|
||||
}
|
||||
});
|
||||
ava_1.default('getFileContentsUsingAPI() throws if the requested file is a directory', async (t) => {
|
||||
const dummyResponse = []; // directories are returned as arrays
|
||||
const spyGetContents = testingUtils.mockGetContents(dummyResponse, 200);
|
||||
try {
|
||||
await util.getFileContentsUsingAPI('github', 'codeql-action', 'non-existing-file', 'main');
|
||||
throw new Error('initConfig did not throw error');
|
||||
}
|
||||
catch (err) {
|
||||
t.assert(spyGetContents.called);
|
||||
t.deepEqual(err, new Error(util.fileIsADirectoryError('github/codeql-action/non-existing-file@main')));
|
||||
}
|
||||
});
|
||||
ava_1.default('getFileContentsUsingAPI() returns the right content', async (t) => {
|
||||
const inputFileContents = `content content content`;
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = testingUtils.mockGetContents(dummyResponse, 200);
|
||||
const content = await util.getFileContentsUsingAPI('github', 'codeql-action', 'non-existing-file', 'main');
|
||||
t.deepEqual(content, inputFileContents);
|
||||
t.assert(spyGetContents.called);
|
||||
});
|
||||
//# sourceMappingURL=util.test.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -7,10 +7,10 @@ import sinon from 'sinon';
|
||||
import * as api from './api-client';
|
||||
import * as CodeQL from './codeql';
|
||||
import * as configUtils from './config-utils';
|
||||
import {setupTests} from './testing-utils';
|
||||
import * as testingUtils from './testing-utils';
|
||||
import * as util from './util';
|
||||
|
||||
setupTests(test);
|
||||
testingUtils.setupTests(test);
|
||||
|
||||
function setInput(name: string, value: string | undefined) {
|
||||
// Transformation copied from
|
||||
@@ -23,19 +23,6 @@ function setInput(name: string, value: string | undefined) {
|
||||
}
|
||||
}
|
||||
|
||||
type GetContentsResponse = { content?: string; } | {}[];
|
||||
|
||||
function mockGetContents(content: GetContentsResponse): sinon.SinonStub<any, any> {
|
||||
// Passing an auth token is required, so we just use a dummy value
|
||||
let client = new github.GitHub('123');
|
||||
const response = {
|
||||
data: content
|
||||
};
|
||||
const spyGetContents = sinon.stub(client.repos, "getContents").resolves(response as any);
|
||||
sinon.stub(api, "getApiClient").value(() => client);
|
||||
return spyGetContents;
|
||||
}
|
||||
|
||||
function mockListLanguages(languages: string[]) {
|
||||
// Passing an auth token is required, so we just use a dummy value
|
||||
let client = new github.GitHub('123');
|
||||
@@ -303,7 +290,7 @@ test("API client used when reading remote config", async t => {
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = mockGetContents(dummyResponse);
|
||||
const spyGetContents = testingUtils.mockGetContents(dummyResponse, 200);
|
||||
|
||||
// Create checkout directory for remote queries repository
|
||||
fs.mkdirSync(path.join(tmpDir, 'foo/bar'), { recursive: true });
|
||||
@@ -322,7 +309,7 @@ test("Remote config handles the case where a directory is provided", async t =>
|
||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||
|
||||
const dummyResponse = []; // directories are returned as arrays
|
||||
mockGetContents(dummyResponse);
|
||||
testingUtils.mockGetContents(dummyResponse, 200);
|
||||
|
||||
const repoReference = 'octo-org/codeql-config/config.yaml@main';
|
||||
setInput('config-file', repoReference);
|
||||
@@ -330,7 +317,8 @@ test("Remote config handles the case where a directory is provided", async t =>
|
||||
await configUtils.initConfig();
|
||||
throw new Error('initConfig did not throw error');
|
||||
} catch (err) {
|
||||
t.deepEqual(err, new Error(configUtils.getConfigFileDirectoryGivenMessage(repoReference)));
|
||||
const reason = util.fileIsADirectoryError(repoReference);
|
||||
t.deepEqual(err, new Error(configUtils.getConfigFileFormatInvalidMessage(repoReference, reason)));
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -343,7 +331,7 @@ test("Invalid format of remote config handled correctly", async t => {
|
||||
const dummyResponse = {
|
||||
// note no "content" property here
|
||||
};
|
||||
mockGetContents(dummyResponse);
|
||||
testingUtils.mockGetContents(dummyResponse, 400);
|
||||
|
||||
const repoReference = 'octo-org/codeql-config/config.yaml@main';
|
||||
setInput('config-file', repoReference);
|
||||
@@ -351,7 +339,8 @@ test("Invalid format of remote config handled correctly", async t => {
|
||||
await configUtils.initConfig();
|
||||
throw new Error('initConfig did not throw error');
|
||||
} catch (err) {
|
||||
t.deepEqual(err, new Error(configUtils.getConfigFileFormatInvalidMessage(repoReference)));
|
||||
const reason = util.fileDownloadError(repoReference);
|
||||
t.deepEqual(err, new Error(configUtils.getConfigFileFormatInvalidMessage(repoReference, reason)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -399,12 +399,8 @@ export function getConfigFileRepoFormatInvalidMessage(configFile: string): strin
|
||||
return error;
|
||||
}
|
||||
|
||||
export function getConfigFileFormatInvalidMessage(configFile: string): string {
|
||||
return 'The configuration file "' + configFile + '" could not be read';
|
||||
}
|
||||
|
||||
export function getConfigFileDirectoryGivenMessage(configFile: string): string {
|
||||
return 'The configuration file "' + configFile + '" looks like a directory, not a file';
|
||||
export function getConfigFileFormatInvalidMessage(configFile: string, reason: string): string {
|
||||
return 'The configuration file "' + configFile + '" could not be read. Reason: ' + reason;
|
||||
}
|
||||
|
||||
function getConfigFilePropertyError(configFile: string, property: string, error: string): string {
|
||||
@@ -689,23 +685,18 @@ async function getRemoteConfig(configFile: string): Promise<UserConfig> {
|
||||
throw new Error(getConfigFileRepoFormatInvalidMessage(configFile));
|
||||
}
|
||||
|
||||
const response = await api.getActionsApiClient(true).repos.getContents({
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
ref: pieces.groups.ref,
|
||||
});
|
||||
|
||||
let fileContents: string;
|
||||
if ("content" in response.data && response.data.content !== undefined) {
|
||||
fileContents = response.data.content;
|
||||
} else if (Array.isArray(response.data)) {
|
||||
throw new Error(getConfigFileDirectoryGivenMessage(configFile));
|
||||
} else {
|
||||
throw new Error(getConfigFileFormatInvalidMessage(configFile));
|
||||
try {
|
||||
fileContents = await util.getFileContentsUsingAPI(
|
||||
pieces.groups.owner,
|
||||
pieces.groups.repo,
|
||||
pieces.groups.path,
|
||||
pieces.groups.ref);
|
||||
} catch (err) {
|
||||
throw new Error(getConfigFileFormatInvalidMessage(configFile, err.message));
|
||||
}
|
||||
|
||||
return yaml.safeLoad(Buffer.from(fileContents, 'base64').toString('binary'));
|
||||
return yaml.safeLoad(fileContents);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as github from "@actions/github";
|
||||
import {TestInterface} from 'ava';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import * as api from './api-client';
|
||||
import * as CodeQL from './codeql';
|
||||
|
||||
type TestContext = {stdoutWrite: any, stderrWrite: any, testOutput: string, env: NodeJS.ProcessEnv};
|
||||
@@ -77,3 +79,18 @@ export function setupTests(test: TestInterface<any>) {
|
||||
process.env = t.context.env;
|
||||
});
|
||||
}
|
||||
|
||||
export type GetContentsResponse = { content?: string; } | {}[];
|
||||
|
||||
export function mockGetContents(content: GetContentsResponse, status: number): sinon.SinonStub<any, any> {
|
||||
// Passing an auth token is required, so we just use a dummy value
|
||||
let client = new github.GitHub('123');
|
||||
const response = {
|
||||
data: content,
|
||||
status: status
|
||||
};
|
||||
|
||||
const spyGetContents = sinon.stub(client.repos, "getContents").resolves(response as any);
|
||||
sinon.stub(api, "getApiClient").value(() => client);
|
||||
return spyGetContents;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ import test from 'ava';
|
||||
import * as fs from 'fs';
|
||||
import * as os from "os";
|
||||
|
||||
import {setupTests} from './testing-utils';
|
||||
|
||||
import * as testingUtils from './testing-utils';
|
||||
import * as util from './util';
|
||||
|
||||
setupTests(test);
|
||||
testingUtils.setupTests(test);
|
||||
|
||||
test('getToolNames', t => {
|
||||
const input = fs.readFileSync(__dirname + '/../src/testdata/tool-names.sarif', 'utf8');
|
||||
@@ -150,3 +151,38 @@ test('getExtraOptionsEnvParam() fails on invalid JSON', t => {
|
||||
|
||||
process.env.CODEQL_ACTION_EXTRA_OPTIONS = origExtraOptions;
|
||||
});
|
||||
|
||||
test('getFileContentsUsingAPI() throws if the request does not succeed', async t => {
|
||||
const spyGetContents = testingUtils.mockGetContents({}, 400);
|
||||
try {
|
||||
await util.getFileContentsUsingAPI('github', 'codeql-action', 'non-existing-file', 'main');
|
||||
throw new Error('initConfig did not throw error');
|
||||
} catch (err) {
|
||||
t.assert(spyGetContents.called);
|
||||
t.deepEqual(err, new Error(util.fileDownloadError('github/codeql-action/non-existing-file@main')));
|
||||
}
|
||||
});
|
||||
|
||||
test('getFileContentsUsingAPI() throws if the requested file is a directory', async t => {
|
||||
const dummyResponse = []; // directories are returned as arrays
|
||||
const spyGetContents = testingUtils.mockGetContents(dummyResponse, 200);
|
||||
try {
|
||||
await util.getFileContentsUsingAPI('github', 'codeql-action', 'non-existing-file', 'main');
|
||||
throw new Error('initConfig did not throw error');
|
||||
} catch (err) {
|
||||
t.assert(spyGetContents.called);
|
||||
t.deepEqual(err, new Error(util.fileIsADirectoryError('github/codeql-action/non-existing-file@main')));
|
||||
}
|
||||
});
|
||||
|
||||
test('getFileContentsUsingAPI() returns the right content', async t => {
|
||||
const inputFileContents = `content content content`;
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = testingUtils.mockGetContents(dummyResponse, 200);
|
||||
const content = await util.getFileContentsUsingAPI('github', 'codeql-action', 'non-existing-file', 'main');
|
||||
|
||||
t.deepEqual(content, inputFileContents);
|
||||
t.assert(spyGetContents.called);
|
||||
});
|
||||
|
||||
36
src/util.ts
36
src/util.ts
@@ -433,3 +433,39 @@ export function getThreadsFlag(): string {
|
||||
export function getCodeQLDatabasesDir() {
|
||||
return path.resolve(getRequiredEnvParam('RUNNER_TEMP'), 'codeql_databases');
|
||||
}
|
||||
|
||||
export function fileDownloadError(file: string): string {
|
||||
return 'Error while trying to download `' + file + '`';
|
||||
}
|
||||
|
||||
export function fileIsADirectoryError(file: string): string {
|
||||
return '`' + file + '` is a directory';
|
||||
}
|
||||
|
||||
export async function getFileContentsUsingAPI(owner: string, repo: string, path: string, ref: string): Promise<string> {
|
||||
const response = await api.getActionsApiClient(true).repos.getContents({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
path: path,
|
||||
ref: ref,
|
||||
});
|
||||
|
||||
const file = [owner, repo, path].join('/') + '@' + ref;
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(fileDownloadError(file));
|
||||
}
|
||||
|
||||
if (Array.isArray(response.data)) {
|
||||
throw new Error(fileIsADirectoryError(file));
|
||||
}
|
||||
|
||||
let fileContents: string;
|
||||
if ("content" in response.data && response.data.content !== undefined) {
|
||||
fileContents = response.data.content;
|
||||
} else {
|
||||
throw new Error(fileDownloadError(file));
|
||||
}
|
||||
|
||||
return Buffer.from(fileContents, 'base64').toString('binary');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user