Skip to content

Commit

Permalink
more testing, cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
erikburt committed Nov 29, 2024
1 parent 6e75459 commit ee3fcff
Show file tree
Hide file tree
Showing 9 changed files with 728 additions and 66 deletions.
4 changes: 2 additions & 2 deletions apps/go-test-caching/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ sequenceDiagram
Pipeline->>Pipeline: Run Changed Tests
Pipeline-->>Action: Done Execution
Action-->>Github: Upload Build Logs
Action-->>Github: Upload Run Logs
Action-->>Github: Upload Coverage (if enabled)
Action->>Workflow: Done Execution
deactivate Action
Workflow->>Action: 'Update'
activate Action
Action-->>Pipeline: Start Update Process
Action-->>Pipeline: Start Update Processqm
Pipeline->>Pipeline: Check Update Criteria
opt Criteria Met
Expand Down
36 changes: 20 additions & 16 deletions apps/go-test-caching/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -106737,14 +106737,19 @@ function isCompilationSuccess(result) {
function isCompilationFailure(result) {
return "error" in result;
}
async function compileTestBinary(cwd, outputDir, { importPath, directory }, buildFlags) {
async function compileTestBinary(cwd, outputDir, { importPath, directory }, buildFlags, collectCoverage) {
const filename = importPath.replace(/\//g, "-") + "-test";
const binPath = path7.join(outputDir, filename);
const logPath = path7.join(outputDir, filename + ".compile.log");
const outputStream = (0, import_fs2.createWriteStream)(logPath);
const localFlags = [...buildFlags];
if (collectCoverage) {
core5.debug(`Building ${importPath} with coverage enabled.`);
localFlags.push("-cover", "-coverpkg=./...", "-covermode=atomic");
}
try {
const cmd = "go";
const flags = ["test", "-c", "-o", binPath, ...buildFlags, importPath];
const flags = ["test", "-c", "-o", binPath, ...localFlags, importPath];
core5.debug(`Exec: ${cmd} ${flags.join(" ")} (cwd: ${cwd})`);
const subprocess = execa(cmd, flags, {
...defaultExecaOptions,
Expand Down Expand Up @@ -106778,18 +106783,18 @@ async function compileTestBinary(cwd, outputDir, { importPath, directory }, buil
}
async function compileConcurrent(workingDir, outputDir, packages, buildFlags, collectCoverage, maxConcurrency) {
const limit = pLimit(maxConcurrency);
if (collectCoverage) {
core5.info("collect-coverage is true - adding coverage flags to builds.");
buildFlags.push("-cover", "-coverpkg=./...", "-covermode=atomic");
}
const values = Object.values(packages);
const building = /* @__PURE__ */ new Set();
const tasks = values.map(
(pkg) => limit(() => {
building.add(pkg.importPath);
return compileTestBinary(workingDir, outputDir, pkg, buildFlags).finally(
() => building.delete(pkg.importPath)
);
return compileTestBinary(
workingDir,
outputDir,
pkg,
buildFlags,
collectCoverage
).finally(() => building.delete(pkg.importPath));
})
);
const interval = setInterval(() => {
Expand Down Expand Up @@ -106911,7 +106916,7 @@ function isRunSuccess(result) {
function isRunFailure(result) {
return "error" in result;
}
async function runTestBinary(outputDir, pkg, binaryPath, runFlags, coverage, coverageDir) {
async function runTestBinary(outputDir, pkg, binaryPath, runFlags, coverageDir) {
const goCoverDir = path8.join(
pkg.directory,
`go-cover-${path8.basename(binaryPath)}`
Expand All @@ -106925,7 +106930,7 @@ async function runTestBinary(outputDir, pkg, binaryPath, runFlags, coverage, cov
const outputStream = (0, import_fs4.createWriteStream)(logPath);
try {
const localFlags = [...runFlags];
if (coverage) {
if (coverageDir) {
core6.debug(
`Collecting coverage for ${pkg.importPath} at ${coveragePath}`
);
Expand All @@ -106949,7 +106954,7 @@ async function runTestBinary(outputDir, pkg, binaryPath, runFlags, coverage, cov
execution,
output: {
log: logPath,
coverage: coverage ? coveragePath : void 0
coverage: coveragePath
}
};
} catch (error6) {
Expand Down Expand Up @@ -107004,7 +107009,7 @@ function filterOutputLogs(logs) {
}
return filteredLines.join("\n");
}
async function runConcurrent(buildDir, packages, flags, coverage, coverageDir, maxConcurrency) {
async function runConcurrent(buildDir, packages, flags, coverageDir, maxConcurrency) {
const limit = pLimit(maxConcurrency);
const allPackages = Object.values(packages);
const pkgsToRun = Object.values(allPackages).filter((pkg) => pkg.shouldRun);
Expand All @@ -107020,7 +107025,6 @@ async function runConcurrent(buildDir, packages, flags, coverage, coverageDir, m
pkg,
pkg.compile.binary,
flags,
coverage,
coverageDir
).finally(() => executing.delete(pkg.importPath));
})
Expand Down Expand Up @@ -107173,12 +107177,12 @@ async function processChangedPackages(inputs, packages) {
async function runTestBinaries(inputs, packages) {
logSection("Run Tests");
const maxRunConcurrency = parseInt(core7.getInput("run-concurrency")) || 4;
const coverageDirectory = inputs.collectCoverage ? inputs.coverageDirectory : "";
const runResults = await runConcurrent(
inputs.buildDirectory,
packages,
[],
inputs.collectCoverage,
inputs.coverageDirectory,
coverageDirectory,
maxRunConcurrency
);
return validateRunResultsOrThrow(packages, runResults);
Expand Down
34 changes: 20 additions & 14 deletions apps/go-test-caching/src/pipeline/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ const defaultExecaOptions = {
all: true,
stdout: "pipe",
stderr: "pipe",
} satisfies ExecaOptions;
export type ExecaOptions = {
} satisfies BuildExecaOptions;
export type BuildExecaOptions = {
cwd: string;
all: true;
stdout: "pipe";
stderr: "pipe";
};
export type ExecaReturn = Awaited<ReturnType<typeof execa<ExecaOptions>>>;
export type ExecaReturn = Awaited<ReturnType<typeof execa<BuildExecaOptions>>>;
type CompilationResult = CompilationSuccess | CompilationFailure;
export type CompilationSuccess = {
output: {
Expand Down Expand Up @@ -57,22 +57,29 @@ export async function compileTestBinary(
outputDir: string,
{ importPath, directory }: GoPackage,
buildFlags: string[],
collectCoverage: boolean,
): Promise<CompilationResult> {
const filename = importPath.replace(/\//g, "-") + "-test";
const binPath = path.join(outputDir, filename);

const logPath = path.join(outputDir, filename + ".compile.log");
const outputStream = createWriteStream(logPath);

const localFlags = [...buildFlags];
if (collectCoverage) {
core.debug(`Building ${importPath} with coverage enabled.`);
localFlags.push("-cover", "-coverpkg=./...", "-covermode=atomic");
}

try {
const cmd = "go";
const flags = ["test", "-c", "-o", binPath, ...buildFlags, importPath];
const flags = ["test", "-c", "-o", binPath, ...localFlags, importPath];
core.debug(`Exec: ${cmd} ${flags.join(" ")} (cwd: ${cwd})`);

const subprocess = execa(cmd, flags, {
...defaultExecaOptions,
cwd,
} satisfies ExecaOptions);
} satisfies BuildExecaOptions);

core.debug(`Logging output to ${logPath}`);
subprocess.all?.pipe(outputStream);
Expand Down Expand Up @@ -125,20 +132,19 @@ export async function compileConcurrent(
maxConcurrency: number,
) {
const limit = pLimit(maxConcurrency);

if (collectCoverage) {
core.info("collect-coverage is true - adding coverage flags to builds.");
buildFlags.push("-cover", "-coverpkg=./...", "-covermode=atomic");
}

const values = Object.values(packages);

const building = new Set<string>();
const tasks = values.map((pkg) =>
limit(() => {
building.add(pkg.importPath);
return compileTestBinary(workingDir, outputDir, pkg, buildFlags).finally(
() => building.delete(pkg.importPath),
);
return compileTestBinary(
workingDir,
outputDir,
pkg,
buildFlags,
collectCoverage,
).finally(() => building.delete(pkg.importPath));
}),
);

Expand Down
6 changes: 4 additions & 2 deletions apps/go-test-caching/src/pipeline/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,15 @@ export async function runTestBinaries(
): Promise<MaybeExecutedPackages> {
logSection("Run Tests");
const maxRunConcurrency = parseInt(core.getInput("run-concurrency")) || 4;
const coverageDirectory = inputs.collectCoverage
? inputs.coverageDirectory
: "";

const runResults = await runConcurrent(
inputs.buildDirectory,
packages,
[],
inputs.collectCoverage,
inputs.coverageDirectory,
coverageDirectory,
maxRunConcurrency,
);

Expand Down
34 changes: 20 additions & 14 deletions apps/go-test-caching/src/pipeline/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
MaybeExecutedPackages,
} from "./index.js";

type ExecaOptions = {
export type RunExecaOptions = {
cwd: string;
all: true;
stdout: "pipe";
Expand All @@ -29,11 +29,10 @@ const defaultExecaOptions = {
env: {
GOCOVERDIR: "",
},
} satisfies ExecaOptions;
} satisfies RunExecaOptions;

export type ExecaReturn = Awaited<ReturnType<typeof execa<ExecaOptions>>>;

type RunResult = RunSuccess | RunFailure;
type ExecaReturn = Awaited<ReturnType<typeof execa<RunExecaOptions>>>;
export type RunResult = RunSuccess | RunFailure;
type RunSuccess = {
output: {
log: string;
Expand All @@ -48,7 +47,7 @@ type RunFailure = {
log: string;
};
pkg: GoPackage;
error: ExecaError<ExecaOptions>;
error: ExecaError<RunExecaOptions>;
};

function isRunSuccess(result: RunResult): result is RunSuccess {
Expand All @@ -58,12 +57,21 @@ function isRunSuccess(result: RunResult): result is RunSuccess {
function isRunFailure(result: RunResult): result is RunFailure {
return "error" in result;
}
async function runTestBinary(

/**
* Runs the test binary for a given package.
* @param outputDir The directory to store the output logs
* @param pkg The package to run the test binary for
* @param binaryPath The path to the test binary
* @param runFlags The flags to pass to the test binary
* @param coverageDir The directory to store the coverage files. If an empty string, coverage is disabled.
* @returns The result of the test run
*/
export async function runTestBinary(
outputDir: string,
pkg: GoPackage,
binaryPath: string,
runFlags: string[],
coverage: boolean,
coverageDir: string,
): Promise<RunResult> {
// GOCOVERDIR is used to store intermediate coverage files. This needs to be unique for each test run.
Expand All @@ -82,7 +90,7 @@ async function runTestBinary(

try {
const localFlags = [...runFlags];
if (coverage) {
if (coverageDir) {
core.debug(
`Collecting coverage for ${pkg.importPath} at ${coveragePath}`,
);
Expand All @@ -98,7 +106,7 @@ async function runTestBinary(
env: {
GOCOVERDIR: goCoverDir,
},
} satisfies ExecaOptions);
} satisfies RunExecaOptions);

core.debug(`Logging output to ${logPath}`);
subprocess.all?.pipe(outputStream);
Expand All @@ -109,15 +117,15 @@ async function runTestBinary(
execution,
output: {
log: logPath,
coverage: coverage ? coveragePath : undefined,
coverage: coveragePath,
},
};
} catch (error) {
if (!(error instanceof ExecaError)) {
core.error(`Failed to run test for package ${pkg.importPath}`);
throw error;
}
const execaError = error as ExecaError<ExecaOptions>;
const execaError = error as ExecaError<RunExecaOptions>;
core.error(
`Failed to run test for package ${pkg.importPath}: ${execaError.message}`,
);
Expand Down Expand Up @@ -180,7 +188,6 @@ export async function runConcurrent(
buildDir: string,
packages: DiffedHashedCompiledPackages,
flags: string[],
coverage: boolean,
coverageDir: string,
maxConcurrency: number,
) {
Expand All @@ -200,7 +207,6 @@ export async function runConcurrent(
pkg,
pkg.compile.binary,
flags,
coverage,
coverageDir,
).finally(() => executing.delete(pkg.importPath));
}),
Expand Down
15 changes: 12 additions & 3 deletions apps/go-test-caching/test/helper/execa-error-mock.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { ExecaError } from "execa";

export class ExecaErrorMock extends ExecaError {
declare stdout: string;
declare stderr: string;
import { BuildExecaOptions } from "../../src/pipeline/build.js";
import { RunExecaOptions } from "../../src/pipeline/run.js";

export class ExecaErrorMockBuild extends ExecaError<BuildExecaOptions> {
constructor(stdout: string, stderr: string) {
super();
this.stdout = stdout;
this.stderr = stderr;
}
}

export class ExecaErrorMockRun extends ExecaError<RunExecaOptions> {
constructor(stdout: string, stderr: string) {
super();
this.stdout = stdout;
Expand Down
Loading

0 comments on commit ee3fcff

Please sign in to comment.