Skip to content
Open
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
106 changes: 105 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Currently, this plugin supports two coverage file format.
* jacoco for jvm based languages like java,kotlin,scala
* cobertura can be used for golang projects using [gocov-xml](https://github.com/AlekSi/gocov-xml) utility

This plugin works out of box for [Vela](https://github.com/go-vela),a CI/CD open-sourced by target
This plugin works out of the box with [Vela](https://github.com/go-vela) (a CI/CD platform open-sourced by Target), [GitHub Actions](#github-actions-usage), and any CI that can run a container.

## VELA Usage

Expand Down Expand Up @@ -94,6 +94,110 @@ Once you have coverage.xml same can be passed as an input to plugin shown below
|gh_api_key| false | | api key to auth for posting coverage comments<br><br>if not set, coverage details will not be commented on PR |
|module | false | \<empty string\> | sub-module to use if operating inside a multi-module project (e.g. gradle multi-project build) |

## GitHub Actions Usage

On GitHub Actions you generate the coverage report in a step, then run the plugin
image with the PR diff piped to its stdin. Posting the comment uses the built-in
`GITHUB_TOKEN`, so the job needs `pull-requests: write`.

Leave the base URL unset for public github.com (it defaults to
`https://api.github.com`). For GitHub Enterprise set `PARAMETER_GH_API_BASE_URL`
to your API root, e.g. `https://git.example.com/api/v3`.

### Go (cobertura)

[gocover-cobertura](https://github.com/boumenot/gocover-cobertura) converts a Go
coverage profile to cobertura in a single step (run via `go run`, nothing to install).

```yaml
name: pr-code-coverage
on:
pull_request:

permissions:
contents: read
pull-requests: write

jobs:
coverage:
runs-on: ubuntu-latest
# GITHUB_TOKEN is read-only on fork PRs, so restrict to same-repo PRs.
if: github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # need the base branch present to diff against

- uses: actions/setup-go@v5
with:
go-version: '1.26'

- name: Generate coverage profile
run: go test -coverpkg=./... -coverprofile=coverage.txt ./...

- name: Convert to cobertura
run: go run github.com/boumenot/gocover-cobertura@latest < coverage.txt > coverage.xml

- name: Report coverage on changed lines
env:
PARAMETER_COVERAGE_TYPE: cobertura
PARAMETER_COVERAGE_FILE: coverage.xml
# Must equal the absolute path in the cobertura <source> element,
# which gocover-cobertura sets to the dir `go test` ran in.
PARAMETER_SOURCE_DIRS: ${{ github.workspace }}
PARAMETER_GH_API_KEY: ${{ secrets.GITHUB_TOKEN }}
BUILD_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
REPOSITORY_ORG: ${{ github.repository_owner }}
REPOSITORY_NAME: ${{ github.event.repository.name }}
run: |
git fetch --no-tags origin "${{ github.base_ref }}"
git --no-pager diff --unified=0 "origin/${{ github.base_ref }}" -- '*.go' \
| docker run --rm -i \
-e PARAMETER_COVERAGE_TYPE -e PARAMETER_COVERAGE_FILE \
-e PARAMETER_SOURCE_DIRS -e PARAMETER_GH_API_KEY \
-e BUILD_PULL_REQUEST_NUMBER -e REPOSITORY_ORG -e REPOSITORY_NAME \
-v "${{ github.workspace }}:${{ github.workspace }}" \
-w "${{ github.workspace }}" \
--entrypoint /plugin \
pullrequestcc/pull-request-code-coverage:latest
```

For JVM projects, generate a jacoco report instead and set
`PARAMETER_COVERAGE_TYPE=jacoco`, `PARAMETER_COVERAGE_FILE` to the jacoco XML, and
`PARAMETER_SOURCE_DIRS` to your source dir(s) (e.g. `src/main/java`).

### Environment variables

Outside Vela, configure the plugin with these environment variables (Vela's
`parameters:` map to the same `PARAMETER_*` names automatically):

| variable | required | description |
|---|---|---|
| `PARAMETER_COVERAGE_TYPE` | yes | `jacoco` or `cobertura` |
| `PARAMETER_COVERAGE_FILE` | yes | path to the coverage report |
| `PARAMETER_SOURCE_DIRS` | yes | comma-separated source dirs (see the cobertura `<source>` note above) |
| `PARAMETER_MODULE` | no | sub-module path in a multi-module project |
| `PARAMETER_GH_API_KEY` | no | token used to post the PR comment (`GITHUB_TOKEN` on Actions); `PLUGIN_GH_API_KEY` is also accepted. If unset, results only print to the console |
| `PARAMETER_GH_API_BASE_URL` | no | GitHub API root; defaults to `https://api.github.com`. For Enterprise use `https://HOST/api/v3` |
| `PARAMETER_DEBUG` | no | `true` for verbose path-matching logs |
| `BUILD_PULL_REQUEST_NUMBER` | no\* | PR number to comment on |
| `REPOSITORY_ORG` | no\* | repository owner |
| `REPOSITORY_NAME` | no\* | repository name |

\* required together for the PR comment; if any is missing the plugin only prints to the console.

### Using the container entrypoint directly

The image's default entrypoint (`scripts/start.sh`) can compute the diff for you
in any CI or a plain `docker run`. Point it at the target branch and it fetches,
diffs, and pipes the result to the plugin:

| variable | description |
|---|---|
| `PARAMETER_TARGET_BRANCH` | branch to diff against (Vela uses `VELA_PULL_REQUEST_TARGET` as a fallback) |
| `PARAMETER_RUN_DIR` | directory containing the `plugin` binary (default: image root) |
| `GIT_NETRC_MACHINE` / `GIT_NETRC_USERNAME` / `GIT_NETRC_PASSWORD` | optional `~/.netrc` git auth for private remotes (Vela uses `VELA_NETRC_*`) |

# Development

This project needs go (>= 1.26.3) to be installed. Make sure you run
Expand Down
52 changes: 37 additions & 15 deletions scripts/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,51 @@

set -Eeuo pipefail



if [[ ! -f ~/.netrc ]]
then
echo "~/.netrc does not exist, creating..."
# pull-request-code-coverage entrypoint.
#
# Computes the unified diff between the PR head and its target branch and pipes
# it to the plugin, which reports coverage for the changed lines. This script is
# CI-agnostic (Vela, GitHub Actions, plain Docker): set the generic variables
# below. Vela variables are honoured as fallbacks so existing Vela pipelines
# keep working unchanged.

# --- optional git auth via ~/.netrc -----------------------------------------
# Needed only when the target branch lives on a remote that git must authenticate
# to fetch. Provide GIT_NETRC_* (generic) or VELA_NETRC_* (Vela). Skipped when
# unset, or when a ~/.netrc already exists (e.g. mounted/created by the CI).
netrc_machine="${GIT_NETRC_MACHINE:-${VELA_NETRC_MACHINE:-}}"
netrc_login="${GIT_NETRC_USERNAME:-${VELA_NETRC_USERNAME:-}}"
netrc_password="${GIT_NETRC_PASSWORD:-${VELA_NETRC_PASSWORD:-}}"

if [[ ! -f ~/.netrc && -n "$netrc_machine" ]]; then
echo "~/.netrc does not exist, creating from netrc environment variables..."

cat >~/.netrc <<EOF
machine $VELA_NETRC_MACHINE
login $VELA_NETRC_USERNAME
password $VELA_NETRC_PASSWORD
machine $netrc_machine
login $netrc_login
password $netrc_password
EOF
fi


# Enable command tracing only after the secret-bearing block above, so the
# netrc password is never echoed to the logs.
set -x

module="${PARAMETER_MODULE:-}"
PARAMETER_RUN_DIR="${PARAMETER_RUN_DIR:-}"
branch="${VELA_PULL_REQUEST_TARGET:-}"
run_dir="${PARAMETER_RUN_DIR:-}"

git config --global user.name "vela"
git config --global user.email "vela@xyz.com"
# Branch to diff the PR against: generic variable first, Vela fallback.
branch="${PARAMETER_TARGET_BRANCH:-${VELA_PULL_REQUEST_TARGET:-}}"
if [[ -z "$branch" ]]; then
echo "No target branch set: provide PARAMETER_TARGET_BRANCH (or VELA_PULL_REQUEST_TARGET)." >&2
exit 1
fi

# Avoid git "dubious ownership" failures when the checkout is owned by a
# different user inside the container (common on GitHub Actions and other CI).
git config --global --add safe.directory "*" || true
git config --global user.name "${GIT_AUTHOR_NAME:-pull-request-code-coverage}"
git config --global user.email "${GIT_AUTHOR_EMAIL:-pull-request-code-coverage@users.noreply.github.com}"

git fetch --no-tags origin "$branch"
git --no-pager diff --unified=0 origin/"$branch" $module | $PARAMETER_RUN_DIR/plugin
git fetch --no-tags origin "$branch"
git --no-pager diff --unified=0 "origin/$branch" $module | "$run_dir/plugin"
Loading