Skip to content

Commit 91aaf3b

Browse files
authored
Merge pull request #594 from olivier-lacroix/feat/write-some-outputs
2 parents 419eeea + 9147c08 commit 91aaf3b

File tree

7 files changed

+265
-48
lines changed

7 files changed

+265
-48
lines changed

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,56 @@ jobs:
346346
path: python-coverage-comment-action.txt
347347
```
348348
349+
### Outputs
350+
351+
The action makes available some data for downstream processing.
352+
353+
| Name | Description |
354+
| --- | --- |
355+
| `activity_run` | The type of activity that was run. One of `process_pr`, `post_comment`, `save_coverage_data_files`. |
356+
357+
All the following outputs are only available when running in PR mode.
358+
359+
| Name | Description |
360+
| --- | --- |
361+
| `comment_file_written` | A boolean indicating whether a comment file was written to `COMMENT_FILENAME` or not. |
362+
| `new_covered_lines` | The number of covered lines in the pull request. |
363+
| `new_num_statements` | The number of statements in the pull request. |
364+
| `new_percent_covered` | The coverage percentage of the pull request. |
365+
| `new_missing_lines` | The number of lines with missing coverage in the pull request. |
366+
| `new_excluded_lines` | The number of excluded lines in the pull request. |
367+
| `new_num_branches` | The number of branches in the pull request. |
368+
| `new_num_partial_branches` | The number of partial branches in the pull request. |
369+
| `new_covered_branches` | The number of covered branches in the pull request. |
370+
| `new_missing_branches` | The number of branches with missing coverage in the pull request. |
371+
| `reference_covered_lines` | The number of covered lines in the base branch. |
372+
| `reference_num_statements` | The number of statements in the base branch. |
373+
| `reference_percent_covered` | The coverage percentage of the base branch. |
374+
| `reference_missing_lines` | The number of lines with missing coverage in the base branch. |
375+
| `reference_excluded_lines` | The number of excluded lines in the base branch. |
376+
| `reference_num_branches` | The number of branches in the base branch. |
377+
| `reference_num_partial_branches` | The number of partial branches in the base branch. |
378+
| `reference_covered_branches` | The number of covered branches in the base branch. |
379+
| `reference_missing_branches` | The number of branches with missing coverage in the base branch. |
380+
| `diff_total_num_lines` | The total number of lines in the diff. |
381+
| `diff_total_num_violations` | The total number of lines with missing coverage in the diff. |
382+
| `diff_total_percent_covered` | The coverage percentage of the diff. |
383+
| `diff_num_changed_lines` | The number of changed lines in the diff. |
384+
385+
Usage may look like this
386+
387+
```yaml
388+
- name: Coverage comment
389+
id: coverage_comment
390+
uses: py-cov-action/python-coverage-comment-action@v3
391+
with:
392+
GITHUB_TOKEN: ${{ github.token }}
393+
394+
- name: Enforce coverage
395+
if: ${{ steps.coverage_comment.outputs.new_percent_covered < steps.coverage_comment.outputs.reference_percent_covered }}
396+
run: echo "Coverage decreased." && exit 1
397+
```
398+
349399
### All options
350400

351401
```yaml

action.yml

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,59 @@ inputs:
111111
Deprecated, see https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging
112112
default: false
113113
outputs:
114-
COMMENT_FILE_WRITTEN:
115-
description: >
116-
This output is only set when running in PR mode. It's a boolean indicating
117-
whether a comment file was written to COMMENT_FILENAME or not. If so,
118-
you'll need to run the action in workflow_run mode to post it. If
119-
"false", no comment file was written (likely because the comment was
120-
already posted to the PR).
114+
activity_run:
115+
description: >
116+
The type of activity that was run. One of `process_pr`, `post_comment`, `save_coverage_data_files`.
117+
comment_file_written:
118+
description: >
119+
A boolean indicating whether a comment file was written to COMMENT_FILENAME or not.
120+
If so, you'll need to run the action in workflow_run mode to post it. If "false",
121+
no comment file was written (likely because the comment was already posted to the PR).
122+
Only available when running in PR mode.
123+
new_covered_lines:
124+
description: The number of covered lines in the pull request. (Only available in PR mode)
125+
new_num_statements:
126+
description: The number of statements in the pull request. (Only available in PR mode)
127+
new_percent_covered:
128+
description: The coverage percentage of the pull request. (Only available in PR mode)
129+
new_missing_lines:
130+
description: The number of lines with missing coverage in the pull request. (Only available in PR mode)
131+
new_excluded_lines:
132+
description: The number of excluded lines in the pull request. (Only available in PR mode)
133+
new_num_branches:
134+
description: The number of branches in the pull request. (Only available in PR mode)
135+
new_num_partial_branches:
136+
description: The number of partial branches in the pull request. (Only available in PR mode)
137+
new_covered_branches:
138+
description: The number of covered branches in the pull request. (Only available in PR mode)
139+
new_missing_branches:
140+
description: The number of branches with missing coverage in the pull request. (Only available in PR mode)
141+
reference_covered_lines:
142+
description: The number of covered lines in the base branch. (Only available in PR mode)
143+
reference_num_statements:
144+
description: The number of statements in the base branch. (Only available in PR mode)
145+
reference_percent_covered:
146+
description: The coverage percentage of the base branch. (Only available in PR mode)
147+
reference_missing_lines:
148+
description: The number of lines with missing coverage in the base branch. (Only available in PR mode)
149+
reference_excluded_lines:
150+
description: The number of excluded lines in the base branch. (Only available in PR mode)
151+
reference_num_branches:
152+
description: The number of branches in the base branch. (Only available in PR mode)
153+
reference_num_partial_branches:
154+
description: The number of partial branches in the base branch. (Only available in PR mode)
155+
reference_covered_branches:
156+
description: The number of covered branches in the base branch. (Only available in PR mode)
157+
reference_missing_branches:
158+
description: The number of branches with missing coverage in the base branch. (Only available in PR mode)
159+
diff_total_num_lines:
160+
description: The total number of lines in the diff. (Only available in PR mode)
161+
diff_total_num_violations:
162+
description: The total number of lines with missing coverage in the diff. (Only available in PR mode)
163+
diff_total_percent_covered:
164+
description: The coverage percentage of the diff. (Only available in PR mode)
165+
diff_num_changed_lines:
166+
description: The number of changed lines in the diff. (Only available in PR mode)
121167
runs:
122168
using: docker
123169
image: Dockerfile

coverage_comment/coverage.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,20 @@ class CoverageMetadata:
2121
show_contexts: bool
2222

2323

24+
class OutputMixin:
25+
def as_output(self, prefix: str) -> dict:
26+
data = dataclasses.asdict(self)
27+
output = {}
28+
for key, value in data.items():
29+
if value is not None and not isinstance(value, dict):
30+
output[f"{prefix}_{key}"] = (
31+
float(value) if isinstance(value, decimal.Decimal) else value
32+
)
33+
return output
34+
35+
2436
@dataclasses.dataclass(kw_only=True)
25-
class CoverageInfo:
37+
class CoverageInfo(OutputMixin):
2638
covered_lines: int
2739
num_statements: int
2840
percent_covered: decimal.Decimal
@@ -76,7 +88,7 @@ def violation_lines(self) -> list[int]:
7688

7789

7890
@dataclasses.dataclass(kw_only=True)
79-
class DiffCoverage:
91+
class DiffCoverage(OutputMixin):
8092
total_num_lines: int
8193
total_num_violations: int
8294
total_percent_covered: decimal.Decimal

coverage_comment/github.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import re
88
import sys
99
import zipfile
10+
from typing import Any
1011
from urllib.parse import urlparse
1112

1213
from coverage_comment import github_client, log
@@ -209,7 +210,7 @@ def post_comment(
209210
raise CannotPostComment from exc
210211

211212

212-
def set_output(github_output: pathlib.Path | None, **kwargs: bool) -> None:
213+
def set_output(github_output: pathlib.Path | None, **kwargs: Any) -> None:
213214
if github_output:
214215
with github_output.open("a") as f:
215216
for key, value in kwargs.items():

coverage_comment/main.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,12 @@ def process_pr(
268268
],
269269
)
270270

271+
outputs = {"activity_run": "process_pr"}
272+
outputs |= coverage.info.as_output(prefix="new")
273+
outputs |= diff_coverage.as_output(prefix="diff")
274+
if previous_coverage:
275+
outputs |= previous_coverage.info.as_output(prefix="reference")
276+
271277
try:
272278
if config.FORCE_WORKFLOW_RUN or not pr_number:
273279
raise github.CannotPostComment
@@ -292,14 +298,16 @@ def process_pr(
292298
filename=config.FINAL_COMMENT_FILENAME,
293299
content=comment,
294300
)
295-
github.set_output(github_output=config.GITHUB_OUTPUT, COMMENT_FILE_WRITTEN=True)
301+
outputs["comment_file_written"] = True
296302
log.debug("Comment stored locally on disk")
297303
else:
298-
github.set_output(
299-
github_output=config.GITHUB_OUTPUT, COMMENT_FILE_WRITTEN=False
300-
)
304+
outputs["comment_file_written"] = False
301305
log.debug("Comment not generated")
302306

307+
github.set_output(
308+
github_output=config.GITHUB_OUTPUT,
309+
**outputs,
310+
)
303311
return 0
304312

305313

@@ -363,6 +371,7 @@ def post_comment(
363371
)
364372
log.info("Comment posted in PR")
365373

374+
github.set_output(github_output=config.GITHUB_OUTPUT, activity_run="post_comment")
366375
return 0
367376

368377

@@ -440,4 +449,8 @@ def save_coverage_data_files(
440449

441450
log.info(log_message)
442451

452+
github.set_output(
453+
github_output=config.GITHUB_OUTPUT, activity_run="save_coverage_data_files"
454+
)
455+
443456
return 0

tests/integration/conftest.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
import pathlib
5+
import shutil
56
import subprocess
67
import uuid
78

@@ -50,16 +51,22 @@ def _(*variables):
5051

5152

5253
@pytest.fixture
53-
def commit(integration_dir):
54+
def git_cmd():
55+
return shutil.which("git")
56+
57+
58+
@pytest.fixture
59+
def commit(integration_dir, git_cmd):
5460
def _():
5561
subprocess.check_call(
56-
["git", "add", "."],
62+
[git_cmd, "add", "."],
5763
cwd=integration_dir,
5864
)
5965
subprocess.check_call(
60-
["git", "commit", "-m", str(uuid.uuid4())],
66+
[git_cmd, "commit", "-m", str(uuid.uuid4())],
6167
cwd=integration_dir,
62-
env={
68+
env=os.environ
69+
| {
6370
"GIT_AUTHOR_NAME": "foo",
6471
"GIT_AUTHOR_EMAIL": "foo",
6572
"GIT_COMMITTER_NAME": "foo",
@@ -73,27 +80,31 @@ def _():
7380

7481

7582
@pytest.fixture
76-
def integration_env(integration_dir, write_file, run_coverage, commit, request):
77-
subprocess.check_call(["git", "init", "-b", "main"], cwd=integration_dir)
83+
def integration_env(
84+
integration_dir, write_file, run_coverage, commit, request, git_cmd
85+
):
86+
subprocess.check_call([git_cmd, "init", "-b", "main"], cwd=integration_dir)
7887
# diff coverage reads the "origin/{...}" branch so we simulate an origin remote
79-
subprocess.check_call(["git", "remote", "add", "origin", "."], cwd=integration_dir)
88+
subprocess.check_call(
89+
[git_cmd, "remote", "add", "origin", "."], cwd=integration_dir
90+
)
8091
write_file("A", "B")
8192
commit()
8293

8394
add_branch_mark = request.node.get_closest_marker("add_branches")
8495
for additional_branch in add_branch_mark.args if add_branch_mark else []:
8596
subprocess.check_call(
86-
["git", "switch", "-c", additional_branch],
97+
[git_cmd, "switch", "-c", additional_branch],
8798
cwd=integration_dir,
8899
)
89100

90101
subprocess.check_call(
91-
["git", "switch", "-c", "branch"],
102+
[git_cmd, "switch", "-c", "branch"],
92103
cwd=integration_dir,
93104
)
94105

95106
write_file("A", "B", "C", "D")
96107
commit()
97108

98109
run_coverage("A", "C")
99-
subprocess.check_call(["git", "fetch", "origin"], cwd=integration_dir)
110+
subprocess.check_call([git_cmd, "fetch", "origin"], cwd=integration_dir)

0 commit comments

Comments
 (0)