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
69 changes: 69 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,75 @@ jobs:
name: packages
path: ./artifacts/*.nupkg

# Measures test coverage and publishes it to Codacy (OPS-157454).
# pdl-public, not a GitHub-hosted runner and not pdl-prod-cluster. This repository is public, so a
# fork pull request is untrusted code from a stranger: pdl-prod-cluster runs a privileged
# Docker-in-Docker sidecar with hostPath mounts on a production node and must never run it.
# pdl-public is the hardened scale set that may: no dind, no privileged container, no hostPath.
coverage:
runs-on: [pdl-public]
timeout-minutes: 30

# The actions-runner image our scale sets use does not offer the Node version several of these
# actions request by default; without this they fail before their first step runs.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
DOTNET_NOLOGO: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1

steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # Nerdbank.GitVersioning needs the history to compute a version.

# The runner user cannot write /usr/share/dotnet, so the SDK goes under the job's temp directory.
- name: Setup .NET
uses: actions/setup-dotnet@v6
env:
DOTNET_INSTALL_DIR: ${{ runner.temp }}/dotnet
with:
dotnet-version: '10.0.x'

- name: Build tests
run: dotnet build Codacy.Api.Test/Codacy.Api.Test.csproj --configuration Debug

# The test project is a Microsoft.Testing.Platform application (UseMicrosoftTestingPlatformRunner),
# so coverage is collected by running it directly with Microsoft.Testing.Extensions.CodeCoverage
# rather than through `dotnet test`. On Linux the executable has no .exe extension. The runner
# image ships no pwsh, hence plain bash.
#
# CI runs only the tests that need no credentials. The classes under Integration/, which call the
# live Codacy API with a token from user secrets, already carry [Trait("Category", "Integration")]
# and are excluded here. xunit.runner.json sets failSkips: true, so leaving them in would turn
# this job red rather than skipping them.
- name: Run tests with coverage
run: >-
./Codacy.Api.Test/bin/Debug/net10.0/Codacy.Api.Test
--coverage
--coverage-settings coverage.config
--coverage-output-format cobertura
--coverage-output coverage.cobertura.xml
--filter "Category!=Integration"

# continue-on-error: a Codacy outage must not turn a passing test run red. The trade-off is that
# an expired or missing project token fails silently, so check the log for
# "Coverage received successfully".
- name: Upload coverage to Codacy
continue-on-error: true
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: Codacy.Api.Test/bin/Debug/net10.0/TestResults/coverage.cobertura.xml

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃敶 HIGH RISK

The coverage report path is likely incorrect. The 'Run tests' step uses '--coverage-output coverage.cobertura.xml' from the root, so the output will be at 'TestResults/coverage.cobertura.xml' rather than inside the bin directory. Verify the path to ensure the upload step finds the file.


- name: Upload coverage artifact
if: always()
continue-on-error: true
uses: actions/upload-artifact@v7
with:
name: coverage
path: Codacy.Api.Test/bin/Debug/net10.0/TestResults/coverage.cobertura.xml
retention-days: 7

publish:
needs: build
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions Codacy.Api.Test/Codacy.Api.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<TargetFramework>net10.0</TargetFramework>
<OutputType>Exe</OutputType>
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
</PropertyGroup>

<ItemGroup>
Expand Down
33 changes: 33 additions & 0 deletions coverage.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Microsoft.Testing.Extensions.CodeCoverage settings.

The attribute exclusions are not optional if figures are to stay comparable across the estate: the
Microsoft collector includes generated code by default, where coverlet excluded it. Porting them is
worth several points of apparent coverage on a repository with generated clients.
-->
<Configuration>
<CodeCoverage>
<ModulePaths>
<Exclude>
<ModulePath>.*Test\.dll$</ModulePath>
<ModulePath>.*Tests\.dll$</ModulePath>
</Exclude>
</ModulePaths>
<Attributes>
<Exclude>
<Attribute>^System\.Diagnostics\.CodeAnalysis\.ExcludeFromCodeCoverageAttribute$</Attribute>
<Attribute>^System\.Runtime\.CompilerServices\.CompilerGeneratedAttribute$</Attribute>
<Attribute>^System\.CodeDom\.Compiler\.GeneratedCodeAttribute$</Attribute>
<Attribute>^System\.ObsoleteAttribute$</Attribute>
</Exclude>
</Attributes>
<Sources>
<Exclude>
<Source>.*\\obj\\.*</Source>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃煛 MEDIUM RISK

Suggestion: The path separator in the regex is Windows-specific. Since the job runs on a Linux runner ('pdl-public'), use a cross-platform pattern (e.g., forward slashes or '[/\\]') to ensure the 'obj' directory is correctly excluded.

Suggested fix:

Suggested change
<Source>.*\\obj\\.*</Source>
<Source>.*/obj/.*</Source>

</Exclude>
</Sources>
<UseVerifiableInstrumentation>False</UseVerifiableInstrumentation>
<CollectFromChildProcesses>True</CollectFromChildProcesses>
</CodeCoverage>
</Configuration>
Loading