# codecov-action: four major versions of argument renames and a documented version skew

> codecov/codecov-action is the GitHub Action that uploads coverage reports to Codecov, and its history is largely a story of how the uploader underneath it changed. It also documents a gap between its own latest tags and the version its usage examples tell you to pin.

**codecov/codecov-action** — GitHub Action that uploads coverage to Codecov :open_umbrella: 

- Repository: https://github.com/codecov/codecov-action
- Website: https://www.codecov.io
- Stars: 1,717 · Forks: 258
- Language: Python
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/codecov-codecov-action

## The Action is a shim around a uploader that keeps being replaced

Understanding this repository means knowing that the Action is not the product. The uploader is. The version history records the substitutions.

At v4 the Action moved to the Codecov CLI. At v5 it moved again, this time to the Codecov Wrapper, described in the README as encapsulating the CLI so that the Action gets updates faster. At v6 the change was support for node24. At v7 the wrapper submodule was bumped again, and the notable difference is where the uploader's PGP verification key now comes from: the `codecovsecops` Keybase account rather than wherever it was fetched before.

The architectural consequence is that your workflow pins a version of the Action, and the Action in turn decides which uploader binary runs. You are pinning something that pins something else. When an upload breaks, the first question is which of those two layers changed, and the README does not give you a way to pin the inner one.

The `binary` input is the escape hatch for exactly this problem. Its documented purpose is the file location of a pre-downloaded version of the CLI, which means a team that needs reproducible uploads can supply its own CLI rather than accept whatever the wrapper fetches. That is the right answer for regulated or audited pipelines, and it is worth knowing about before an incident rather than after.

The repository is Python, not JavaScript, with the built output checked into `dist/`, a `.gitmodules` entry for the wrapper, an `install.sh`, an `action.yml` holding the input definitions and a `demo/` directory containing two sample projects used to exercise the action.

## Two arguments were renamed and eight were added

The argument surface is where the action bites. Two inputs were changed rather than removed, which means a workflow written against the old names fails silently in intent rather than in syntax: `file` was deprecated in favour of `files`, and `plugin` in favour of `plugins`. If you have a workflow from before v5 with a single `file:` key pointing at one report, it now needs to be a comma-separated `files:` list.

The v5 release added a group of inputs that show where the team's priorities were: `binary`, `gcov_args`, `gcov_executable`, `gcov_ignore`, `gcov_include`, `report_type`, `skip_validation` and `swift_project`. The gcov cluster is a coherent group for C and C++ projects, letting you point at a specific gcov binary, pass arguments to it, and include or ignore files by pattern. `report_type` is for the languages where Codecov needs to be told what it is receiving, and `swift_project` exists because a Swift project path is not something the tool can infer.

`skip_validation` deserves a note. Turning off validation removes a check that catches malformed reports before upload, which trades a class of clear error message for a class of silent wrong output.

Full usage for every input is not in this README. Consult `action.yml` for the authoritative input list for the version you pin.

The other input worth understanding is `base_sha`, which is scoped narrowly: it is only used in the "pr-base-picking" run command. It is not a general way to re-baseline a report.

## Token, or OIDC with id-token: write

Authentication has two supported shapes, and they are not equivalent.

The token path is the default and is what most workflows use. The token comes from codecov.io for the specific repository, and the README's instruction is to store it as a secret rather than inline it, conventionally named `CODECOV_TOKEN` and passed either as a `token:` input or as an `env:` entry on the step. Both forms appear in the README's usage blocks and both work.

The OIDC path exists to remove the long-lived secret entirely. Setting `use_oidc: true` switches verification to the workflow's OIDC token, and the README is explicit that any token you also supply is ignored, because Codecov defaults to the OIDC token for verification. The step becomes:

```yaml
- uses: codecov/codecov-action@v5
  with:
    use_oidc: true
```

The cost is a permission requirement that must be granted at either the workflow or the job level:

```yaml
permissions:
  id-token: write
```

A fork pull request is the case where the distinction becomes concrete, and the history here is not clean. Tokenless uploading was unsupported as of v4, with a documented exception for pull requests from forks against upstream public repositories so that outside contributors did not need the maintainer's token. Separately, there is a note that if you use Dependabot you must add `CODECOV_TOKEN` as a Dependabot Secret, otherwise Dependabot's pull requests cannot upload.

For public repositories, the Global Upload Token organization setting can let contributors upload without holding the token.

For private repositories, secrets are not available to forks, which the README flags with an important note.

## Runner requirements are the quiet cause of first-run failures

The Action needs `bash`, `curl`, `git` and `gpg` present on the runner, and it needs `actions/checkout` to have run before it. GitHub-hosted runners have these by default. Custom runners and container-based runners do not necessarily, and the README states plainly that the Action will fail if they are absent.

That is a specific and avoidable failure: the job fails at the upload step rather than at setup, and the message points at the Action rather than at the missing package.

There is a related detection caveat. The Action identifies linux, macos and windows runners automatically, but it may misidentify other architectures. The fix is to specify the OS explicitly, and the accepted values are a short list: alpine, alpine-arm64, linux, linux-arm64, macos and windows.

Ordering matters too. The usage blocks all begin with `actions/checkout@main` before the Codecov step, because the uploader reads coverage files from the checked-out working tree. A workflow that puts the upload first will find nothing to upload.

The other inputs in the sample block are ordinary: `fail_ci_if_error` defaults to false and decides whether an upload problem breaks the build, `files` accepts a comma-separated list of report paths, `flags` attaches labels such as `unittests` that Codecov uses to separate reports, `name` identifies the upload, and `verbose` turns on logging. Setting `fail_ci_if_error: true` is the difference between a broken upload being visible and a coverage drop being invisible.

## The README recommends @v5 while the tags are at v7.1.1

There is a documentation gap worth naming, because it is the kind of thing that costs an afternoon.

The usage section says to specify this repository with a tag number and marks `@v5` as recommended, and every example in that section uses `@v5`. Meanwhile the release history shows v7.1.0 on 2026-09-15 and v7.1.1 on 2026-09-17, with v5.5.5 from 2026-06-09 sitting between them in the list. The repository is not archived and its last push was on 2026-09-17, so it is actively worked on, and the README simply has not caught up with its own tags.

What that means practically is that pinning `@v5` gets you the wrapper-based uploader without node24 support, and pinning `@v7` gets you the Keybase-sourced PGP verification key. Both are documented behaviours, so the choice should be deliberate rather than inherited from a copy-pasted example.

The deployment mechanism in the Makefile shows how releases are cut. It deletes and recreates the moving `v7` tag, signs a version-specific tag taken from `src/version` with `git tag v$(VERSION) -s`, and pushes the tags. So `v7` is a floating major tag and `v7.1.1` is the immutable, signed one. If you want a workflow that does not change under you, pinning the signed point tag rather than the floating major is the safer choice, and the major tag is what every README example uses.

Licence is MIT. The repository includes a `CHANGELOG.md` maintained alongside a `changelog.py` script, a `CONTRIBUTING.md` and a `LICENSE` file, so the release history is documented rather than only tagged.

## Conclusion

Use codecov-action if your repository already publishes to Codecov and you want upload authentication handled for you, either with a `CODECOV_TOKEN` secret or with OIDC. Do not adopt it as a neutral coverage reporter, because the action is a thin wrapper whose behaviour is defined by whichever Codecov CLI release it pulls, so an upload problem is often a Codecov-side problem and not something you can debug in your workflow file. Verify first which major version you pin, since the README's usage examples still say `@v5` while the newest tags are v7.1.0 and v7.1.1, that your runner actually has `bash`, `curl`, `git` and `gpg` present if it is a custom or container runner, and that the `permissions: id-token: write` block exists if you intend to use `use_oidc` instead of a token.

## FAQ

### Which version of codecov-action should I use in my workflow?

The README's usage section marks `@v5` as recommended and all its examples use `@v5`, while the newest tags are v7.1.0 and v7.1.1. v5 wraps the Codecov CLI in the Codecov Wrapper, v6 adds node24 support, and v7 bumps the wrapper and sources its PGP verification key from the codecovsecops Keybase account.

### Why does codecov-action fail on my runner?

The Action requires `bash`, `curl`, `git` and `gpg` on the runner, and it fails if any of them are missing. GitHub-hosted runners have these by default, so the problem appears on custom or container runners, and `actions/checkout` must also run before the Codecov step.

### Can codecov-action upload without a Codecov token?

Yes, through OIDC: set `use_oidc: true` and grant `id-token: write` under `permissions` at workflow or job level. Any token you also supply is ignored. For public repositories, an organization-level Global Upload Token setting also lets contributors upload without the maintainer's token.

### What happened to the file and plugin arguments?

The README marks `file` as deprecated in favour of `files` and `plugin` as deprecated in favour of `plugins`, so a workflow written against the older names needs updating. The v5 release also added `binary`, `gcov_args`, `gcov_executable`, `gcov_ignore`, `gcov_include`, `report_type`, `skip_validation` and `swift_project`.

### Why does codecov-action misidentify my runner architecture?

The Action identifies linux, macos and windows runners automatically but may misidentify other architectures. You can specify the OS explicitly, with accepted values alpine, alpine-arm64, linux, linux-arm64, macos and windows.

### How do Dependabot pull requests upload coverage?

The README says you must add `CODECOV_TOKEN` as a Dependabot Secret, because secrets are not otherwise available to the Dependabot context, and without it Dependabot's pull requests cannot upload coverage.

## Sources

- [codecov/codecov-action on GitHub](https://github.com/codecov/codecov-action)
- [License: MIT](https://github.com/codecov/codecov-action/blob/main/LICENSE)
- [Project website](https://www.codecov.io)
- [README](https://github.com/codecov/codecov-action/blob/main/README.md)
- [Releases](https://github.com/codecov/codecov-action/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/codecov-codecov-action
