Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions init/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ inputs:
your workflow between the `init` and `analyze` steps. Available for all
compiled languages.
required: false
analysis-kinds:
description: >-
[Internal] A comma-separated list of analysis kinds to enable. This input is intended for
internal-use only at this time and the behaviour is subject to changes. Some features may
not be available depending on which analysis kinds are enabled.
Available options are:
- `code-scanning`: The default, security-focused analysis.
- `code-quality`: Analysis focused on code quality. This must be enabled in conjunction
with `code-scanning`.
Comment on lines +54 to +55
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of interest, where's this restriction coming from? We can address it in a follow up PR, but I think we want to be able to run code quality only analyses.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this restriction will be lifted in a follow-up PR. It's just representative of the current state of the implementation as of this PR.

default: 'code-scanning'
required: true
token:
description: GitHub token to use for authenticating with this instance of GitHub. To download custom packs from multiple registries, use the registries input.
default: ${{ github.token }}
Expand Down
27 changes: 26 additions & 1 deletion lib/analyses.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/analyses.js.map

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

31 changes: 31 additions & 0 deletions lib/analyses.test.js

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

1 change: 1 addition & 0 deletions lib/analyses.test.js.map

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

14 changes: 12 additions & 2 deletions lib/config-utils.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/config-utils.js.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions lib/config-utils.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/config-utils.test.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/init-action.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/init-action.js.map

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions src/analyses.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import test from "ava";

import {
AnalysisKind,
parseAnalysisKinds,
supportedAnalysisKinds,
} from "./analyses";
import { ConfigurationError } from "./util";

test("All known analysis kinds can be parsed successfully", async (t) => {
for (const analysisKind of supportedAnalysisKinds) {
t.deepEqual(await parseAnalysisKinds(analysisKind), [analysisKind]);
}
});

test("Parsing analysis kinds returns unique results", async (t) => {
const analysisKinds = await parseAnalysisKinds(
"code-scanning,code-quality,code-scanning",
);
t.deepEqual(analysisKinds, [
AnalysisKind.CodeScanning,
AnalysisKind.CodeQuality,
]);
});

test("Parsing an unknown analysis kind fails with a configuration error", async (t) => {
await t.throwsAsync(parseAnalysisKinds("code-scanning,foo"), {
instanceOf: ConfigurationError,
});
});

test("Parsing analysis kinds requires at least one analysis kind", async (t) => {
await t.throwsAsync(parseAnalysisKinds(","), {
instanceOf: ConfigurationError,
});
});
36 changes: 36 additions & 0 deletions src/analyses.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,40 @@
import { ConfigurationError } from "./util";

export enum AnalysisKind {
CodeScanning = "code-scanning",
CodeQuality = "code-quality",
}

// Exported for testing. A set of all known analysis kinds.
export const supportedAnalysisKinds = new Set(Object.values(AnalysisKind));

/**
* Parses a comma-separated string into a list of unique analysis kinds.
* Throws a configuration error if the input contains unknown analysis kinds
* or doesn't contain at least one element.
*
* @param input The comma-separated string to parse.
* @returns The array of unique analysis kinds that were parsed from the input string.
*/
export async function parseAnalysisKinds(
input: string,
): Promise<AnalysisKind[]> {
const components = input.split(",");

if (components.length < 1) {
throw new ConfigurationError(
"At least one analysis kind must be configured.",
);
}

for (const component of components) {
if (!supportedAnalysisKinds.has(component as AnalysisKind)) {
throw new ConfigurationError(`Unknown analysis kind: ${component}`);
}
}

// Return all unique elements.
return Array.from(
new Set(components.map((component) => component as AnalysisKind)),
);
}
3 changes: 3 additions & 0 deletions src/config-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as yaml from "js-yaml";
import * as sinon from "sinon";

import * as actionsUtil from "./actions-util";
import { AnalysisKind } from "./analyses";
import * as api from "./api-client";
import { CachingKind } from "./caching-utils";
import { createStubCodeQL } from "./codeql";
Expand Down Expand Up @@ -47,6 +48,7 @@ function createTestInitConfigInputs(
return Object.assign(
{},
{
analysisKindsInput: "code-scanning",
languagesInput: undefined,
queriesInput: undefined,
qualityQueriesInput: undefined,
Expand Down Expand Up @@ -322,6 +324,7 @@ test("load non-empty input", async (t) => {

// And the config we expect it to parse to
const expectedConfig: configUtils.Config = {
analysisKinds: [AnalysisKind.CodeScanning],
languages: [KnownLanguage.javascript],
buildMode: BuildMode.None,
originalUserInput: {
Expand Down
22 changes: 21 additions & 1 deletion src/config-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as yaml from "js-yaml";
import * as semver from "semver";

import { isAnalyzingPullRequest } from "./actions-util";
import { AnalysisKind, parseAnalysisKinds } from "./analyses";
import * as api from "./api-client";
import { CachingKind, getCachingKind } from "./caching-utils";
import { type CodeQL } from "./codeql";
Expand Down Expand Up @@ -93,6 +94,10 @@ interface IncludeQueryFilter {
* Format of the parsed config file.
*/
export interface Config {
/**
* Set of analysis kinds that are enabled.
*/
analysisKinds: AnalysisKind[];
/**
* Set of languages to run analysis for.
*/
Expand Down Expand Up @@ -483,6 +488,7 @@ export async function getRawLanguages(

/** Inputs required to initialize a configuration. */
export interface InitConfigInputs {
analysisKindsInput: string;
languagesInput: string | undefined;
queriesInput: string | undefined;
qualityQueriesInput: string | undefined;
Expand Down Expand Up @@ -511,6 +517,7 @@ export interface InitConfigInputs {
* Get the default config, populated without user configuration file.
*/
export async function getDefaultConfig({
analysisKindsInput,
languagesInput,
queriesInput,
qualityQueriesInput,
Expand All @@ -530,6 +537,18 @@ export async function getDefaultConfig({
features,
logger,
}: InitConfigInputs): Promise<Config> {
const analysisKinds = await parseAnalysisKinds(analysisKindsInput);

// For backwards compatibility, add Code Quality to the enabled analysis kinds
// if an input to `quality-queries` was specified. We should remove this once
// `quality-queries` is no longer used.
if (
!analysisKinds.includes(AnalysisKind.CodeQuality) &&
qualityQueriesInput !== undefined
) {
analysisKinds.push(AnalysisKind.CodeQuality);
}

const languages = await getLanguages(
codeql,
languagesInput,
Expand Down Expand Up @@ -560,6 +579,7 @@ export async function getDefaultConfig({
);

return {
analysisKinds,
languages,
buildMode,
originalUserInput: {},
Expand Down Expand Up @@ -1475,5 +1495,5 @@ export function generateCodeScanningConfig(
export function isCodeQualityEnabled(config: Config): config is Config & {
augmentationProperties: { qualityQueriesInput: string };
} {
return config.augmentationProperties.qualityQueriesInput !== undefined;
return config.analysisKinds.includes(AnalysisKind.CodeQuality);
}
1 change: 1 addition & 0 deletions src/init-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ async function run() {
}

config = await initConfig({
analysisKindsInput: getRequiredInput("analysis-kinds"),
languagesInput: getOptionalInput("languages"),
queriesInput: getOptionalInput("queries"),
qualityQueriesInput: getOptionalInput("quality-queries"),
Expand Down
Loading