Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
all-files-minimum-coverage: 0
changed-files-minimum-coverage: 0
update-comment: true
test-changed-files: 'php-files/src/index.php,php-files/src/services/service2.php'

- name: Verify action outputs
run: |
Expand All @@ -53,8 +54,7 @@ jobs:

# Expected values based on test data
# All files: index.php (6/12) + service1.php (5/15) + service2.php (12/48) = 23/75 = 30.67%
# Changed files detected by GitHub: index.php (6/12) + service2.php (12/48) = 18/60 = 30.00%
# Note: service1.php appears in coverage but not detected as changed by GitHub in PR context
# Changed files (mocked in test mode): index.php (6/12) + service2.php (12/48) = 18/60 = 30.00%
EXPECTED_ALL_FILES_COVERAGE="30.67"
EXPECTED_ALL_FILES_LINES_HIT="23"
EXPECTED_ALL_FILES_LINES_TOTAL="75"
Expand Down
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ jobs:

# Optional: Update existing comment vs create new (default: true)
update-comment: true

# Optional: Show all files coverage in PR comment (default: false)
all-files-coverage-visible: false
```

## Inputs
Expand All @@ -86,6 +89,7 @@ jobs:
| `changed-files-minimum-coverage` | Minimum coverage percentage for changed files (0-100) | ❌ | `0` |
| `artifact-name` | Name for coverage artifact upload (empty to skip) | ❌ | `''` |
| `update-comment` | Whether to update existing comment or create new one | ❌ | `true` |
| `all-files-coverage-visible` | Whether to show all files coverage in PR comment | ❌ | `false` |

## Outputs

Expand Down Expand Up @@ -130,22 +134,24 @@ permissions:

## Example Output

The action will post a comment on your pull request that looks like this:
The action will post a comment on your pull request. By default, only the "Changed Files" section is shown. To also display the "All Files" section, set `all-files-coverage-visible: true`.

**Example with `all-files-coverage-visible: true`:**

> ## Coverage Report ⚠️
>
>
> ### All Files
> - Lines: 847/1205 (70.3%) ⚠️
> - Functions: 156/198 (78.8%)
> - Branches: 234/298 (78.5%)
>
>
> ### Changed Files
> - Lines: 142/165 (86.1%) ✅
> - Functions: 28/32 (87.5%)
> - Branches: 45/52 (86.5%)
>
>
> Files changed:
>
>
> | **File** | **Lines** | **Line %** | **Functions** | **Function %** | **Branches** | **Branch %** |
> |------|-------|--------|-----------|------------|----------|----------|
> | **📁 src** | **142/165** | **86.1%** | **28/32** | **87.5%** | **45/52** | **86.5%** |
Expand Down
8 changes: 8 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ inputs:
description: 'Whether to update existing comment or create new one'
required: false
default: 'true'
all-files-coverage-visible:
description: 'Whether to show all files coverage in PR comment (true/false)'
required: false
default: 'false'
test-changed-files:
description: 'Comma-separated list of file paths to mock as changed files (for testing only)'
required: false
default: ''

outputs:
all-files-coverage:
Expand Down
3 changes: 2 additions & 1 deletion dist/CoverageReporter.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { CoverageData, CoverageReport, ChangedFile } from './types';
export declare class CoverageReporter {
private readonly allFilesMinimumCoverage;
private readonly changedFilesMinimumCoverage;
constructor(allFilesMinimumCoverage?: number, changedFilesMinimumCoverage?: number);
private readonly allFilesCoverageVisible;
constructor(allFilesMinimumCoverage?: number, changedFilesMinimumCoverage?: number, allFilesCoverageVisible?: boolean);
generateReport(coverageData: CoverageData, changedFiles: ChangedFile[]): CoverageReport;
generateMarkdownReport(report: CoverageReport): string;
private calculateSummary;
Expand Down
2 changes: 1 addition & 1 deletion dist/CoverageReporter.d.ts.map

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

3 changes: 2 additions & 1 deletion dist/GitHubService.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export declare class GitHubService {
private readonly octokit;
private readonly context;
private readonly commentIdentifier;
constructor(githubToken: string, context: Context);
private readonly testChangedFiles;
constructor(githubToken: string, context: Context, testChangedFiles?: string);
getChangedFiles(): Promise<ChangedFile[]>;
postOrUpdateComment(commentBody: string, shouldUpdate: boolean): Promise<void>;
private findExistingComment;
Expand Down
2 changes: 1 addition & 1 deletion dist/GitHubService.d.ts.map

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

35 changes: 25 additions & 10 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -88977,9 +88977,10 @@ const DirectoryStructure_1 = __nccwpck_require__(49627);
const MarkdownTableGenerator_1 = __nccwpck_require__(50935);
const path = __importStar(__nccwpck_require__(16928));
class CoverageReporter {
constructor(allFilesMinimumCoverage = 0, changedFilesMinimumCoverage = 0) {
constructor(allFilesMinimumCoverage = 0, changedFilesMinimumCoverage = 0, allFilesCoverageVisible = false) {
this.allFilesMinimumCoverage = allFilesMinimumCoverage;
this.changedFilesMinimumCoverage = changedFilesMinimumCoverage;
this.allFilesCoverageVisible = allFilesCoverageVisible;
}
generateReport(coverageData, changedFiles) {
const allFiles = this.calculateSummary(Object.values(coverageData));
Expand Down Expand Up @@ -89068,11 +89069,13 @@ class CoverageReporter {
const allFilesStatus = this.getCoverageStatus(report.allFiles.linesCoverage, true);
const changedFilesStatus = this.getCoverageStatus(report.changedFiles.linesCoverage, false);
let markdown = `## Coverage Report ${allFilesStatus}\n\n`;
// All Files Summary
markdown += `### All Files\n`;
markdown += `- Lines: ${report.allFiles.linesHit}/${report.allFiles.linesTotal} (${report.allFiles.linesCoverage.toFixed(1)}%) ${allFilesStatus}\n`;
markdown += `- Functions: ${report.allFiles.functionsHit}/${report.allFiles.functionsTotal} (${report.allFiles.functionsCoverage.toFixed(1)}%)\n`;
markdown += `- Branches: ${report.allFiles.branchesHit}/${report.allFiles.branchesTotal} (${report.allFiles.branchesCoverage.toFixed(1)}%)\n\n`;
// All Files Summary (conditionally hidden)
if (this.allFilesCoverageVisible) {
markdown += `### All Files\n`;
markdown += `- Lines: ${report.allFiles.linesHit}/${report.allFiles.linesTotal} (${report.allFiles.linesCoverage.toFixed(1)}%) ${allFilesStatus}\n`;
markdown += `- Functions: ${report.allFiles.functionsHit}/${report.allFiles.functionsTotal} (${report.allFiles.functionsCoverage.toFixed(1)}%)\n`;
markdown += `- Branches: ${report.allFiles.branchesHit}/${report.allFiles.branchesTotal} (${report.allFiles.branchesCoverage.toFixed(1)}%)\n\n`;
}
// Changed Files Summary
markdown += `### Changed Files\n`;
markdown += `- Lines: ${report.changedFiles.linesHit}/${report.changedFiles.linesTotal} (${report.changedFiles.linesCoverage.toFixed(1)}%) ${changedFilesStatus}\n`;
Expand Down Expand Up @@ -89390,12 +89393,22 @@ exports.GitHubService = void 0;
const core = __importStar(__nccwpck_require__(37484));
const github = __importStar(__nccwpck_require__(93228));
class GitHubService {
constructor(githubToken, context) {
constructor(githubToken, context, testChangedFiles = '') {
this.commentIdentifier = '<!-- PR Test Coverage Report -->';
this.octokit = github.getOctokit(githubToken);
this.context = context;
this.testChangedFiles = testChangedFiles;
}
async getChangedFiles() {
// If test mode is enabled, return mock changed files
if (this.testChangedFiles) {
const files = this.testChangedFiles.split(',').map(filename => filename.trim()).filter(f => f);
core.info(`TEST MODE: Using mocked changed files: ${files.join(', ')}`);
return files.map(filename => ({
filename,
status: 'modified'
}));
}
const pullRequest = this.context.payload.pull_request;
if (!pullRequest) {
throw new Error('No pull request found in context');
Expand Down Expand Up @@ -89842,9 +89855,9 @@ class PrTestCoverageAction {
constructor(inputs, context) {
this.inputs = inputs;
this.context = context;
this.githubService = new GitHubService_1.GitHubService(inputs.githubToken, context);
this.githubService = new GitHubService_1.GitHubService(inputs.githubToken, context, inputs.testChangedFiles);
this.phpunitXmlParser = new PhpUnitXmlParser_1.PhpUnitXmlParser();
this.coverageReporter = new CoverageReporter_1.CoverageReporter(inputs.allFilesMinimumCoverage, inputs.changedFilesMinimumCoverage);
this.coverageReporter = new CoverageReporter_1.CoverageReporter(inputs.allFilesMinimumCoverage, inputs.changedFilesMinimumCoverage, inputs.allFilesCoverageVisible);
}
async execute() {
core.info('Starting PR Test Coverage Action...');
Expand Down Expand Up @@ -90023,7 +90036,9 @@ async function run() {
allFilesMinimumCoverage: parseInt(core.getInput('all-files-minimum-coverage') || '0', 10),
changedFilesMinimumCoverage: parseInt(core.getInput('changed-files-minimum-coverage') || '0', 10),
artifactName: core.getInput('artifact-name'),
updateComment: core.getInput('update-comment').toLowerCase() === 'true'
updateComment: core.getInput('update-comment').toLowerCase() === 'true',
allFilesCoverageVisible: core.getInput('all-files-coverage-visible').toLowerCase() === 'true',
testChangedFiles: core.getInput('test-changed-files')
};
const action = new PrTestCoverageAction_1.PrTestCoverageAction(inputs, github.context);
await action.execute();
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions dist/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export interface ActionInputs {
changedFilesMinimumCoverage: number;
artifactName: string;
updateComment: boolean;
allFilesCoverageVisible: boolean;
testChangedFiles: string;
}
export interface FileCoverage {
file: string;
Expand Down
2 changes: 1 addition & 1 deletion dist/types.d.ts.map

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

26 changes: 15 additions & 11 deletions src/CoverageReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import * as path from 'path'
export class CoverageReporter {
private readonly allFilesMinimumCoverage: number
private readonly changedFilesMinimumCoverage: number
private readonly allFilesCoverageVisible: boolean

constructor(allFilesMinimumCoverage: number = 0, changedFilesMinimumCoverage: number = 0) {
constructor(allFilesMinimumCoverage: number = 0, changedFilesMinimumCoverage: number = 0, allFilesCoverageVisible: boolean = false) {
this.allFilesMinimumCoverage = allFilesMinimumCoverage
this.changedFilesMinimumCoverage = changedFilesMinimumCoverage
this.allFilesCoverageVisible = allFilesCoverageVisible
}

generateReport(coverageData: CoverageData, changedFiles: ChangedFile[]): CoverageReport {
Expand Down Expand Up @@ -114,12 +116,14 @@ export class CoverageReporter {
const changedFilesStatus = this.getCoverageStatus(report.changedFiles.linesCoverage, false)

let markdown = `## Coverage Report ${allFilesStatus}\n\n`

// All Files Summary
markdown += `### All Files\n`
markdown += `- Lines: ${report.allFiles.linesHit}/${report.allFiles.linesTotal} (${report.allFiles.linesCoverage.toFixed(1)}%) ${allFilesStatus}\n`
markdown += `- Functions: ${report.allFiles.functionsHit}/${report.allFiles.functionsTotal} (${report.allFiles.functionsCoverage.toFixed(1)}%)\n`
markdown += `- Branches: ${report.allFiles.branchesHit}/${report.allFiles.branchesTotal} (${report.allFiles.branchesCoverage.toFixed(1)}%)\n\n`

// All Files Summary (conditionally hidden)
if (this.allFilesCoverageVisible) {
markdown += `### All Files\n`
markdown += `- Lines: ${report.allFiles.linesHit}/${report.allFiles.linesTotal} (${report.allFiles.linesCoverage.toFixed(1)}%) ${allFilesStatus}\n`
markdown += `- Functions: ${report.allFiles.functionsHit}/${report.allFiles.functionsTotal} (${report.allFiles.functionsCoverage.toFixed(1)}%)\n`
markdown += `- Branches: ${report.allFiles.branchesHit}/${report.allFiles.branchesTotal} (${report.allFiles.branchesCoverage.toFixed(1)}%)\n\n`
}

// Changed Files Summary
markdown += `### Changed Files\n`
Expand All @@ -130,7 +134,7 @@ export class CoverageReporter {
// File Details Table with nested directory structure
if (report.fileDetails.length > 0) {
markdown += `Files changed:\n\n`

// Convert fileDetails to FileDetail format for DirectoryStructure
const fileDetails: FileDetail[] = report.fileDetails.map(file => ({
file: file.file,
Expand All @@ -150,14 +154,14 @@ export class CoverageReporter {
percentage: file.branches.percentage
}
}))

// Build directory tree and generate nested table
const directoryStructure = new DirectoryStructure()
const directoryTree = directoryStructure.buildDirectoryTree(fileDetails)

const markdownGenerator = new MarkdownTableGenerator()
const nestedTable = markdownGenerator.generateTable(directoryTree)

markdown += nestedTable
}

Expand Down
16 changes: 14 additions & 2 deletions src/GitHubService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,29 @@ import { ChangedFile } from './types'
export class GitHubService {
private static readonly FILES_PER_PAGE = 100
private static readonly COMMENTS_PER_PAGE = 100

private readonly octokit: ReturnType<typeof github.getOctokit>
private readonly context: Context
private readonly commentIdentifier = '<!-- PR Test Coverage Report -->'
private readonly testChangedFiles: string

constructor(githubToken: string, context: Context) {
constructor(githubToken: string, context: Context, testChangedFiles: string = '') {
this.octokit = github.getOctokit(githubToken)
this.context = context
this.testChangedFiles = testChangedFiles
}

async getChangedFiles(): Promise<ChangedFile[]> {
// If test mode is enabled, return mock changed files
if (this.testChangedFiles) {
const files = this.testChangedFiles.split(',').map(filename => filename.trim()).filter(f => f)
core.info(`TEST MODE: Using mocked changed files: ${files.join(', ')}`)
return files.map(filename => ({
filename,
status: 'modified'
}))
}

const pullRequest = this.context.payload.pull_request
if (!pullRequest) {
throw new Error('No pull request found in context')
Expand Down
Loading