Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fail more clearly if the file program is not installed on the runner #2234

Merged
merged 10 commits into from
Apr 15, 2024
Prev Previous commit
Next Next commit
Store diagnostics in memory until the database is available
mbg committed Apr 11, 2024
commit 4b0172d9c2e8e400db6491a24b3d46cf0db3689d
54 changes: 41 additions & 13 deletions lib/diagnostics.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/diagnostics.js.map

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

3 changes: 3 additions & 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.

86 changes: 67 additions & 19 deletions src/diagnostics.ts
Original file line number Diff line number Diff line change
@@ -55,6 +55,17 @@ export interface DiagnosticMessage {
attributes?: { [key: string]: any };
}

/** Represents a diagnostic message that has not yet been written to the database. */
interface UnwrittenDiagnostic {
/** The diagnostic message that has not yet been written. */
diagnostic: DiagnosticMessage;
/** The language the diagnostic is for. */
language: Language;
}

/** A list of diagnostics which have not yet been written to disk. */
let unwrittenDiagnostics: UnwrittenDiagnostic[] = [];

/**
* Constructs a new diagnostic message with the specified id and name, as well as optional additional data.
*
@@ -76,9 +87,11 @@ export function makeDiagnostic(
}

/**
* Writes the given diagnostic to the database.
* Adds the given diagnostic to the database. If the database does not yet exist,
* the diagnostic will be written to it once it has been created.
*
* @param config The configuration that tells us where to store the diagnostic.
* @param language The language which the diagnostic is for.
* @param diagnostic The diagnostic message to add to the database.
*/
export function addDiagnostic(
@@ -88,30 +101,65 @@ export function addDiagnostic(
) {
const logger = getActionsLogger();
const databasePath = getCodeQLDatabasePath(config, language);

// Check that the database exists before writing to it. If the database does not yet exist,
// store the diagnostic in memory and write it later.
if (existsSync(databasePath)) {
writeDiagnostic(config, language, diagnostic);
} else {
logger.info(
`Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.`,
);

unwrittenDiagnostics.push({ diagnostic, language });
}
}

/**
* Writes the given diagnostic to the database.
*
* @param config The configuration that tells us where to store the diagnostic.
* @param language The language which the diagnostic is for.
* @param diagnostic The diagnostic message to add to the database.
*/
function writeDiagnostic(
config: Config,
language: Language,
diagnostic: DiagnosticMessage,
) {
const logger = getActionsLogger();
const diagnosticsPath = path.resolve(
databasePath,
getCodeQLDatabasePath(config, language),
"diagnostic",
"codeql-action",
);

// Check that the database exists before writing to it.
if (existsSync(databasePath)) {
try {
// Create the directory if it doesn't exist yet.
mkdirSync(diagnosticsPath, { recursive: true });

const jsonPath = path.resolve(
diagnosticsPath,
`codeql-action-${diagnostic.timestamp}.json`,
);
try {
// Create the directory if it doesn't exist yet.
mkdirSync(diagnosticsPath, { recursive: true });

writeFileSync(jsonPath, JSON.stringify(diagnostic));
} catch (err) {
logger.warning(`Unable to write diagnostic message to database: ${err}`);
}
} else {
logger.info(
`Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.`,
const jsonPath = path.resolve(
diagnosticsPath,
`codeql-action-${diagnostic.timestamp}.json`,
);

writeFileSync(jsonPath, JSON.stringify(diagnostic));
} catch (err) {
logger.warning(`Unable to write diagnostic message to database: ${err}`);
}
}

/** Writes all unwritten diagnostics to disk. */
export function flushDiagnostics(config: Config) {
const logger = getActionsLogger();
logger.info(
`Writing ${unwrittenDiagnostics.length} diagnostic(s) to database.`,
);

for (const unwritten of unwrittenDiagnostics) {
writeDiagnostic(config, unwritten.language, unwritten.diagnostic);
}

// Reset the unwritten diagnostics array.
unwrittenDiagnostics = [];
}
6 changes: 5 additions & 1 deletion src/init-action.ts
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ import {
import { getGitHubVersion } from "./api-client";
import { CodeQL } from "./codeql";
import * as configUtils from "./config-utils";
import { addDiagnostic, makeDiagnostic } from "./diagnostics";
import { addDiagnostic, flushDiagnostics, makeDiagnostic } from "./diagnostics";
import { EnvVar } from "./environment";
import { Feature, Features } from "./feature-flags";
import { checkInstallPython311, initCodeQL, initConfig, runInit } from "./init";
@@ -522,6 +522,10 @@ async function run() {
}
}

// Write diagnostics to the database that we previously stored in memory because the database
// did not exist until now.
flushDiagnostics(config);

core.setOutput("codeql-path", config.codeQLCmd);
} catch (unwrappedError) {
const error = wrapError(unwrappedError);