Skip to content
Merged
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ _Actions for continuous integration steps: build, lint, and test._

#### - [Build](actions/build/README.md)

#### - [Codecov](actions/codecov/README.md)

#### - [Lint](actions/lint/README.md)

#### - [Test](actions/test/README.md)
Expand Down
92 changes: 92 additions & 0 deletions actions/codecov/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<!-- header:start -->

# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItdXBsb2FkLWNsb3VkIiBjb2xvcj0iYmx1ZSI+PHBvbHlsaW5lIHBvaW50cz0iMTYgMTYgMTIgMTIgOCAxNiI+PC9wb2x5bGluZT48bGluZSB4MT0iMTIiIHkxPSIxMiIgeDI9IjEyIiB5Mj0iMjEiPjwvbGluZT48cGF0aCBkPSJNMjAuMzkgMTguMzlBNSA1IDAgMCAwIDE4IDloLTEuMjZBOCA4IDAgMSAwIDMgMTYuMyI+PC9wYXRoPjxwb2x5bGluZSBwb2ludHM9IjE2IDE2IDEyIDEyIDggMTYiPjwvcG9seWxpbmU+PC9zdmc+) GitHub Action: Codecov

<div align="center">
<img src="https://opengraph.githubassets.com/36aa7cc4e1d084a81183a986cfab32857be10fa31cf7e5e4b9820a5989b4dae9/hoverkraft-tech/ci-github-nodejs" width="60px" align="center" alt="Codecov" />
</div>

---

<!-- header:end -->
<!-- badges:start -->

[![Marketplace](https://img.shields.io/badge/Marketplace-codecov-blue?logo=github-actions)](https://github.com/marketplace/actions/codecov)
[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/)
[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)

<!-- badges:end -->
<!-- overview:start -->

## Overview

Action to upload coverage to Codecov.

- **Automatic dependency management**: Automatically detects and installs missing dependencies (Git, cURL, gnupg) using pkgxdev
- **Configuration fixes**: Automatically fixes pkgxdev configuration issues with unexpanded environment variables in gpgconf.ctl and .curlrc files
- **Cleanup**: Uninstalls dependencies after Codecov upload is complete
- **OIDC support**: Uses OIDC authentication with Codecov for secure uploads

<!-- overview:end -->
<!-- usage:start -->

## Usage

```yaml
- uses: hoverkraft-tech/ci-github-nodejs/actions/codecov@9f334582b395b78e4d7c88fa08a8957a8fe5513c # copilot/fix-variable-expansion-issue
with:
# Working directory where coverage files are located.
# Can be absolute or relative to the repository root.
#
# Default: `.`
working-directory: .
```

<!-- usage:end -->
<!-- inputs:start -->

## Inputs

| **Input** | **Description** | **Required** | **Default** |
| ----------------------- | --------------------------------------------------- | ------------ | ----------- |
| **`working-directory`** | Working directory where coverage files are located. | **false** | `.` |
| | Can be absolute or relative to the repository root. | | |

<!-- inputs:end -->
<!-- secrets:start -->
<!-- secrets:end -->
<!-- outputs:start -->
<!-- outputs:end -->
<!-- examples:start -->
<!-- examples:end -->
<!-- contributing:start -->

## Contributing

Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.

<!-- contributing:end -->
<!-- security:start -->
<!-- security:end -->
<!-- license:start -->

## License

This project is licensed under the MIT License.

SPDX-License-Identifier: MIT

Copyright © 2025 hoverkraft

For more details, see the [license](http://choosealicense.com/licenses/mit/).

<!-- license:end -->
<!-- generated:start -->

---

This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).

<!-- generated:end -->
130 changes: 130 additions & 0 deletions actions/codecov/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: "Codecov"
description: |
Action to upload coverage to Codecov.

- **Automatic dependency management**: Automatically detects and installs missing dependencies (Git, cURL, gnupg) using pkgxdev
- **Configuration fixes**: Automatically fixes pkgxdev configuration issues with unexpanded environment variables in gpgconf.ctl and .curlrc files
- **Cleanup**: Uninstalls dependencies after Codecov upload is complete
- **OIDC support**: Uses OIDC authentication with Codecov for secure uploads

author: hoverkraft
branding:
icon: upload-cloud
color: blue

inputs:
working-directory:
description: |
Working directory where coverage files are located.
Can be absolute or relative to the repository root.
required: false
default: "."

runs:
using: "composite"
steps:
# Check and install dependencies for codecov
- name: Check Codecov dependencies
id: check-codecov-deps
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
// Check which dependencies are missing
const deps = {"git": "git", "curl": "curl", "gpg": "gnupg.org"};
const missingDeps = [];

for (const [dep, pkg] of Object.entries(deps)) {
try {
await io.which(dep, true);
} catch {
missingDeps.push(pkg);
}
}

if (missingDeps.length > 0) {
core.setOutput('missing-deps', missingDeps.join(' '));
}

- name: Install missing Codecov dependencies
if: steps.check-codecov-deps.outputs.missing-deps
uses: pkgxdev/setup@f211ee4db3110b42e5a156282372527e7c1ed723 # v4.0.0
with:
+: ${{ steps.check-codecov-deps.outputs.missing-deps }}

# Fix pkgxdev gnupg's gpgconf.ctl which contains unexpanded environment variables
- name: Fix GPG configuration
if: contains(steps.check-codecov-deps.outputs.missing-deps, 'gnupg.org')
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');

// Find and remove the malformed gpgconf.ctl file that contains unexpanded shell variables
// The pkgxdev gnupg installs gpgconf.ctl next to the gpgconf binary
try {
const gpgconfPath = await io.which('gpgconf', false);
if (gpgconfPath) {
const gpgconfCtl = path.join(path.dirname(gpgconfPath), 'gpgconf.ctl');
if (fs.existsSync(gpgconfCtl)) {
core.info(`Removing malformed gpgconf.ctl: ${gpgconfCtl}`);
await io.rmRF(gpgconfCtl);
}
}
} catch (error) {
core.warning(`Failed to check/remove gpgconf.ctl: ${error.message}`);
}

// Ensure GNUPGHOME is set up correctly
const gnupgHome = path.join(os.homedir(), '.gnupg');
await io.mkdirP(gnupgHome);
fs.chmodSync(gnupgHome, 0o700);

# Fix pkgxdev curl's .curlrc which contains unexpanded environment variables
- name: Fix curl configuration
if: contains(steps.check-codecov-deps.outputs.missing-deps, 'curl')
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('node:fs');
const path = require('node:path');

// Find and fix the .curlrc file that contains unexpanded shell variables like ${SSL_CERT_FILE:-...}
// The pkgxdev curl installs .curlrc next to the curl binary
try {
const curlPath = await io.which('curl', false);
if (curlPath) {
const curlrc = path.join(path.dirname(curlPath), '.curlrc');
if (fs.existsSync(curlrc)) {
core.info(`Removing malformed .curlrc: ${curlrc}`);
await io.rmRF(curlrc);
}
}
} catch (error) {
core.warning(`Failed to check/remove .curlrc: ${error.message}`);
}

- name: 📊 Upload coverage to Codecov
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
with:
directory: ${{ inputs.working-directory }}
root_dir: ${{ inputs.working-directory }}
working-directory: ${{ inputs.working-directory }}
use_oidc: true
disable_telem: true
fail_ci_if_error: false

# Uninstall pkgxdev dependencies after codecov is done
- name: Uninstall Codecov dependencies
if: always() && steps.check-codecov-deps.outputs.missing-deps
shell: bash
env:
MISSING_DEPS: ${{ steps.check-codecov-deps.outputs.missing-deps }}
run: |
if command -v pkgx &> /dev/null; then
for dep in $MISSING_DEPS; do
echo "Uninstalling $dep..."
pkgx uninstall "$dep" 2>/dev/null || true
done
fi
66 changes: 1 addition & 65 deletions actions/test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,75 +142,11 @@ runs:
title: "Code Coverage Report"
body: ${{ steps.parse-coverage-reports.outputs.markdown }}

# Check and install dependencies for codecov in container mode
- name: Check and install Codecov dependencies
if: always() && inputs.coverage == 'codecov' && inputs.container == 'true'
id: check-codecov-deps
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
// Check which dependencies are missing
const deps = {"git": "git", "curl": "curl", "gpg": "gnupg.org"};
const missingDeps = [];

for (const [dep, pkg] of Object.entries(deps)) {
try {
await io.which(dep, true);
} catch {
missingDeps.push(pkg);
}
}

if (missingDeps.length > 0) {
core.setOutput('missing-deps', missingDeps.join(' '));
}

- name: Install missing Codecov dependencies
if: always() && steps.check-codecov-deps.outputs.missing-deps
uses: pkgxdev/setup@f211ee4db3110b42e5a156282372527e7c1ed723 # v4.0.0
with:
+: ${{ steps.check-codecov-deps.outputs.missing-deps }}

# Fix pkgxdev gnupg's gpgconf.ctl which contains unexpanded environment variables
- name: Fix GPG configuration
if: always() && contains(steps.check-codecov-deps.outputs.missing-deps, 'gnupg.org')
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');

// Find and remove the malformed gpgconf.ctl file that contains unexpanded shell variables
// The pkgxdev gnupg installs gpgconf.ctl next to the gpgconf binary
try {
const gpgconfPath = await io.which('gpgconf', false);
if (gpgconfPath) {
const gpgconfCtl = path.join(path.dirname(gpgconfPath), 'gpgconf.ctl');
if (fs.existsSync(gpgconfCtl)) {
core.info(`Removing malformed gpgconf.ctl: ${gpgconfCtl}`);
await io.rmRF(gpgconfCtl);
}
}
} catch (error) {
core.warning(`Failed to check/remove gpgconf.ctl: ${error.message}`);
}

// Ensure GNUPGHOME is set up correctly
const gnupgHome = path.join(os.homedir(), '.gnupg');
await io.mkdirP(gnupgHome);
fs.chmodSync(gnupgHome, 0o700);

- name: 📊 Upload coverage to Codecov
if: always() && inputs.coverage == 'codecov'
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
uses: ./self-test-action/codecov
with:
directory: ${{ inputs.working-directory }}
root_dir: ${{ inputs.working-directory }}
working-directory: ${{ inputs.working-directory }}
use_oidc: true
disable_telem: true
fail_ci_if_error: false

# FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684
- shell: bash
Expand Down
Loading