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
1 change: 1 addition & 0 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ jobs:
set -euo pipefail
bash test/push-nuget_test.sh
bash test/normalize-ci-matrix_test.sh
bash test/install-dotnet-coverage_test.sh

- name: Run python tests
run: python3 -m unittest discover -s test -p '*_test.py'
2 changes: 1 addition & 1 deletion .github/workflows/csharp-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ jobs:
DOTNET_COVERAGE_VERSION: ${{ steps.dotnet-coverage.outputs.version }}
run: |
set -euo pipefail
dotnet tool update -g dotnet-coverage --version "$DOTNET_COVERAGE_VERSION"
"$GITHUB_WORKSPACE/.github-actions-helpers/scripts/install-dotnet-coverage.sh" "$DOTNET_COVERAGE_VERSION"

- name: Restore
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ docs/*
!docs/public

/test/_stub_push.sh
/test/_stub_dotnet.sh
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Fix `go-ci.yaml` failing the `Augment coverage report with cyclomatic complexity` step on self-hosted runners. The step ran `sudo chown "$(id -un)" code-coverage-results.md` to take back a file that `irongut/CodeCoverageSummary` (a Docker action) writes as root, but self-hosted runners (e.g. the Hetzner pool) lack passwordless sudo, so the step died with `sudo: a password is required` — breaking every Go consumer's `build-and-test` job once it compiled far enough to reach coverage. Ownership is now taken without sudo: when the report is not writable it is replaced with a runner-owned copy via a same-directory `cp` + `mv -f`, which needs only workspace-directory permissions and is a no-op on GitHub-hosted runners where the file is already writable. Reported by `peacefulstudio/terraform-provider-canton-internal`.
- Fix `csharp-ci.yaml`'s `Install dotnet-coverage` step failing outright on shared self-hosted runners when a previous job already left a newer `dotnet-coverage` global tool installed than the current caller's pin. `dotnet tool update` refuses to move to an older version, so a runner that has accumulated a newer version from one repo's pin hard-fails every other repo's job that pins an older one, with no way to recover short of a rerun landing on a different runner. The install step now shells out to a new `scripts/install-dotnet-coverage.sh`, which checks the currently-installed version first and uninstalls-then-reinstalls only when it differs from the pin (in either direction), making the step idempotent regardless of what any other job left behind.

## [2.3.1] - 2026-06-19

Expand Down
26 changes: 26 additions & 0 deletions scripts/install-dotnet-coverage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Copyright (c) 2026 Peaceful Studio OÜ
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail

version="${1:?usage: install-dotnet-coverage.sh <version>}"
dotnet_bin="${DOTNET_BIN:-dotnet}"

installed="$("$dotnet_bin" tool list -g | awk '$1 == "dotnet-coverage" {print $2}')"

if [ "$installed" = "$version" ]; then
echo "dotnet-coverage $version already installed"
exit 0
fi

if [ -n "$installed" ]; then
# `dotnet tool update` refuses to move to an older version, so a runner
# that already carries a newer dotnet-coverage than the caller's pin
# (shared self-hosted runners accumulate whatever the last caller
# installed) fails outright instead of matching the pin. Uninstalling
# first makes this idempotent in both directions.
echo "dotnet-coverage $installed installed, want $version — reinstalling"
"$dotnet_bin" tool uninstall -g dotnet-coverage
fi

"$dotnet_bin" tool install -g dotnet-coverage --version "$version"
100 changes: 100 additions & 0 deletions test/install-dotnet-coverage_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env bash
# Copyright (c) 2026 Peaceful Studio OÜ
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail

here="$(cd "$(dirname "$0")" && pwd)"
script="$here/../scripts/install-dotnet-coverage.sh"

fail=0
check() {
local name="$1" expected="$2" actual="$3"
if [ "$expected" = "$actual" ]; then
echo "ok - $name"
else
echo "FAIL - $name: expected [$expected] got [$actual]"
fail=1
fi
}

stub="$here/_stub_dotnet.sh"
cat > "$stub" <<'STUB'
#!/usr/bin/env bash
if [ "$1" = "tool" ] && [ "$2" = "list" ]; then
echo "Package Id Version Commands"
echo "-----------------------------------------"
if [ -n "${STUB_INSTALLED_VERSION:-}" ]; then
echo "dotnet-coverage $STUB_INSTALLED_VERSION dotnet-coverage"
fi
exit 0
fi
if [ "$1" = "tool" ] && [ "$2" = "uninstall" ]; then
echo "UNINSTALL" >> "$CALL_LOG"
exit 0
fi
if [ "$1" = "tool" ] && [ "$2" = "install" ]; then
shift 2
ver=""
while [ $# -gt 0 ]; do
if [ "$1" = "--version" ]; then ver="$2"; fi
shift
done
echo "INSTALL $ver" >> "$CALL_LOG"
exit 0
fi
echo "unexpected dotnet invocation: $*" >&2
exit 1
STUB
chmod +x "$stub"

work="$(mktemp -d)"
export CALL_LOG="$work/calls.log"

# Not installed at all — the common fresh-runner case.
: > "$CALL_LOG"
set +e
out="$(STUB_INSTALLED_VERSION= DOTNET_BIN="$stub" bash "$script" 18.8.0)"
rc=$?
set -e
check "not-installed exit 0" 0 "$rc"
check "not-installed calls" "INSTALL 18.8.0" "$(cat "$CALL_LOG")"

# Installed at an older version — the ordinary update case.
: > "$CALL_LOG"
set +e
STUB_INSTALLED_VERSION=18.7.0 DOTNET_BIN="$stub" bash "$script" 18.8.0 >/dev/null
rc=$?
set -e
check "older-installed exit 0" 0 "$rc"
check "older-installed calls" "$(printf 'UNINSTALL\nINSTALL 18.8.0')" "$(cat "$CALL_LOG")"

# Installed at a NEWER version than the pin — the actual regression this
# script exists to fix (`dotnet tool update` refuses to downgrade and fails
# outright here; a shared self-hosted runner can easily end up in this state
# because a different caller's pin installed a newer version first).
: > "$CALL_LOG"
set +e
STUB_INSTALLED_VERSION=18.9.0 DOTNET_BIN="$stub" bash "$script" 18.8.0 >/dev/null
rc=$?
set -e
check "newer-installed exit 0" 0 "$rc"
check "newer-installed calls" "$(printf 'UNINSTALL\nINSTALL 18.8.0')" "$(cat "$CALL_LOG")"

# Already at the exact pinned version — should be a pure no-op, no reinstall.
: > "$CALL_LOG"
set +e
out="$(STUB_INSTALLED_VERSION=18.8.0 DOTNET_BIN="$stub" bash "$script" 18.8.0)"
rc=$?
set -e
check "already-current exit 0" 0 "$rc"
check "already-current calls nothing" "" "$(cat "$CALL_LOG")"
check "already-current message" "dotnet-coverage 18.8.0 already installed" "$out"

# No version argument — usage error.
set +e
DOTNET_BIN="$stub" bash "$script" >/dev/null 2>&1
rc=$?
set -e
check "no-args exit 1" 1 "$rc"

exit $fail