Uploading Reports to Codecov using the Codecov CLI

Introduction

Codecov uses the Codecov CLI to make it easy to upload coverage reports to Codecov for processing.

ℹ️

Update on the Bash and Node Uploader

With the introduction of the CLI we're upgrading our GitHub Action, Circle CI Orb and Bitrise Step to use the CLI to upload reports. Therefore, we're no longer adding more features to the Bash and Node uploaders moving forward. Any functional bugs on those would be fixed exclusively to the CLI moving forward.

We will still endeavour to patch critical security fixes to the Node Uploader, but we highly encourage people using the Bash and Node Uploader to plan on moving to use the Codecov CLI.

Using the CLI

Using the CLI to upload reports with codecov.io (Cloud)

The first step is to download the CLI. You can use our dedicated wrappers, or invoke things yourself in CI.

👍

Dedicated wrappers for the Codecov CLI

Avoid setup time and use a build pipeline-specific wrapper to the uploader to automatically ingest and run the CLI:

Codecov's Github Action
Codecov's CircleCI Orb
Codecov's Bitrise Step

These wrappers all include integrity checking via SHASUM verification.

🚧

It is Highly Recommended to Integrity Check the CLI

While the snippets below can be used to download and use the CLI directly, it is highly recommended to perform signature and SHASUM verification to ensure integrity of the CLI before use. See Integrity Checking the Uploader below for more information.

Download Using Pip

To use codecov-cli in your local machine, or your CI workflows, you need to install it:

pip install codecov-cli

pip install codecov-cli

The above command will download the latest version of codecov-cli. If you wish to use a specific version, releases can be viewed here.

Your default will need to be Python3 in order to make this work.

Note: If you're installing in a pytest environment, you may need to call pytest rehash before the CLI will work.

Download As a Binary

For Codecov Cloud users, the CLI can be invoked as follows:

#download Codecov CLI
curl -Os https://cli.codecov.io/latest/linux/codecov
sudo chmod +x codecov
#download Codecov CLI
curl -Os https://cli.codecov.io/latest/alpine/codecov
sudo chmod +x codecov
./codecov --help
#download Codecov CLI
curl -Os https://cli.codecov.io/latest/macos/codecov
sudo chmod +x codecov
./codecov --help
#download Codecov CLI
$ProgressPreference = 'SilentlyContinue' 
Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe 
-Outfile codecov.exe .\codecov.exe
#download Codecov CLI
curl -Os https://cli.codecov.io/latest/linux-arm64/codecov
sudo chmod +x codecov
#download Codecov CLI
curl -Os https://cli.codecov.io/latest/alpine-arm64/codecov
sudo chmod +x codecov

The above commands will download the latest version of the CLI. If you wish to use a specific version of the CLI, releases can be viewed per distribution here: https://cli.codecov.io/ .

Pinning to a particular version requires replacing "latest" in the curl command with the specific version numbers, as follows:

#download Codecov CLI
curl -Os https://cli.codecov.io/v0.4.4/linux/codecov
sudo chmod +x codecov

Uploading coverage reports to Codecov

Add the following snippet after your tests have run and a coverage report has been generated.

Here, we will upload the test report called coverage-service.xml, we are passing in the flag called "service" and a dynamic name to specify a specific test run (it will be useful to see in the Codecov UI). We are using some options params like --verbose and --fail-on-error

Note: the most important param that you must pass in this case is the upload token

./codecov --verbose upload-process --fail-on-error -t ${{ secrets.CODECOV_TOKEN }} -n 'service'-${{ github.run_id }} -F service -f coverage-service.xml

Self-Hosted Use of the CLI

Note that for Codecov Self-Hosted the Self-Hosted URL will need to be included in the upload command via the --enterprise-url parameter. An example:

# here we upload the test report called  coverage-service.xml, we are passing 
# in the flag called "service" and a dyncamic name  to specify a specifc test run
# we are using some options params like --verbose and --fail-on-error
# the most important that you must pass in this case is the actual upload token
# NOTE: we are adding a parameter for the self-hosted URL

./codecov --verbose --enterprise-url https://<your-codecov-self-hosted-url> upload-process --fail-on-error -t ${{ secrets.CODECOV_TOKEN }} -n 'service'-${{ github.run_id }} -F service -f coverage-service.xml 

Upload Token

The Codecov CLI's upload command will automatically search your environment for a $CODECOV_TOKEN environment variable and use it if found. If you do not have a repository upload token, or global upload token, stored as an environment variable, you will need to pass it into each command manually, like so: -t {$CODECOV_TOKEN}.

The Codecov CLI supports 2 classes of tokens - a "global" upload token that is tied to your Github Organization, and a more fine-grained repo upload token that is scoped to the repo being set up.

Organization upload token

Per-repository Token

A unique upload token is required to identify which project the coverage belongs to. This token is located in the repository settings (/<github | gitlab | bitbucket>///settings).

Integrity Checking the Codecov CLI

The Codecov CLI can be integrity checked against a known GPG key signature, and can also have its contents checked via SHASUM. While performing these two checks is optional, it is highly recommended to do so. By checking the GPG signature and the SHASUM of the uploader, users can be much more confident in the overall integrity of the downloaded file.

At a high level, to integrity check the new Uploader, one must:

  1. Import the Codecov PGP public key (one-time step). The Codecov PGP public key can be retrieved from Keybase or many other keyservers. Key ID: ED779869 Key Fingerprint: 2703 4E7F DB85 0E0B BC2C 62FF 806B B28A ED77 9869
  2. Download the Uploader, SHA256SUM, and SHA256SUM.sig files for your particular distribution
  3. Verify the SHA256SUM file is signed using Codecov’s PGP key
  4. Verify the SHA256SUM in the file matches the CLI

The following example performs these steps for each distribution of the Uploader's latest version before using the Uploader to upload a coverage report:

🚧

Alpine Linux may Require Additional Dependencies

If the following commands fail when using Alpine Linux, you may need to run: apk add curl gnupg coreutils

🚧

Windows may Require Additional Dependencies

If gpg.exe is not already installed on your system, you can download the Windows GPG client from: https://gnupg.org/download/

For systems running gpg>= 2.4.3:

curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step  
curl -Os https://cli.codecov.io/latest/linux/codecov
curl -Os https://cli.codecov.io/latest/linux/codecov.SHA256SUM
curl -Os https://cli.codecov.io/latest/linux/codecov.SHA256SUM.sig
gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM

shasum -a 256 -c codecov.SHA256SUM
sudo chmod +x codecov
./codecov --help
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step  
curl -Os https://cli.codecov.io/latest/alpine/codecov
curl -Os https://cli.codecov.io/latest/alpine/codecov.SHA256SUM
curl -Os https://cli.codecov.io/latest/alpine/codecov.SHA256SUM.sig
gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM

shasum -a 256 -c codecov.SHA256SUM
sudo chmod +x codecov
./codecov --help
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step  
curl -Os https://cli.codecov.io/latest/macos/codecov
curl -Os https://cli.codecov.io/latest/macos/codecov.SHA256SUM
curl -Os https://cli.codecov.io/latest/macos/codecov.SHA256SUM.sig
gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM

sudo chmod +x codecov
./codecov --help
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri https://keybase.io/codecovsecurity/pgp_keys.asc -OutFile codecov.asc 
gpg.exe --import codecov.asc

Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe -Outfile codecov.exe
Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe.SHA256SUM -Outfile codecov.exe.SHA256SUM
Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe.SHA256SUM.sig -Outfile codecov.exe.SHA256SUM.sig

gpg.exe --verify codecov.exe.SHA256SUM.sig codecov.exe.SHA256SUM
If ($(Compare-Object -ReferenceObject  $(($(certUtil -hashfile codecov.exe SHA256)[1], "codecov.exe") -join "  ") -DifferenceObject $(Get-Content codecov.exe.SHA256SUM)).length -eq 0) { echo "SHASUM verified" } Else {exit 1}
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step  
curl -Os https://cli.codecov.io/latest/linux-arm64/codecov
curl -Os https://cli.codecov.io/latest/linux-arm64/codecov.SHA256SUM
curl -Os https://cli.codecov.io/latest/linux-arm64/codecov.SHA256SUM.sig
gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM

shasum -a 256 -c codecov.SHA256SUM
sudo chmod +x codecov
./codecov --help
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step  
curl -Os https://cli.codecov.io/latest/alpine-arm64/codecov
curl -Os https://cli.codecov.io/latest/alpine-arm64/codecov.SHA256SUM
curl -Os https://cli.codecov.io/latest/alpine-arm64/codecov.SHA256SUM.sig
gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM

shasum -a 256 -c codecov.SHA256SUM
sudo chmod +x codecov
./codecov --help

For those running gpg < 2.4.3:

curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step

curl -Os https://uploader.codecov.io/latest/linux/codecov

curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM

curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig

gpgv codecov.SHA256SUM.sig codecov.SHA256SUM

shasum -a 256 -c codecov.SHA256SUM

chmod +x codecov
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step

curl -Os https://uploader.codecov.io/latest/alpine/codecov

curl -Os https://uploader.codecov.io/latest/alpine/codecov.SHA256SUM

curl -Os https://uploader.codecov.io/latest/alpine/codecov.SHA256SUM.sig

gpgv codecov.SHA256SUM.sig codecov.SHA256SUM

shasum -a 256 -c codecov.SHA256SUM

chmod +x codecov
./codecov -t ${CODECOV_TOKEN}
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step
curl -Os https://cli.codecov.io/latest/macos/codecov
curl -Os https://cli.codecov.io/latest/macos/codecov.SHA256SUM
curl -Os https://cli.codecov.io/latest/macos/codecov.SHA256SUM.sig
gpgv codecov.SHA256SUM.sig codecov.SHA256SUM

sudo chmod +x codecov
./codecov --help
./codecov -t ${CODECOV_TOKEN}
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri https://keybase.io/codecovsecurity/pgp_keys.asc -OutFile codecov.asc 
gpg.exe --import codecov.asc

Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe -Outfile codecov.exe
Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe.SHA256SUM -Outfile codecov.exe.SHA256SUM
Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe.SHA256SUM.sig -Outfile codecov.exe.SHA256SUM.sig

gpg.exe --verify codecov.exe.SHA256SUM.sig codecov.exe.SHA256SUM
If ($(Compare-Object -ReferenceObject  $(($(certUtil -hashfile codecov.exe SHA256)[1], "codecov.exe") -join "  ") -DifferenceObject $(Get-Content codecov.exe.SHA256SUM)).length -eq 0) { echo "SHASUM verified" } Else {exit 1}
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step

curl -Os https://uploader.codecov.io/latest/linux-arm64/codecov

curl -Os https://uploader.codecov.io/latest/linux-arm64/codecov.SHA256SUM

curl -Os https://uploader.codecov.io/latest/linux-arm64/codecov.SHA256SUM.sig

gpgv codecov.SHA256SUM.sig codecov.SHA256SUM

shasum -a 256 -c codecov.SHA256SUM

chmod +x codecov
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step

curl -Os https://uploader.codecov.io/latest/alpine-arm64/codecov

curl -Os https://uploader.codecov.io/latest/alpine-arm64/codecov.SHA256SUM

curl -Os https://uploader.codecov.io/latest/alpine-arm64/codecov.SHA256SUM.sig

gpgv codecov.SHA256SUM.sig codecov.SHA256SUM

shasum -a 256 -c codecov.SHA256SUM

chmod +x codecov
./codecov -t ${CODECOV_TOKEN}

To check your gpg version, run

gpg --version

Running test within containers

If you are running your tests within containers, it's possible that the environment variables needed for the CLI to run are not reproduced into the docker container. Here's how you can set up Codecov CLI to upload to Codecov, both within the container when test run and after tests run in the container.

Fetching Version Specific Metadata

Metadata can be fetched for a particular release of the Uploader (including latest) as follows:

curl -H "Accept: application/json" https://cli.codecov.io/alpine/latest  | jq

Which will return a JSON response of the following form:

{
    "artifact": {
        "distro": "linux",
        "file": "codecovcli_linux",
        "full_version": "v0.4.4",
        "created_at": "2024-01-11 16:36:06",
        "version": "v0.4.4",
        "hash": "e5e5916c6597a0bf37e77871c66ba5c25c73d794bf7c167a383fbf4a5b223ac2"
    },
    "link": "https:\/\/cli.codecov.io\/v0.4.4\/linux\/codecov",
    "file_hash_link": "https:\/\/cli.codecov.io\/v0.4.4\/linux\/codecov.SHA256SUM",
    "file_sig_link": "https:\/\/cli.codecov.io\/v0.4.4\/linux\/codecov.SHA256SUM.sig",
    "github_release_link": "https:\/\/github.com\/codecov\/codecov-cli\/releases\/tag\/v0.4.4",
    "hash": "e5e5916c6597a0bf37e77871c66ba5c25c73d794bf7c167a383fbf4a5b223ac2",
    "version": "v0.4.4",
    "full_version": "v0.4.4"
}

The response contains meta information about the particular version in the artifact object, include the distro and the commit SHA of the release. Links to distributions of the particular version are also provided.

While this is generally useful, the most obvious use case is leveraging this metadata to setup a vendoring pipeline that fetches and verifies latest whenever it updates and stores this verified version of the CLI in an private CDN, filestore, or other storage apparatus.

Supporting Tokenless Uploads

As you can see, all examples show uploading to Codecov with the Codecov Token (or the org level Global Upload Token).

Currently, tokenless uploading is only available to forks attempting to create PRs on public repositories. This does mean that for most use cases, you will still need a token, even for public repositories. However, contributors creating PRs from their forks to the upstream repo will be able to get coverage information from Codecov.

Uploader Command Line Arguments

The Codecov CLI is an exciting way to interact with new Codecov features. In order to find more options on how to upload using the CLI, please review CLI Options