Skip to content

Commit

Permalink
fix: Git push fails when cacluating previous coverage (#30)
Browse files Browse the repository at this point in the history
docs: Add brief documentation comments to each function
test: Added --local input arg to test functionality locally
  • Loading branch information
thelukewalton authored Aug 19, 2024
1 parent 3f1fdc3 commit 2eef29f
Show file tree
Hide file tree
Showing 13 changed files with 505 additions and 53 deletions.
409 changes: 383 additions & 26 deletions dist/index.js

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion package-lock.json

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

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
"@actions/exec": "^1.1.1",
"@actions/github": "^6.0.0",
"@types/adm-zip": "^0.5.5",
"@types/minimist": "^1.2.5",
"adm-zip": "^0.5.14",
"lcov-utils": "^0.5.4"
"lcov-utils": "^0.5.4",
"minimist": "^1.2.8"
},
"devDependencies": {
"@types/jest": "^29.5.12",
Expand All @@ -23,7 +25,8 @@
"scripts": {
"test": "npx jest",
"test:coverage": "npx jest --coverage",
"build": "npx @vercel/ncc build src/main.ts -o dist"
"build": "npx @vercel/ncc build src/main.ts -o dist",
"start": "npx tsx src/main.ts --local"
},
"overrides": {
"graceful-fs": "^4.2.11"
Expand Down
20 changes: 12 additions & 8 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import { checkBranchStatus } from "./scripts/behind";
import { push } from "./scripts/push";
import { retrievePreviousCoverage } from "./scripts/prevCoverage";
import { Lcov } from "lcov-utils";
import minimist from "minimist";

export type stepResponse = { output: string; error: boolean };
export const COVERAGE_DIR = ".coverage";

const run = async () => {
const run = async (isLocal: boolean) => {
try {
const workingDirectory = getInput("working-directory");
// Check if the working directory is different from the current directory
Expand All @@ -23,12 +24,12 @@ const run = async () => {

const token = process.env.GITHUB_TOKEN || getInput("token");

const runTests = getBooleanInput("run-tests");
const runAnalyze = getBooleanInput("run-analyze");
const runCoverage = getBooleanInput("run-coverage");
const runPrevCoverage = getBooleanInput("run-prev-coverage");
const runBehindBy = getBooleanInput("run-behind-by");
const createComment = getBooleanInput("create-comment");
const runTests = isLocal ? true : getBooleanInput("run-tests");
const runAnalyze = isLocal ? true : getBooleanInput("run-analyze");
const runCoverage = isLocal ? true : getBooleanInput("run-coverage");
const runPrevCoverage = isLocal ? true : getBooleanInput("run-prev-coverage");
const runBehindBy = isLocal ? true : getBooleanInput("run-behind-by");
const createComment = isLocal ? true : getBooleanInput("create-comment");

const octokit = getOctokit(token);
let prevCoverage: Lcov | undefined;
Expand All @@ -39,6 +40,7 @@ const run = async () => {
console.error(e);
}
}

const behindByStr: stepResponse | undefined = runBehindBy ? await checkBranchStatus(octokit, context) : undefined;
await setup();

Expand All @@ -62,6 +64,8 @@ const run = async () => {
}
};

run();
const argv = minimist(process.argv.slice(2));

run(argv.local ?? false);

//TODO: Show coverage diff in comment - which files coverage have changed.
15 changes: 15 additions & 0 deletions src/scripts/analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export type analyzeDetails = { file: string; details: string };

export type analyzeErrTypes = "error" | "warning" | "info";

/**
* Run static analysis on the codebase
* @returns Analysis result as a stepResponse object
*/
export const getAnalyze = async (): Promise<stepResponse> => {
startGroup("Analyzing code");
let response: stepResponse | undefined;
Expand Down Expand Up @@ -78,6 +82,11 @@ export const getAnalyze = async (): Promise<stepResponse> => {
return response;
};

/**
* Get the emoji corresponding to the error type
* @param errType - Type of error
* @returns Emoji corresponding to the error type
*/
export const getErrEmoji = (errType: analyzeErrTypes) => {
switch (errType) {
case "error":
Expand All @@ -89,5 +98,11 @@ export const getErrEmoji = (errType: analyzeErrTypes) => {
}
};

/**
* Generate a table row for the error
* @param err - Error details
* @param type - Type of error
* @returns Formatted table row for the error
*/
export const generateTableRow = (err: analyzeDetails, type: analyzeErrTypes) =>
`<tr><td>${getErrEmoji(type)}</td><td>Error</td><td>${err.file}</td><td>${err.details}</td></tr>`;
6 changes: 6 additions & 0 deletions src/scripts/behind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { GitHub } from "@actions/github/lib/utils";
import { stepResponse } from "../main";
import { debug } from "@actions/core";

/**
* Check if the branch is behind the base branch
* @param octokit - Instance of GitHub client
* @param context - GitHub context
* @returns stepResponse object
*/
export const checkBranchStatus = async (
octokit: InstanceType<typeof GitHub>,
context: Context
Expand Down
14 changes: 14 additions & 0 deletions src/scripts/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import { debug } from "@actions/core";

const SIGNATURE = `<sub>Created with <a href='https://github.com/ZebraDevs/flutter-code-quality'>Flutter code quality action</a></sub>`;

/**
* Create a comment for the PR
* @param analyze - Static analysis result
* @param test - Test result
* @param coverage - Coverage result
* @param behindBy - Branch status
* @returns Comment message
*/
export const createComment = (
analyze: stepResponse | undefined,
test: stepResponse | undefined,
Expand All @@ -31,6 +39,12 @@ ${SIGNATURE}
return output;
};

/**
* Post a comment on the PR
* @param octokit - Instance of GitHub client
* @param commentMessage - Comment message
* @param context - GitHub context
*/
export async function postComment(octokit: InstanceType<typeof GitHub>, commentMessage: string, context: Context) {
startGroup(`Commenting on PR`);

Expand Down
6 changes: 6 additions & 0 deletions src/scripts/coverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import { getLcovLines } from "./utils";

export const COV_FAILURE = "⚠️ - Coverage check failed";

/**
* Get the coverage report and compare with the previous coverage
* @param prevCoverage - Previous coverage report
* @param coverageDirectory - Directory to store coverage report
* @returns Coverage report as a stepResponse object
*/
export const getCoverage = (prevCoverage: Lcov | undefined, coverageDirectory: string): stepResponse => {
startGroup("Checking test coverage");
let response: stepResponse | undefined;
Expand Down
37 changes: 21 additions & 16 deletions src/scripts/prevCoverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,36 @@ import { Context } from "@actions/github/lib/context";
import { GitHub } from "@actions/github/lib/utils";
import { exec } from "@actions/exec";
import { Lcov, parse } from "lcov-utils";
import { COV_FILE, importLcov } from "./utils";
import { COV_FILE, importLcov, toBuffer } from "./utils";
import { DefaultArtifactClient } from "@actions/artifact";
import { endGroup, startGroup } from "@actions/core";
import { debug } from "@actions/core";
import AdmZip from "adm-zip";

const ARTIFACT_NAME = "coverage";

/**
* Retrieve previous coverage report from the base branch
* @param octokit - Instance of GitHub client
* @param context - GitHub context
* @param coverageDirectory - Directory to store coverage report
* @returns Lcov object
*/
export const retrievePreviousCoverage = async (
octokit: InstanceType<typeof GitHub>,
context: Context,
coverageDirectory: string
): Promise<Lcov> => {
startGroup("Retrieving previous coverage");
let report: Lcov | undefined;
let baseSHA: string, headSHA: string;
let baseSHA: string, headBranch: string;
try {
const pullDetails = await octokit.request(
`GET /repos/${context.issue.owner}/${context.issue.repo}/pulls/${context.issue.number}`
);

baseSHA = pullDetails.data.base.sha;
headSHA = pullDetails.data.head.sha;
headBranch = pullDetails.data.head.ref;
} catch (err) {
console.error("Failed to get pull details", err);
throw err;
Expand Down Expand Up @@ -72,7 +79,7 @@ export const retrievePreviousCoverage = async (
}
if (!report) {
debug("Artifact not found, will pull coverage from BASE");
report = await generateOldCoverage(baseSHA, headSHA, coverageDirectory);
report = await generatePreviousCoverage(baseSHA, headBranch, coverageDirectory);
} else {
try {
await exec(`rm ${coverageDirectory}/${COV_FILE}`);
Expand All @@ -86,9 +93,16 @@ export const retrievePreviousCoverage = async (
throw new Error("Failed to generate coverage report");
};

const generateOldCoverage = async (
/**
* Generate coverage report from the base branch
* @param prev_sha - Base branch SHA
* @param current_branch - Current branch name
* @param coverage_directory - Directory to store coverage report
* @returns Previous coverage report as Lcov object
*/
const generatePreviousCoverage = async (
prev_sha: string,
current_sha: string,
current_branch: string,
coverage_directory: string
): Promise<Lcov> => {
const artifact = new DefaultArtifactClient();
Expand All @@ -104,15 +118,6 @@ const generateOldCoverage = async (

debug(`Artifact uploaded with id: ${id} and size: ${size}`);
await exec(`git reset --hard`);
await exec(`git checkout ${current_sha}`);
await exec(`git checkout ${current_branch}`);
return report;
};

export const toBuffer = (arrayBuffer: ArrayBuffer) => {
const buffer = Buffer.alloc(arrayBuffer.byteLength);
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < buffer.length; ++i) {
buffer[i] = view[i];
}
return buffer;
};
3 changes: 3 additions & 0 deletions src/scripts/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { exec } from "@actions/exec";
import { execSync } from "child_process";
import { debug } from "@actions/core";

/**
* Push changes to the branch
*/
export const push = async () => {
startGroup("Check for changes");
let stdout: string = "";
Expand Down
5 changes: 5 additions & 0 deletions src/scripts/runTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { stepResponse } from "../main";
export const TEST_SUCCESS = "✅ - All tests passed";
export const TEST_ERROR = "⚠️ - Error running tests";

/**
* Run tests and return the result
* @param coverageDir - Directory to store coverage report
* @returns Test result as a stepResponse object
*/
export const getTest = async (coverageDir: string): Promise<stepResponse> => {
startGroup("Running tests");
let response: stepResponse | undefined;
Expand Down
3 changes: 3 additions & 0 deletions src/scripts/setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { endGroup, startGroup } from "@actions/core";
import { exec } from "@actions/exec";

/**
* Set up Flutter
*/
export const setup = async () => {
startGroup("Set up Flutter");
try {
Expand Down
24 changes: 24 additions & 0 deletions src/scripts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { readFileSync } from "fs";
import { Lcov, parse, sum } from "lcov-utils";
export const COV_FILE = "lcov.info";

/**
* Import the Lcov report
* @param file_directory - Directory containing the Lcov report
* @returns Lcov report
*/
export const importLcov = (file_directory: string): Lcov => {
startGroup("Retrieving coverage report");
try {
Expand All @@ -16,4 +21,23 @@ export const importLcov = (file_directory: string): Lcov => {
}
};

/**
* Get the total lines covered in the Lcov report
* @param report - Lcov report
* @returns Total lines covered
*/
export const getLcovLines = (report: Lcov): number => sum(report).lines;

/**
* Convert ArrayBuffer to Buffer
* @param arrayBuffer - ArrayBuffer to convert
* @returns Data in Buffer format
*/
export const toBuffer = (arrayBuffer: ArrayBuffer) => {
const buffer = Buffer.alloc(arrayBuffer.byteLength);
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < buffer.length; ++i) {
buffer[i] = view[i];
}
return buffer;
};

0 comments on commit 2eef29f

Please sign in to comment.