Skip to content

Commit

Permalink
feat: ✨ Improved markdown report
Browse files Browse the repository at this point in the history
  • Loading branch information
robvanderleek committed Dec 3, 2024
1 parent 5a51caf commit 4377889
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 139 deletions.
161 changes: 22 additions & 139 deletions src/action.ts
Original file line number Diff line number Diff line change
@@ -1,154 +1,37 @@
import nodeFetch from "node-fetch";
import path from "path";
import fs from "fs";
import {getInput} from "@actions/core";
import {promisify} from "util";
import {context} from "@actions/github";
import {Octokit} from "@octokit/action";
import {
branchExists,
createBranch,
createInitialCommit,
createBranchIfNotExists,
createOrUpdateFile,
createPRComment,
getRepoName,
getRepoOwner
getRepoOwner,
getSourceBranch,
isPullRequest
} from "./github";
import {exec, getExecOutput} from "@actions/exec";
import {makeBadge} from "badge-maker";
import {downloadCodeLimitBinary, getBadgeContent, getReportContent} from "./codelimit";
import {getChangedFiles} from "./utils";

const streamPipeline = promisify(require('stream').pipeline);


function getBinaryName() {
const binaries: { [platform: string]: string } = {
'darwin': 'codelimit-macos',
'win32': 'codelimit.exe',
'linux': 'codelimit-linux'
};
if (process.env.RUNNER_OS) {
const platform = process.env.RUNNER_OS.toLowerCase();
if (platform in binaries) {
return binaries[platform];
}
}
if (process.platform in binaries) {
return binaries[process.platform];
}
return binaries['linux'];
}

async function getLatestBinaryUrl() {
const latestUrl = 'https://github.com/getcodelimit/codelimit/releases/latest';
const res = await nodeFetch(latestUrl);
const downloadUrl = res.url.replace('/tag/', '/download/');
return `${downloadUrl}/${getBinaryName()}`;
}

async function downloadBinary() {
const binaryUrl = await getLatestBinaryUrl();
console.log(`Downloading Code Limit binary from URL: ${binaryUrl}`);
const response = await nodeFetch(binaryUrl);
const filename = path.join(__dirname, getBinaryName());
await streamPipeline(response.body, fs.createWriteStream(filename));
fs.chmodSync(filename, '777');
console.log(`Code Limit binary downloaded: ${filename}`);
return filename;
}

async function getChangedFiles(token: string) {
const eventName = context.eventName
if (eventName === undefined) {
return ['.'];
}
let base;
let head;
if (eventName === 'pull_request') {
base = context.payload.pull_request?.base?.sha
head = context.payload.pull_request?.head?.sha
} else {
base = context.payload.before
head = context.payload.after
}
console.log(`Base commit: ${base}`);
console.log(`Head commit: ${head}`);
const octokit = new Octokit({auth: token});
const response = await octokit.repos.compareCommits({
base, head, owner: context.repo.owner, repo: context.repo.repo
});
if (response.status !== 200) {
return ['.'];
}
const files = response.data.files
const result = [];
if (files) {
for (const file of files) {
const filename = file.filename
if (file.status === 'modified' || file.status === 'added') {
result.push(filename);
}
}
}
async function generateMarkdownReport(clBinary: string) {
const totalsMarkdown = await getExecOutput(clBinary, ['report', '--totals', '--format', 'markdown']);
const unitsMarkdown = await getExecOutput(clBinary, ['report', '--full', '--format', 'markdown']);
let result = '';
result += '## Codebase totals\n';
result += totalsMarkdown.stdout;
result += '\n';
result += '## Refactoring report\n';
result += unitsMarkdown.stdout;
return result;
}

function isPullRequest() {
return context.eventName === 'pull_request';
}

function getSourceBranch() {
if (isPullRequest()) {
return process.env.GITHUB_HEAD_REF;
} else {
return process.env.GITHUB_REF_NAME;
}
}

async function createReportsBranchIfNotExists(octokit: Octokit, owner: string, repo: string) {
if (!await branchExists(octokit, owner, repo, '_codelimit_reports')) {
const initialCommitSha = await createInitialCommit(octokit, owner, repo);
await createBranch(octokit, owner, repo, '_codelimit_reports', initialCommitSha);
} else {
console.log('Branch _codelimit_reports already exists');
}
}

function makeBadgeSvg(message: string, color: 'red' | 'orange' | 'green' | 'grey'): string {
const badge = {
label: 'Code Limit',
message: message,
color: color
};
return makeBadge(badge);
}

function getReportContent(): string | undefined {
return fs.readFileSync('.codelimit_cache/codelimit.json', 'utf8');
}

function getBadgeContent(reportContent: string | undefined): string {
if (!reportContent) {
return makeBadgeSvg('Not found', 'grey');
} else {
const reportJson = JSON.parse(reportContent);
const profile = reportJson.codebase.tree['./'].profile
if (profile[3] > 0) {
return makeBadgeSvg('Needs refactoring', 'red');
} else if (profile[2] > 0) {
return makeBadgeSvg('Needs refactoring', 'orange');
} else {
return makeBadgeSvg('Passed', 'green');
}
}
}

async function main() {
const filename = await downloadBinary();
const clBinary = await downloadCodeLimitBinary();
console.log('Scanning codebase...');
await exec(filename, ['scan', '.']);
const totalsMarkdown = await getExecOutput(filename, ['report', '--totals', '--format', 'markdown']);
const unitsMarkdown = await getExecOutput(filename, ['report', '--full', '--format', 'markdown']);
const markdownReport = `${totalsMarkdown.stdout}\n${unitsMarkdown.stdout}`;
await exec(clBinary, ['scan', '.']);
const markdownReport = await generateMarkdownReport(clBinary);
const doUpload = getInput('upload') || false;
const token = getInput('token');
const octokit = new Octokit({auth: token});
Expand All @@ -159,7 +42,7 @@ async function main() {
process.exit(1);
}
const branch = getSourceBranch();
await createReportsBranchIfNotExists(octokit, owner, repo);
await createBranchIfNotExists(octokit, owner, repo, '_codelimit_reports');
const reportContent = getReportContent();
await createOrUpdateFile(octokit, owner, repo, '_codelimit_reports', `${branch}/badge.svg`, getBadgeContent(reportContent));
if (reportContent) {
Expand All @@ -181,7 +64,7 @@ async function main() {
}
const slug = context.payload.repository?.full_name;
if (slug && branch) {
exitCode = await exec(filename, ['app', 'upload', '--token', token, slug, branch]);
exitCode = await exec(clBinary, ['app', 'upload', '--token', token, slug, branch]);
}
}
const doCheck = getInput('check') || true;
Expand All @@ -192,10 +75,10 @@ async function main() {
console.log('No files changed, skipping Code Limit');
} else {
console.log('Running Code Limit...');
exitCode = await exec(filename, ['check'].concat(changedFiles), {ignoreReturnCode: true});
exitCode = await exec(clBinary, ['check'].concat(changedFiles), {ignoreReturnCode: true});
}
}
fs.unlinkSync(filename);
fs.unlinkSync(clBinary);
console.log('Done!');
process.exit(exitCode);
}
Expand Down
72 changes: 72 additions & 0 deletions src/codelimit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import nodeFetch from "node-fetch";
import path from "path";
import fs from "fs";
import {promisify} from "util";
import {makeBadge} from "badge-maker";

const streamPipeline = promisify(require('stream').pipeline);

function getBinaryName() {
const binaries: { [platform: string]: string } = {
'darwin': 'codelimit-macos',
'win32': 'codelimit.exe',
'linux': 'codelimit-linux'
};
if (process.env.RUNNER_OS) {
const platform = process.env.RUNNER_OS.toLowerCase();
if (platform in binaries) {
return binaries[platform];
}
}
if (process.platform in binaries) {
return binaries[process.platform];
}
return binaries['linux'];
}

async function getLatestBinaryUrl() {
const latestUrl = 'https://github.com/getcodelimit/codelimit/releases/latest';
const res = await nodeFetch(latestUrl);
const downloadUrl = res.url.replace('/tag/', '/download/');
return `${downloadUrl}/${getBinaryName()}`;
}

export async function downloadCodeLimitBinary() {
const binaryUrl = await getLatestBinaryUrl();
console.log(`Downloading Code Limit binary from URL: ${binaryUrl}`);
const response = await nodeFetch(binaryUrl);
const filename = path.join(__dirname, getBinaryName());
await streamPipeline(response.body, fs.createWriteStream(filename));
fs.chmodSync(filename, '777');
console.log(`Code Limit binary downloaded: ${filename}`);
return filename;
}

export function getReportContent(): string | undefined {
return fs.readFileSync('.codelimit_cache/codelimit.json', 'utf8');
}

function makeBadgeSvg(message: string, color: 'red' | 'orange' | 'green' | 'grey'): string {
const badge = {
label: 'Code Limit',
message: message,
color: color
};
return makeBadge(badge);
}

export function getBadgeContent(reportContent: string | undefined): string {
if (!reportContent) {
return makeBadgeSvg('Not found', 'grey');
} else {
const reportJson = JSON.parse(reportContent);
const profile = reportJson.codebase.tree['./'].profile
if (profile[3] > 0) {
return makeBadgeSvg('Needs refactoring', 'red');
} else if (profile[2] > 0) {
return makeBadgeSvg('Needs refactoring', 'orange');
} else {
return makeBadgeSvg('Passed', 'green');
}
}
}
22 changes: 22 additions & 0 deletions src/github.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Octokit} from "@octokit/action";
import {Context} from "@actions/github/lib/context";
import {context} from "@actions/github";

export async function branchExists(octokit: Octokit, owner: string, repo: string, branchName: string) {
try {
Expand Down Expand Up @@ -98,4 +99,25 @@ export async function createPRComment(octokit: Octokit, owner: string, repo: str
issue_number: prNumber,
body: comment
});
}

export function isPullRequest() {
return context.eventName === 'pull_request';
}

export function getSourceBranch() {
if (isPullRequest()) {
return process.env.GITHUB_HEAD_REF;
} else {
return process.env.GITHUB_REF_NAME;
}
}

export async function createBranchIfNotExists(octokit: Octokit, owner: string, repo: string, branchName: string) {
if (!await branchExists(octokit, owner, repo, branchName)) {
const initialCommitSha = await createInitialCommit(octokit, owner, repo);
await createBranch(octokit, owner, repo, branchName, initialCommitSha);
} else {
console.log(`Branch ${branchName} already exists`);
}
}
36 changes: 36 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {context} from "@actions/github";
import {Octokit} from "@octokit/action";

export async function getChangedFiles(token: string) {
const eventName = context.eventName
if (eventName === undefined) {
return ['.'];
}
let base;
let head;
if (eventName === 'pull_request') {
base = context.payload.pull_request?.base?.sha
head = context.payload.pull_request?.head?.sha
} else {
base = context.payload.before
head = context.payload.after
}
const octokit = new Octokit({auth: token});
const response = await octokit.repos.compareCommits({
base, head, owner: context.repo.owner, repo: context.repo.repo
});
if (response.status !== 200) {
return ['.'];
}
const files = response.data.files
const result = [];
if (files) {
for (const file of files) {
const filename = file.filename
if (file.status === 'modified' || file.status === 'added') {
result.push(filename);
}
}
}
return result;
}

0 comments on commit 4377889

Please sign in to comment.