Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SUBPROJECT_ID setting #213

Merged
merged 15 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from 9 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
112 changes: 110 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,14 +327,25 @@ jobs:
COMMENT_ARTIFACT_NAME: python-coverage-comment-action

# Name of the file in which the body of the comment to post on the PR is stored.
# You typically don't have to change this unless you're already using this name for something else.
# In monorepo setting, see SUBPROJECT_ID.
COMMENT_FILENAME: python-coverage-comment-action.txt

# This setting is only necessary if you plan to run the action multiple times
# in the same repository. It will be appended to the value of all the
# settings that need to be unique, so as for the action to avoid mixing
# up results of multiple runs.
# Affects `COMMENT_FILENAME`, `COVERAGE_DATA_BRANCH`.
# Ideally, use dashes (`-`) rather than underscrores (`_`) to split words,
# for consistency
SUBPROJECT_ID: null / "lib-name"

# An alternative template for the comment for pull requests. See details below.
COMMENT_TEMPLATE: The coverage rate is `{{ coverage.info.percent_covered | pct }}`{{ marker }}

# Name of the branch in which coverage data will be stored on the repository.
# Please make sure that this branch is not protected.
# Default is 'python-coverage-comment-action-data'. Please make sure that this
# branch is not protected.
# In monorepo setting, see SUBPROJECT_ID.
COVERAGE_DATA_BRANCH: python-coverage-comment-action-data

# Deprecated, see https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging
Expand Down Expand Up @@ -383,6 +394,103 @@ coverage (percentage) of the whole project from the PR build:
"Coverage: {{ coverage.info.percent_covered | pct }}{{ marker }}"
```

## Monorepo setting

In case you want to use the action multiple times with different parts of your
source (so you have multiple codebases into a single repo), you'll
need to use SUBPROJECT_ID with a different value for each launch. You may
still use the same step for storing all files as artifacts. You'll end up with
a different comment for each launch. Feel free to use the `COMMENT_TEMPLATE` if
you want each comment to clearly state what it relates to.

```yaml
# .github/workflows/ci.yml
name: CI

on:
pull_request:
push:
branches:
- "main"

jobs:
test:
name: Run tests & display coverage
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
steps:
- uses: actions/checkout@v3

- name: Test project 1
run: make -C project_1 test

- name: Test project 2
run: make -C project_2 test

- name: Coverage comment (project 1)
id: coverage_comment
uses: py-cov-action/python-coverage-comment-action@v3
with:
COVERAGE_PATH: project_1
SUBPROJECT_ID: project-1
GITHUB_TOKEN: ${{ github.token }}

- name: Coverage comment (project 2)
id: coverage_comment
kieferro marked this conversation as resolved.
Show resolved Hide resolved
uses: py-cov-action/python-coverage-comment-action@v3
with:
COVERAGE_PATH: project_2/src
SUBPROJECT_ID: project-2
GITHUB_TOKEN: ${{ github.token }}

- name: Store Pull Request comment to be posted
uses: actions/upload-artifact@v3
if: steps.coverage_comment.outputs.COMMENT_FILE_WRITTEN == 'true'
with:
name: python-coverage-comment-action
# Note the star
path: python-coverage-comment-action*.txt
```

```yaml
# .github/workflows/coverage.yml
name: Post coverage comment

on:
workflow_run:
workflows: ["CI"]
types:
- completed

jobs:
test:
name: Run tests & display coverage
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
permissions:
pull-requests: write
contents: write
actions: read
steps:
- name: Post comment
uses: py-cov-action/python-coverage-comment-action@v3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PR_RUN_ID: ${{ github.event.workflow_run.id }}
SUBPROJECT_ID: project-1
COVERAGE_PATH: project_1

- name: Post comment
uses: py-cov-action/python-coverage-comment-action@v3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PR_RUN_ID: ${{ github.event.workflow_run.id }}
SUBPROJECT_ID: project-2
COVERAGE_PATH: project_2/src
```

# Other topics

## Pinning
Expand Down
23 changes: 20 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ inputs:
Name of the branch in which coverage data will be stored on the repository.
Default is 'python-coverage-comment-action-data'. Please make sure that this
branch is not protected.
In monorepo setting, see SUBPROJECT_ID.
default: python-coverage-comment-action-data
required: false
COVERAGE_PATH:
Expand All @@ -38,13 +39,25 @@ inputs:
COMMENT_ARTIFACT_NAME:
description: >
Name of the artifact in which the body of the comment to post on the PR is stored.
You typically don't have to change this unless you're already using this name for something else.
default: python-coverage-comment-action
required: false
COMMENT_FILENAME:
description: >
Name of the file in which the body of the comment to post on the PR is stored.
In monorepo setting, see SUBPROJECT_ID.
default: python-coverage-comment-action.txt
required: false
SUBPROJECT_ID:
description: >
This setting is only necessary if you plan to run the action multiple
times in the same repository. It will be appended to the value of all the
settings that need to be unique, so as for the action to avoid mixing up
results of multiple runs. Ideally, use dashes (`-`) rather than
underscrores (`_`) to split words, for consistency.
Affects `COMMENT_FILENAME`, `COVERAGE_DATA_BRANCH`.
default: null
required: false
MINIMUM_GREEN:
description: >
If the coverage percentage is above or equal to this value, the badge
Expand All @@ -67,7 +80,7 @@ inputs:
default: false
ANNOTATION_TYPE:
description: >
Only needed if ANNOTATE_MISSING_LINES is set to true. This parameter allows you to choose between
Only relevant if ANNOTATE_MISSING_LINES is set to true. This parameter allows you to choose between
notice, warning and error as annotation type. For more information look here:
https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-notice-message
default: warning
Expand All @@ -78,8 +91,11 @@ inputs:
outputs:
COMMENT_FILE_WRITTEN:
description: >
If "true", a comment file was written to COMMENT_FILENAME. If "false",
no comment file was written (because the comment was already posted).
This output is only set when running in PR mode.It's a boolean indicating
ewjoachim marked this conversation as resolved.
Show resolved Hide resolved
whether a comment file was written to COMMENT_FILENAME or not. If so,
you'll need to run the action in workflow_run mode to post it. If
"false", no comment file was written (likely because the comment was
already posted to the PR).
runs:
using: docker
image: Dockerfile
Expand All @@ -91,6 +107,7 @@ runs:
COVERAGE_PATH: ${{ inputs.COVERAGE_PATH }}
COMMENT_ARTIFACT_NAME: ${{ inputs.COMMENT_ARTIFACT_NAME }}
COMMENT_FILENAME: ${{ inputs.COMMENT_FILENAME }}
SUBPROJECT_ID: ${{ inputs.SUBPROJECT_ID }}
MINIMUM_GREEN: ${{ inputs.MINIMUM_GREEN }}
MINIMUM_ORANGE: ${{ inputs.MINIMUM_ORANGE }}
MERGE_COVERAGE_FILES: ${{ inputs.MERGE_COVERAGE_FILES }}
Expand Down
2 changes: 1 addition & 1 deletion coverage_comment/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def get_pr_number_from_workflow_run(
raise CannotDeterminePR(f"No open PR found for branch {full_branch}")


def get_my_login(github: github_client.GitHub):
def get_my_login(github: github_client.GitHub) -> str:
try:
response = github.user.get()
except github_client.Forbidden:
Expand Down
21 changes: 12 additions & 9 deletions coverage_comment/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,19 +120,22 @@ def generate_comment(
previous_coverage_data_file = storage.get_datafile_contents(
github=gh,
repository=config.GITHUB_REPOSITORY,
branch=config.COVERAGE_DATA_BRANCH,
branch=config.FINAL_COVERAGE_DATA_BRANCH,
)
previous_coverage = None
if previous_coverage_data_file:
previous_coverage = files.parse_datafile(contents=previous_coverage_data_file)

marker = template.get_marker(marker_id=config.SUBPROJECT_ID)
try:
comment = template.get_comment_markdown(
coverage=coverage,
diff_coverage=diff_coverage,
previous_coverage_rate=previous_coverage,
base_template=template.read_template_file("comment.md.j2"),
custom_template=config.COMMENT_TEMPLATE,
marker=marker,
subproject_id=config.SUBPROJECT_ID,
)
except template.MissingMarker:
log.error(
Expand Down Expand Up @@ -167,7 +170,7 @@ def generate_comment(
repository=config.GITHUB_REPOSITORY,
pr_number=config.GITHUB_PR_NUMBER,
contents=comment,
marker=template.MARKER,
marker=marker,
)
except github.CannotPostComment:
log.debug("Exception when posting comment", exc_info=True)
Expand All @@ -178,7 +181,7 @@ def generate_comment(
"on PR comments for external PRs)."
)
comment_file.store_file(
filename=config.COMMENT_FILENAME,
filename=config.FINAL_COMMENT_FILENAME,
content=comment,
)
github.set_output(github_output=config.GITHUB_OUTPUT, COMMENT_FILE_WRITTEN=True)
Expand Down Expand Up @@ -224,7 +227,7 @@ def post_comment(config: settings.Config, github_session: httpx.Client) -> int:
repository=config.GITHUB_REPOSITORY,
artifact_name=config.COMMENT_ARTIFACT_NAME,
run_id=config.GITHUB_PR_RUN_ID,
filename=config.COMMENT_FILENAME,
filename=config.FINAL_COMMENT_FILENAME,
)
except github.NoArtifact:
log.info(
Expand All @@ -240,7 +243,7 @@ def post_comment(config: settings.Config, github_session: httpx.Client) -> int:
repository=config.GITHUB_REPOSITORY,
pr_number=pr_number,
contents=comment,
marker=template.MARKER,
marker=template.get_marker(marker_id=config.SUBPROJECT_ID),
)
log.info("Comment posted in PR")

Expand Down Expand Up @@ -294,14 +297,14 @@ def save_coverage_data_files(
storage.get_raw_file_url,
is_public=is_public,
repository=config.GITHUB_REPOSITORY,
branch=config.COVERAGE_DATA_BRANCH,
branch=config.FINAL_COVERAGE_DATA_BRANCH,
)
readme_url = storage.get_repo_file_url(
branch=config.COVERAGE_DATA_BRANCH,
branch=config.FINAL_COVERAGE_DATA_BRANCH,
repository=config.GITHUB_REPOSITORY,
)
html_report_url = storage.get_html_report_url(
branch=config.COVERAGE_DATA_BRANCH,
branch=config.FINAL_COVERAGE_DATA_BRANCH,
repository=config.GITHUB_REPOSITORY,
)
readme_file, log_message = communication.get_readme_and_log(
Expand All @@ -315,7 +318,7 @@ def save_coverage_data_files(
storage.commit_operations(
operations=operations,
git=git,
branch=config.COVERAGE_DATA_BRANCH,
branch=config.FINAL_COVERAGE_DATA_BRANCH,
)

log.info(log_message)
Expand Down
16 changes: 16 additions & 0 deletions coverage_comment/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Config:
COVERAGE_PATH: pathlib.Path = pathlib.Path(".")
COMMENT_ARTIFACT_NAME: str = "python-coverage-comment-action"
COMMENT_FILENAME: pathlib.Path = pathlib.Path("python-coverage-comment-action.txt")
SUBPROJECT_ID: str | None = None
GITHUB_OUTPUT: pathlib.Path | None = None
MINIMUM_GREEN: decimal.Decimal = decimal.Decimal("100")
MINIMUM_ORANGE: decimal.Decimal = decimal.Decimal("70")
Expand Down Expand Up @@ -119,6 +120,21 @@ def GITHUB_PR_NUMBER(self) -> int | None:
return int(self.GITHUB_REF.split("/")[2])
return None

@property
def FINAL_COMMENT_FILENAME(self):
filename = self.COMMENT_FILENAME
if self.SUBPROJECT_ID:
new_name = f"{filename.stem}-{self.SUBPROJECT_ID}{filename.suffix}"
return filename.parent / new_name
return filename

@property
def FINAL_COVERAGE_DATA_BRANCH(self):
parts = [self.COVERAGE_DATA_BRANCH]
if self.SUBPROJECT_ID:
parts.append(self.SUBPROJECT_ID)
return "-".join(parts)
ewjoachim marked this conversation as resolved.
Show resolved Hide resolved

# We need to type environ as a MutableMapping because that's what
# os.environ is, and just saying `dict[str, str]` is not enough to make
# mypy happy
Expand Down
15 changes: 12 additions & 3 deletions coverage_comment/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

from coverage_comment import coverage as coverage_module

MARKER = """<!-- This comment was produced by python-coverage-comment-action -->"""
MARKER = (
"""<!-- This comment was produced by python-coverage-comment-action{id_part} -->"""
)


def uptodate():
Expand Down Expand Up @@ -39,11 +41,17 @@ class TemplateError(Exception):
pass


def get_marker(marker_id: str | None):
return MARKER.format(id_part=f" (id: {marker_id})" if marker_id else "")


def get_comment_markdown(
coverage: coverage_module.Coverage,
diff_coverage: coverage_module.DiffCoverage,
previous_coverage_rate: decimal.Decimal | None,
base_template: str,
marker: str,
subproject_id: str | None = None,
custom_template: str | None = None,
):
loader = CommentLoader(base_template=base_template, custom_template=custom_template)
Expand All @@ -55,12 +63,13 @@ def get_comment_markdown(
previous_coverage_rate=previous_coverage_rate,
coverage=coverage,
diff_coverage=diff_coverage,
marker=MARKER,
subproject_id=subproject_id,
marker=marker,
)
except jinja2.exceptions.TemplateError as exc:
raise TemplateError from exc

if MARKER not in comment:
if marker not in comment:
raise MissingMarker()

return comment
Expand Down
2 changes: 1 addition & 1 deletion coverage_comment/template_files/comment.md.j2
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% block title %}## Coverage report{% endblock title %}
{% block title %}## Coverage report{% if subproject_id %} ({{ subproject_id }}){% endif %}{% endblock title %}
{% block coverage_evolution -%}
{% if previous_coverage_rate -%}
{% block coverage_evolution_wording -%}
Expand Down
Loading
Loading