원클릭으로
dotnet-gha-build-test
Configures GitHub Actions .NET build/test -- setup-dotnet, NuGet cache, reporting.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Configures GitHub Actions .NET build/test -- setup-dotnet, NuGet cache, reporting.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Deploys .NET from GitHub Actions. Azure Web Apps, GitHub Pages, container registries.
Composes GitHub Actions workflows. Reusable workflows, composite actions, matrix, caching.
Publishes .NET artifacts from GitHub Actions. NuGet push, container images, signing, SBOM.
| name | dotnet-gha-build-test |
| description | Configures GitHub Actions .NET build/test -- setup-dotnet, NuGet cache, reporting. |
| license | MIT |
| targets | ["*"] |
| category | operations |
| subcategory | ci-cd |
| tags | ["devops","dotnet","skill","github-actions","ci-cd"] |
| version | 1.0.0 |
| author | dotnet-agent-harness |
| invocable | true |
| related_skills | ["dotnet-gha-patterns","dotnet-gha-deploy","dotnet-gha-publish"] |
| claudecode | {"allowed-tools":["Read","Grep","Glob","Bash","Write","Edit"]} |
| codexcli | {"short-description":".NET skill guidance for github actions"} |
| opencode | {"allowed-tools":["Read","Grep","Glob","Bash","Write","Edit"]} |
| copilot | {} |
| geminicli | {} |
| antigravity | {} |
.NET build and test workflow patterns for GitHub Actions: actions/setup-dotnet@v4 configuration with multi-version
installs and NuGet authentication, NuGet restore caching for fast CI, dotnet test with result publishing via
dorny/test-reporter, code coverage upload to Codecov and Coveralls, multi-TFM matrix testing across net8.0 and net9.0,
and test sharding strategies for large projects.
Version assumptions: actions/setup-dotnet@v4 for .NET 8/9/10 support. dorny/test-reporter@v1 for test result
visualization. Codecov and Coveralls GitHub Apps for coverage reporting.
Cross-references: [skill:dotnet-add-ci] for starter build/test templates, [skill:dotnet-testing-strategy] for test architecture guidance, [skill:dotnet-ci-benchmarking] for benchmark CI integration, [skill:dotnet-artifacts-output] for artifact upload path adjustments when using centralized build output layout.
actions/setup-dotnet@v4 Configuration
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
```text
### Multi-Version Install
Install multiple SDK versions for multi-TFM builds within a single job:
```yaml
- name: Setup .NET SDKs
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
9.0.x
```text
The first listed version becomes the default `dotnet` on PATH. All installed versions are available via `--framework`
targeting.
### NuGet Authentication for Private Feeds
Configure NuGet source authentication via `actions/setup-dotnet@v4`:
```yaml
- name: Setup .NET with NuGet auth
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
source-url: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
env:
NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```json
For multiple private feeds, configure additional sources after setup:
```yaml
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Add private NuGet feed
run: |
set -euo pipefail
dotnet nuget add source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json \
--name AzureArtifacts \
--username az \
--password ${{ secrets.AZURE_ARTIFACTS_PAT }} \
--store-password-in-clear-text
```text
The `--store-password-in-clear-text` flag is required on Linux runners where DPAPI encryption is unavailable.
### Global.json SDK Version Pinning
When `global.json` exists in the repository root, `actions/setup-dotnet@v4` can read it automatically:
```yaml
- name: Setup .NET from global.json
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
```json
This ensures CI uses the same SDK version as local development.
---
## NuGet Restore Caching
### Standard Cache Configuration
```yaml
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }}
restore-keys: |
nuget-${{ runner.os }}-
- name: Restore dependencies
run: dotnet restore MySolution.sln
```text
### Built-in Cache with setup-dotnet
`actions/setup-dotnet@v4` has built-in caching support using `packages.lock.json`:
```yaml
- name: Setup .NET with caching
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
cache: true
cache-dependency-path: '**/packages.lock.json'
```json
Generate lock files locally first: `dotnet restore --use-lock-file`. Commit `packages.lock.json` files for deterministic
restore.
### Cache Key Strategy
| Key Component | Purpose |
| ------------------------------------------ | ------------------------------------------------- |
| `runner.os` | Prevent cross-OS cache collisions |
| `hashFiles('**/*.csproj')` | Invalidate when package references change |
| `hashFiles('**/Directory.Packages.props')` | Invalidate when centrally managed versions change |
| `restore-keys` prefix | Partial match for incremental cache reuse |
---
## Test Result Publishing
### dorny/test-reporter
Publish `dotnet test` results as GitHub Actions check annotations with inline failure details:
```yaml
- name: Test
run: |
set -euo pipefail
dotnet test MySolution.sln \
--configuration Release \
--logger "trx;LogFileName=test-results.trx" \
--results-directory ./test-results
continue-on-error: true
id: test
- name: Publish test results
uses: dorny/test-reporter@v1
if: always()
with:
name: '.NET Test Results'
path: 'test-results/**/*.trx'
reporter: dotnet-trx
fail-on-error: true
```text
**Key decisions:**
- `continue-on-error: true` on the test step ensures the reporter step always runs, even on failures
- `if: always()` on the reporter step publishes results regardless of test outcome
- `fail-on-error: true` on the reporter marks the check as failed when tests fail
### Alternative: EnricoMi/publish-unit-test-result-action
For richer PR comment integration with test counts:
```yaml
- name: Publish test results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: 'test-results/**/*.trx'
check_name: 'Test Results'
```text
---
## Code Coverage Upload
### Codecov
```yaml
- name: Test with coverage
run: |
set -euo pipefail
dotnet test MySolution.sln \
--configuration Release \
--collect:"XPlat Code Coverage" \
--results-directory ./coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
directory: ./coverage
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
```text
### Coveralls
```yaml
- name: Test with coverage
run: |
set -euo pipefail
dotnet test MySolution.sln \
--configuration Release \
--collect:"XPlat Code Coverage" \
--results-directory ./coverage
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
file: coverage/**/coverage.cobertura.xml
format: cobertura
github-token: ${{ secrets.GITHUB_TOKEN }}
```xml
### Coverage Report Generation with ReportGenerator
Generate human-readable HTML coverage reports alongside CI upload:
```yaml
- name: Generate coverage report
run: |
set -euo pipefail
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator \
-reports:coverage/**/coverage.cobertura.xml \
-targetdir:coverage-report \
-reporttypes:HtmlInline_AzurePipelines\;Cobertura
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage-report/
retention-days: 30
```text
---
## Multi-TFM Matrix Testing
### Matrix Strategy for TFMs
```yaml
jobs:
test:
strategy:
fail-fast: false
matrix:
tfm: [net8.0, net9.0]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
9.0.x
- name: Cache NuGet
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }}
restore-keys: |
nuget-${{ runner.os }}-
- name: Test ${{ matrix.tfm }}
run: |
set -euo pipefail
dotnet test MySolution.sln \
--framework ${{ matrix.tfm }} \
--configuration Release \
--logger "trx;LogFileName=${{ matrix.tfm }}-results.trx" \
--results-directory ./test-results
- name: Publish test results
uses: dorny/test-reporter@v1
if: always()
with:
name: 'Tests (${{ matrix.os }} / ${{ matrix.tfm }})'
path: 'test-results/**/*.trx'
reporter: dotnet-trx
```text
### Install All Required SDKs
When running multi-TFM tests in a single job instead of a matrix, install all required SDKs upfront:
```yaml
- name: Setup .NET SDKs
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
9.0.x
- name: Test all TFMs
run: dotnet test MySolution.sln --configuration Release
```text
Without the matching SDK installed, `dotnet test` cannot build for that TFM and fails with `NETSDK1045`.
---
## Test Sharding for Large Projects
### Splitting Tests Across Parallel Jobs
## Detailed Examples
See [references/detailed-examples.md](references/detailed-examples.md) for complete code samples and advanced patterns.