From 6d7a135feaa07851262f55294bc4629a3ca9c7ea Mon Sep 17 00:00:00 2001 From: Robert Brignull Date: Tue, 11 Aug 2020 12:42:42 +0100 Subject: [PATCH] Add a CLI interface to the upload-sarif action --- .gitignore | 2 + package.json | 7 +- src/api-client.ts | 35 +++++++- src/cli.ts | 82 ++++++++++++++++++ src/codeql.ts | 2 +- src/config-utils.ts | 4 +- src/finalize-db.ts | 17 +++- src/logging.ts | 26 ++++++ src/repository.ts | 16 ++++ src/testing-utils.ts | 4 + src/upload-lib.test.ts | 5 +- src/upload-lib.ts | 184 ++++++++++++++++++++++++----------------- src/upload-sarif.ts | 17 +++- src/util.ts | 19 +++-- webpack.config.js | 26 ++++++ 15 files changed, 356 insertions(+), 90 deletions(-) create mode 100644 .gitignore create mode 100644 src/cli.ts create mode 100644 src/logging.ts create mode 100644 src/repository.ts create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..939bdb3ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/cli/ + diff --git a/package.json b/package.json index 761044dbb..94523ca21 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "description": "CodeQL action", "scripts": { "build": "tsc", + "build-cli": "webpack --mode production", "test": "ava src/** --serial --verbose", "lint": "tslint -p . -c tslint.json 'src/**/*.ts'", "removeNPMAbsolutePaths": "removeNPMAbsolutePaths . --force" @@ -23,6 +24,7 @@ "@actions/github": "^2.2.0", "@actions/http-client": "^1.0.8", "@actions/tool-cache": "^1.5.5", + "commander": "6.0.0", "console-log-level": "^1.4.1", "file-url": "^3.0.0", "fs": "0.0.1-security", @@ -52,6 +54,9 @@ "sinon": "^9.0.2", "tslint": "^6.1.0", "tslint-eslint-rules": "^5.4.0", - "typescript": "^3.7.5" + "ts-loader": "8.0.2", + "typescript": "^3.7.5", + "webpack": "4.44.1", + "webpack-cli": "3.3.12" } } \ No newline at end of file diff --git a/src/api-client.ts b/src/api-client.ts index cee534d3a..2e5e84869 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -2,16 +2,45 @@ import * as core from "@actions/core"; import * as github from "@actions/github"; import consoleLogLevel from "console-log-level"; -import { isLocalRun } from "./util"; +import { getRequiredEnvParam, isLocalRun } from "./util"; -export const getApiClient = function(allowLocalRun = false) { +export const getApiClient = function(githubAuth: string, githubApiUrl: string, allowLocalRun = false) { if (isLocalRun() && !allowLocalRun) { throw new Error('Invalid API call in local run'); } return new github.GitHub( - core.getInput('token'), { + auth: parseAuth(githubAuth), + baseUrl: githubApiUrl, userAgent: "CodeQL Action", log: consoleLogLevel({ level: "debug" }) }); }; + +// Parses the user input as either a single token, +// or a username and password / PAT. +function parseAuth(auth: string): string { + // Check if it's a username:password pair + const c = auth.indexOf(':'); + if (c !== -1) { + return 'basic ' + Buffer.from(auth).toString('base64'); + // return { + // username: auth.substring(0, c), + // password: auth.substring(c + 1), + // on2fa: async () => { throw new Error(''); } + // }; + } + + // Otherwise use the token as it is + return auth; +} + +// Temporary function to aid in the transition to running on and off of github actions. +// Once all code has been coverted this function should be removed or made canonical +// and called only from the action entrypoints. +export function getActionsApiClient(allowLocalRun = false) { + return getApiClient( + core.getInput('token'), + getRequiredEnvParam('GITHUB_API_URL'), + allowLocalRun); +} diff --git a/src/cli.ts b/src/cli.ts new file mode 100644 index 000000000..c1ea96f79 --- /dev/null +++ b/src/cli.ts @@ -0,0 +1,82 @@ +import { Command } from 'commander'; +import * as path from 'path'; + +import { getCLILogger } from './logging'; +import { parseRepositoryNwo } from './repository'; +import * as upload_lib from './upload-lib'; + +const program = new Command(); +program.version('0.0.1'); + +interface UploadArgs { + sarifFile: string; + repository: string; + commit: string; + ref: string; + analysisKey: string; + githubUrl: string; + githubAuth: string; + analysisName: string | undefined; + checkoutPath: string | undefined; + environment: string | undefined; +} + +function parseGithubApiUrl(inputUrl: string): string { + try { + const url = new URL(inputUrl); + + // If we detect this is trying to be to github.com + // then return with a fixed canonical URL. + if (url.hostname === 'github.com' || url.hostname === 'api.github.com') { + return 'https://api.github.com'; + } + + // Add the API path if it's not already present. + if (url.pathname.indexOf('/api/v3') === -1) { + url.pathname = path.join(url.pathname, 'api', 'v3'); + } + + return url.toString(); + + } catch (e) { + throw new Error(`"${inputUrl}" is not a valid URL`); + } +} + +program + .command('upload') + .description('Uploads a SARIF file, or all SARIF files from a directory, to code scanning') + .requiredOption('--sarif-file ', 'SARIF file to upload') + .requiredOption('--repository ', 'Repository name') + .requiredOption('--commit ', 'SHA of commit that was analyzed') + .requiredOption('--ref ', 'Name of ref that was analyzed') + .requiredOption('--analysis-key ', 'Identifies the analysis, for use matching up equivalent analyses on different commits') + .requiredOption('--github-url ', 'URL of GitHub instance') + .requiredOption('--github-auth ', 'GitHub Apps token, or of the form "username:token" if using a personal access token') + .option('--checkout-path ', 'Checkout path (default: current working directory)') + .option('--analysis-name ', 'Display name of the analysis (default: same as analysis-key') + .option('--environment ', 'Environment (default: empty)') + .action(async (cmd: UploadArgs) => { + const logger = getCLILogger(); + try { + await upload_lib.upload( + cmd.sarifFile, + parseRepositoryNwo(cmd.repository), + cmd.commit, + cmd.ref, + cmd.analysisKey, + cmd.analysisName || cmd.analysisKey, + undefined, + cmd.checkoutPath || process.cwd(), + cmd.environment, + cmd.githubAuth, + parseGithubApiUrl(cmd.githubUrl), + 'cli', + logger); + } catch (e) { + logger.error("Upload failed"); + logger.error(e); + } + }); + +program.parse(process.argv); diff --git a/src/codeql.ts b/src/codeql.ts index d8aa2f23b..c02cd2f6e 100644 --- a/src/codeql.ts +++ b/src/codeql.ts @@ -121,7 +121,7 @@ async function getCodeQLBundleDownloadURL(): Promise { } let [repositoryOwner, repositoryName] = repository.split("/"); try { - const release = await api.getApiClient().repos.getReleaseByTag({ + const release = await api.getActionsApiClient().repos.getReleaseByTag({ owner: repositoryOwner, repo: repositoryName, tag: CODEQL_BUNDLE_VERSION diff --git a/src/config-utils.ts b/src/config-utils.ts index 7474f3839..b886806d3 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -441,7 +441,7 @@ async function getLanguagesInRepo(): Promise { let repo = repo_nwo[1]; core.debug(`GitHub repo ${owner} ${repo}`); - const response = await api.getApiClient(true).repos.listLanguages({ + const response = await api.getActionsApiClient(true).repos.listLanguages({ owner, repo }); @@ -689,7 +689,7 @@ async function getRemoteConfig(configFile: string): Promise { throw new Error(getConfigFileRepoFormatInvalidMessage(configFile)); } - const response = await api.getApiClient(true).repos.getContents({ + const response = await api.getActionsApiClient(true).repos.getContents({ owner: pieces.groups.owner, repo: pieces.groups.repo, path: pieces.groups.path, diff --git a/src/finalize-db.ts b/src/finalize-db.ts index 6b2635d78..ce2b037fe 100644 --- a/src/finalize-db.ts +++ b/src/finalize-db.ts @@ -4,6 +4,8 @@ import * as path from 'path'; import { getCodeQL, isScannedLanguage } from './codeql'; import * as configUtils from './config-utils'; +import { getActionsLogger } from './logging'; +import { parseRepositoryNwo } from './repository'; import * as sharedEnv from './shared-environment'; import * as upload_lib from './upload-lib'; import * as util from './util'; @@ -144,7 +146,20 @@ async function run() { queriesStats = await runQueries(databaseFolder, sarifFolder, config); if ('true' === core.getInput('upload')) { - uploadStats = await upload_lib.upload(sarifFolder); + uploadStats = await upload_lib.upload( + sarifFolder, + parseRepositoryNwo(util.getRequiredEnvParam('GITHUB_REPOSITORY')), + await util.getCommitOid(), + util.getRef(), + await util.getAnalysisKey(), + util.getRequiredEnvParam('GITHUB_WORKFLOW'), + util.getWorkflowRunID(), + core.getInput('checkout_path'), + core.getInput('matrix'), + core.getInput('token'), + util.getRequiredEnvParam('GITHUB_API_URL'), + 'actions', + getActionsLogger()); } } catch (error) { diff --git a/src/logging.ts b/src/logging.ts new file mode 100644 index 000000000..fb74b93bf --- /dev/null +++ b/src/logging.ts @@ -0,0 +1,26 @@ +import * as core from '@actions/core'; + +export interface Logger { + debug: (message: string) => void; + info: (message: string) => void; + warning: (message: string) => void; + error: (message: string) => void; + + startGroup: (name: string) => void; + endGroup: () => void; +} + +export function getActionsLogger(): Logger { + return core; +} + +export function getCLILogger(): Logger { + return { + debug: console.debug, + info: console.info, + warning: console.warn, + error: console.error, + startGroup: () => undefined, + endGroup: () => undefined, + }; +} diff --git a/src/repository.ts b/src/repository.ts new file mode 100644 index 000000000..f34c2a418 --- /dev/null +++ b/src/repository.ts @@ -0,0 +1,16 @@ +// A repository name with owner, parsed into its two parts +export interface RepositoryNwo { + owner: string; + repo: string; +} + +export function parseRepositoryNwo(input: string): RepositoryNwo { + const parts = input.split('/'); + if (parts.length !== 2) { + throw new Error(`"${input}" is not a valid repository name`); + } + return { + owner: parts[0], + repo: parts[1], + }; +} diff --git a/src/testing-utils.ts b/src/testing-utils.ts index f4192f5e7..d2b8d682e 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -55,6 +55,10 @@ export function setupTests(test: TestInterface) { // process.env only has strings fields, so a shallow copy is fine. t.context.env = {}; Object.assign(t.context.env, process.env); + + // Any test that runs code that expects to only be run on actions + // will depend on various environment variables. + process.env['GITHUB_API_URL'] = 'https://github.localhost/api/v3'; }); typedTest.afterEach.always(t => { diff --git a/src/upload-lib.test.ts b/src/upload-lib.test.ts index 50fb0c812..9f1ebed07 100644 --- a/src/upload-lib.test.ts +++ b/src/upload-lib.test.ts @@ -1,5 +1,6 @@ import test from 'ava'; +import { getCLILogger } from './logging'; import {setupTests} from './testing-utils'; import * as uploadLib from './upload-lib'; @@ -7,10 +8,10 @@ setupTests(test); test('validateSarifFileSchema - valid', t => { const inputFile = __dirname + '/../src/testdata/valid-sarif.sarif'; - t.notThrows(() => uploadLib.validateSarifFileSchema(inputFile)); + t.notThrows(() => uploadLib.validateSarifFileSchema(inputFile, getCLILogger())); }); test('validateSarifFileSchema - invalid', t => { const inputFile = __dirname + '/../src/testdata/invalid-sarif.sarif'; - t.throws(() => uploadLib.validateSarifFileSchema(inputFile)); + t.throws(() => uploadLib.validateSarifFileSchema(inputFile, getCLILogger())); }); diff --git a/src/upload-lib.ts b/src/upload-lib.ts index f0ab8b798..66bc5addb 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -1,4 +1,3 @@ -import * as core from '@actions/core'; import fileUrl from 'file-url'; import * as fs from 'fs'; import * as jsonschema from 'jsonschema'; @@ -7,9 +6,12 @@ import zlib from 'zlib'; import * as api from './api-client'; import * as fingerprints from './fingerprints'; -import * as sharedEnv from './shared-environment'; +import { Logger } from './logging'; +import { RepositoryNwo } from './repository'; import * as util from './util'; +type UploadMode = 'actions' | 'cli'; + // Takes a list of paths to sarif files and combines them together, // returning the contents of the combined sarif file. export function combineSarifFiles(sarifFiles: string[]): string { @@ -35,8 +37,15 @@ export function combineSarifFiles(sarifFiles: string[]): string { // Upload the given payload. // If the request fails then this will retry a small number of times. -async function uploadPayload(payload) { - core.info('Uploading results'); +async function uploadPayload( + payload: any, + repositoryNwo: RepositoryNwo, + githubAuth: string, + githubApiUrl: string, + mode: UploadMode, + logger: Logger) { + + logger.info('Uploading results'); // If in test mode we don't want to upload the results const testMode = process.env['TEST_MODE'] === 'true' || false; @@ -44,26 +53,29 @@ async function uploadPayload(payload) { return; } - const [owner, repo] = util.getRequiredEnvParam("GITHUB_REPOSITORY").split("/"); - // Make up to 4 attempts to upload, and sleep for these // number of seconds between each attempt. // We don't want to backoff too much to avoid wasting action // minutes, but just waiting a little bit could maybe help. const backoffPeriods = [1, 5, 15]; + const client = api.getApiClient(githubAuth, githubApiUrl); + for (let attempt = 0; attempt <= backoffPeriods.length; attempt++) { - const response = await api.getApiClient().request("PUT /repos/:owner/:repo/code-scanning/analysis", ({ - owner: owner, - repo: repo, + const reqURL = mode === 'actions' + ? 'PUT /repos/:owner/:repo/code-scanning/analysis' + : 'POST /repos/:owner/:repo/code-scanning/sarifs'; + const response = await client.request(reqURL, ({ + owner: repositoryNwo.owner, + repo: repositoryNwo.repo, data: payload, })); - core.debug('response status: ' + response.status); + logger.debug('response status: ' + response.status); const statusCode = response.status; if (statusCode === 202) { - core.info("Successfully uploaded results"); + logger.info("Successfully uploaded results"); return; } @@ -77,7 +89,7 @@ async function uploadPayload(payload) { // On a 5xx status code we may retry the request if (attempt < backoffPeriods.length) { // Log the failure as a warning but don't mark the action as failed yet - core.warning('Upload attempt (' + (attempt + 1) + ' of ' + (backoffPeriods.length + 1) + + logger.warning('Upload attempt (' + (attempt + 1) + ' of ' + (backoffPeriods.length + 1) + ') failed (' + requestID + '). Retrying in ' + backoffPeriods[attempt] + ' seconds: (' + statusCode + ') ' + JSON.stringify(response.data)); // Sleep for the backoff period @@ -109,18 +121,48 @@ export interface UploadStatusReport { // Uploads a single sarif file or a directory of sarif files // depending on what the path happens to refer to. // Returns true iff the upload occurred and succeeded -export async function upload(input: string): Promise { - if (fs.lstatSync(input).isDirectory()) { - const sarifFiles = fs.readdirSync(input) +export async function upload( + sarifFile: string, + repositoryNwo: RepositoryNwo, + commitOid: string, + ref: string, + analysisKey: string, + analysisName: string, + workflowRunID: number | undefined, + checkoutPath: string, + environment: string | undefined, + githubAuth: string, + githubApiUrl: string, + mode: UploadMode, + logger: Logger): Promise { + + const sarifFiles: string[] = []; + if (fs.lstatSync(sarifFile).isDirectory()) { + fs.readdirSync(sarifFile) .filter(f => f.endsWith(".sarif")) - .map(f => path.resolve(input, f)); + .map(f => path.resolve(sarifFile, f)) + .forEach(f => sarifFiles.push(f)); if (sarifFiles.length === 0) { - throw new Error("No SARIF files found to upload in \"" + input + "\"."); + throw new Error("No SARIF files found to upload in \"" + sarifFile + "\"."); } - return await uploadFiles(sarifFiles); } else { - return await uploadFiles([input]); + sarifFiles.push(sarifFile); } + + return await uploadFiles( + sarifFiles, + repositoryNwo, + commitOid, + ref, + analysisKey, + analysisName, + workflowRunID, + checkoutPath, + environment, + githubAuth, + githubApiUrl, + mode, + logger); } // Counts the number of results in the given SARIF file @@ -134,17 +176,17 @@ export function countResultsInSarif(sarif: string): number { // Validates that the given file path refers to a valid SARIF file. // Throws an error if the file is invalid. -export function validateSarifFileSchema(sarifFilePath: string) { +export function validateSarifFileSchema(sarifFilePath: string, logger: Logger) { const sarif = JSON.parse(fs.readFileSync(sarifFilePath, 'utf8')); - const schema = JSON.parse(fs.readFileSync(__dirname + '/../src/sarif_v2.1.0_schema.json', 'utf8')); + const schema = require('../src/sarif_v2.1.0_schema.json'); const result = new jsonschema.Validator().validate(sarif, schema); if (!result.valid) { // Output the more verbose error messages in groups as these may be very large. for (const error of result.errors) { - core.startGroup("Error details: " + error.stack); - core.info(JSON.stringify(error, null, 2)); - core.endGroup(); + logger.startGroup("Error details: " + error.stack); + logger.info(JSON.stringify(error, null, 2)); + logger.endGroup(); } // Set the main error message to the stacks of all the errors. @@ -156,75 +198,69 @@ export function validateSarifFileSchema(sarifFilePath: string) { // Uploads the given set of sarif files. // Returns true iff the upload occurred and succeeded -async function uploadFiles(sarifFiles: string[]): Promise { - core.startGroup("Uploading results"); - core.info("Uploading sarif files: " + JSON.stringify(sarifFiles)); - - const sentinelEnvVar = "CODEQL_UPLOAD_SARIF"; - if (process.env[sentinelEnvVar]) { - throw new Error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job"); - } - core.exportVariable(sentinelEnvVar, sentinelEnvVar); +async function uploadFiles( + sarifFiles: string[], + repositoryNwo: RepositoryNwo, + commitOid: string, + ref: string, + analysisKey: string, + analysisName: string, + workflowRunID: number | undefined, + checkoutPath: string, + environment: string | undefined, + githubAuth: string, + githubApiUrl: string, + mode: UploadMode, + logger: Logger): Promise { + + logger.info("Uploading sarif files: " + JSON.stringify(sarifFiles)); // Validate that the files we were asked to upload are all valid SARIF files for (const file of sarifFiles) { - validateSarifFileSchema(file); + validateSarifFileSchema(file, logger); } - const commitOid = await util.getCommitOid(); - const workflowRunIDStr = util.getRequiredEnvParam('GITHUB_RUN_ID'); - const ref = util.getRef(); - const analysisKey = await util.getAnalysisKey(); - const analysisName = util.getRequiredEnvParam('GITHUB_WORKFLOW'); - const startedAt = process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT]; - let sarifPayload = combineSarifFiles(sarifFiles); sarifPayload = fingerprints.addFingerprints(sarifPayload); const zipped_sarif = zlib.gzipSync(sarifPayload).toString('base64'); - let checkoutPath = core.getInput('checkout_path'); let checkoutURI = fileUrl(checkoutPath); - const workflowRunID = parseInt(workflowRunIDStr, 10); - - if (Number.isNaN(workflowRunID)) { - throw new Error('GITHUB_RUN_ID must define a non NaN workflow run ID'); - } - - let matrix: string | undefined = core.getInput('matrix'); - if (matrix === "null" || matrix === "") { - matrix = undefined; - } const toolNames = util.getToolNames(sarifPayload); - const payload = JSON.stringify({ - "commit_oid": commitOid, - "ref": ref, - "analysis_key": analysisKey, - "analysis_name": analysisName, - "sarif": zipped_sarif, - "workflow_run_id": workflowRunID, - "checkout_uri": checkoutURI, - "environment": matrix, - "started_at": startedAt, - "tool_names": toolNames, - }); + let payload: string; + if (mode === 'actions') { + payload = JSON.stringify({ + "commit_oid": commitOid, + "ref": ref, + "analysis_key": analysisKey, + "analysis_name": analysisName, + "sarif": zipped_sarif, + "workflow_run_id": workflowRunID, + "checkout_uri": checkoutURI, + "environment": environment, + "tool_names": toolNames, + }); + } else { + payload = JSON.stringify({ + "commit_sha": commitOid, + "ref": ref, + "sarif": zipped_sarif, + "checkout_uri": checkoutURI, + "tool_name": toolNames[0], + }); + } // Log some useful debug info about the info const rawUploadSizeBytes = sarifPayload.length; - core.debug("Raw upload size: " + rawUploadSizeBytes + " bytes"); + console.debug("Raw upload size: " + rawUploadSizeBytes + " bytes"); const zippedUploadSizeBytes = zipped_sarif.length; - core.debug("Base64 zipped upload size: " + zippedUploadSizeBytes + " bytes"); + console.debug("Base64 zipped upload size: " + zippedUploadSizeBytes + " bytes"); const numResultInSarif = countResultsInSarif(sarifPayload); - core.debug("Number of results in upload: " + numResultInSarif); + console.debug("Number of results in upload: " + numResultInSarif); - if (!util.isLocalRun()) { - // Make the upload - await uploadPayload(payload); - } else { - core.debug("Not uploading because this is a local run."); - } - core.endGroup(); + // Make the upload + await uploadPayload(payload, repositoryNwo, githubAuth, githubApiUrl, mode, logger); return { raw_upload_size_bytes: rawUploadSizeBytes, diff --git a/src/upload-sarif.ts b/src/upload-sarif.ts index a5973558e..7e9ed375e 100644 --- a/src/upload-sarif.ts +++ b/src/upload-sarif.ts @@ -1,5 +1,7 @@ import * as core from '@actions/core'; +import { getActionsLogger } from './logging'; +import { parseRepositoryNwo } from './repository'; import * as upload_lib from './upload-lib'; import * as util from './util'; @@ -21,7 +23,20 @@ async function run() { } try { - const uploadStats = await upload_lib.upload(core.getInput('sarif_file')); + const uploadStats = await upload_lib.upload( + core.getInput('sarif_file'), + parseRepositoryNwo(util.getRequiredEnvParam('GITHUB_REPOSITORY')), + await util.getCommitOid(), + util.getRef(), + await util.getAnalysisKey(), + util.getRequiredEnvParam('GITHUB_WORKFLOW'), + util.getWorkflowRunID(), + core.getInput('checkout_path'), + core.getInput('matrix'), + core.getInput('token'), + util.getRequiredEnvParam('GITHUB_API_URL'), + 'actions', + getActionsLogger()); await sendSuccessStatusReport(startedAt, uploadStats); } catch (error) { diff --git a/src/util.ts b/src/util.ts index 8716854b3..e3ab9d831 100644 --- a/src/util.ts +++ b/src/util.ts @@ -90,15 +90,12 @@ export async function getCommitOid(): Promise { * Get the path of the currently executing workflow. */ async function getWorkflowPath(): Promise { - if (isLocalRun()) { - return 'LOCAL'; - } const repo_nwo = getRequiredEnvParam('GITHUB_REPOSITORY').split("/"); const owner = repo_nwo[0]; const repo = repo_nwo[1]; const run_id = Number(getRequiredEnvParam('GITHUB_RUN_ID')); - const apiClient = api.getApiClient(); + const apiClient = api.getActionsApiClient(); const runsResponse = await apiClient.request('GET /repos/:owner/:repo/actions/runs/:run_id', { owner, repo, @@ -111,6 +108,17 @@ async function getWorkflowPath(): Promise { return workflowResponse.data.path; } +/** + * Get the workflow run ID. + */ +export function getWorkflowRunID(): number { + const workflowRunID = parseInt(getRequiredEnvParam('GITHUB_RUN_ID'), 10); + if (Number.isNaN(workflowRunID)) { + throw new Error('GITHUB_RUN_ID must define a non NaN workflow run ID'); + } + return workflowRunID; +} + /** * Get the analysis key paramter for the current job. * @@ -283,7 +291,8 @@ export async function sendStatusReport( const nwo = getRequiredEnvParam("GITHUB_REPOSITORY"); const [owner, repo] = nwo.split("/"); - const statusResponse = await api.getApiClient().request('PUT /repos/:owner/:repo/code-scanning/analysis/status', { + const client = api.getActionsApiClient(); + const statusResponse = await client.request('PUT /repos/:owner/:repo/code-scanning/analysis/status', { owner: owner, repo: repo, data: statusReportJSON, diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 000000000..c1e632e97 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,26 @@ +const path = require('path'); + +module.exports = { + entry: './src/cli.ts', + module: { + rules: [ + { + test: /\.ts$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + target: 'node', + resolve: { + extensions: [ '.ts', '.js' ], + }, + output: { + filename: 'cli.js', + path: path.resolve(__dirname, 'cli'), + }, + optimization: { + // We no not want to minimize our code. + minimize: false + }, +};