Skip to content

Commit

Permalink
Merge pull request #91 from Ic3m4n34/feature/color-config
Browse files Browse the repository at this point in the history
Badge Color Config
  • Loading branch information
olavoparno authored May 4, 2024
2 parents 31ca2f2 + 4174c43 commit 6fc646b
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 18 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@
npm run istanbul-badges-readme --logo="jest"
```

#### Configure Badge Color
- You can configure the color threshold of the badges by passing the `--colors` argument. If you want red badges for a code coverage below 50% and yellow badges for a coverage below 60%, you'd do this:
```bash
npm run istanbul-badges-readme --colors=red:50,yellow:60
```


#### Exit code

- To exit with **1** code on validation errors (eg.: _README doesn't exist_, or _coverage directory doesn't exist_) or on editing errors (eg.: cannot write to README due to lack of permissions). The default exit code is **0**. Set a different one by using **--exitCode** argument.
Expand Down
34 changes: 29 additions & 5 deletions src/editor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import { getArgumentValue } from './arguments';
import { readmePathConst, coveragePathConst, hashesConst, coverageUrlConst, badgeStyles } from './constants';
import { getCoveragePath, getReadmePath, readFileAsync } from './helpers';
import { getCoveragePath, getReadmePath, readFileAsync, parseColorConfig } from './helpers';
import { logger } from './logger';
import { Colors, Hashes, Report } from './types';

Expand All @@ -23,17 +23,40 @@ export const getReadmeHashes = (readmeFile: string): Hashes[] => {
return filteredHashes as unknown as Hashes[];
};

export const getCoverageColor = (coverage: number): Colors => {
if (coverage < 80) {


/**
* Determines the color representation of code coverage based on coverage percentage.
* Optionally uses a provided string to configure custom color thresholds.
*
* @param {number} coverage - The code coverage percentage to evaluate.
* @param {string | false} colorConfigString - A string to configure custom color thresholds, or false to use defaults.
* @returns {Colors} - The color associated with the given code coverage percentage, based on either default or custom thresholds.
*/
export const getCoverageColor = (coverage: number, colorConfigString?: string | false): Colors => {
const defaultThresholds = {
red: 80,
yellow: 90,
};

let colorThresholds = defaultThresholds;

if (colorConfigString) {
colorThresholds = parseColorConfig(colorConfigString);
}

// Adjusting to use dynamic color thresholds from colorConfigString if provided
if (coverage < colorThresholds.red) {
return 'red';
}
if (coverage < 90) {
if (coverage < colorThresholds.yellow) {
return 'yellow';
}

return 'brightgreen';
};


export const getCoverageBadge = (coverageFile: string, hashKey: string): string | boolean => {
logInfo(`- Getting coverage badge url for ${hashKey}...`);

Expand All @@ -45,7 +68,8 @@ export const getCoverageBadge = (coverageFile: string, hashKey: string): string
}

const coverage: number = parsedCoverage.total[hashKey].pct;
const color = getCoverageColor(coverage);
const customColors = getArgumentValue('colors');
const color = getCoverageColor(coverage, customColors);
const customLabel = getArgumentValue(`${hashKey}Label`);
const customBadgeStyle = getArgumentValue('style');
const customBadgeLogo = getArgumentValue('logo');
Expand Down
29 changes: 29 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,32 @@ export const getExitCodeOnError = (): number | undefined => {

return argExitCode && !isNaN(argExitCode) ? argExitCode : undefined;
};

/**
* Parses a string representing colors and their corresponding numeric values into an object.
* The input string should be formatted as "color:value", with multiple color-value pairs separated by commas.
* This function specifically expects "red", "yellow", and "brightgreen" as the only valid colors in the string.
*
* @param {string} colorsString - The string representation of colors and their values to parse.
* @returns {{ red: number; yellow: number; brightgreen: number }} An object with keys "red", "yellow", and "brightgreen",
* each mapped to their numeric value as specified in the input string.
*/
export const parseColorConfig = (colorsString: string): {
red: number;
yellow: number;
} => {
if (!colorsString) {
return { red: 80, yellow: 90 };
}

return colorsString.split(',').reduce((acc, colorPair) => {
const [color, value] = colorPair.split(':');
if (color === 'red' || color === 'yellow') {
acc[color] = parseInt(value, 10);
}
return acc;
}, {} as { red: number; yellow: number; });
};



56 changes: 43 additions & 13 deletions tests/editor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs';
import path from 'path';
import { getReadmeHashes, getCoverageColor, getCoverageBadge, getNewReadme, writeNewReadme } from '../src/editor';
import { getReadmeHashes, getCoverageBadge, getCoverageColor, getNewReadme, writeNewReadme } from '../src/editor';
import { parseColorConfig } from '../src/helpers';

describe('Tests editor', () => {
afterEach(() => {
Expand All @@ -14,20 +15,49 @@ describe('Tests editor', () => {
expect(readmeHashes.length).toEqual(0);
});

it('should getCoverageColor from both red, yellow and green', () => {
const colorsMap: Record<any, string> = {
90: 'brightgreen',
80: 'yellow',
default: 'red',
};
describe('parseColorConfig', () => {
it('correctly parses a valid color configuration string', () => {
const inputString = 'red:70,yellow:85';
const expectedResult = { red: 70, yellow: 85 };
expect(parseColorConfig(inputString)).toEqual(expectedResult);
});

it('ignores invalid color names', () => {
const inputString = 'red:70,yellow:85,blue:95';
const expectedResult = { red: 70, yellow: 85 };
expect(parseColorConfig(inputString)).toEqual(expectedResult);
});

it('returns default colors for an empty string', () => {
const inputString = '';
const expectedResult = { red: 80, yellow: 90 };
expect(parseColorConfig(inputString)).toEqual(expectedResult);
});
});

const checkColor = (threshold: number) =>
expect(getCoverageColor(threshold)).toEqual(colorsMap[threshold] ? colorsMap[threshold] : colorsMap.default);
describe('getCoverageColor', () => {
test.each`
coverage | expectedColor
${75} | ${'red'}
${85} | ${'yellow'}
${95} | ${'brightgreen'}
`(
'returns $expectedColor for a coverage of $coverage using default thresholds',
({ coverage, expectedColor }) => {
expect(getCoverageColor(coverage)).toBe(expectedColor);
}
);

checkColor(90);
checkColor(80);
checkColor(79);
checkColor(10);
test('uses custom thresholds if provided', () => {
const customConfig = 'red:70,yellow:85';
expect(getCoverageColor(65, customConfig)).toBe('red');
expect(getCoverageColor(75, customConfig)).toBe('yellow');
expect(getCoverageColor(90, customConfig)).toBe('brightgreen');
});

test('returns brightgreen for coverage above 100', () => {
expect(getCoverageColor(105)).toBe('brightgreen');
});
});

it('should getCoverageBadge from coverageFile', () => {
Expand Down

0 comments on commit 6fc646b

Please sign in to comment.