Skip to main content 首页 创作者 rudironsoni synaxis dotnet-ado-build-test
dotnet-ado-build-test Configures .NET build/test in Azure DevOps. DotNetCoreCLI task, Artifacts, test results.
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/rudironsoni/Synaxis --skill dotnet-ado-build-test命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... name dotnet-ado-build-test category operations subcategory ci-cd description Configures .NET build/test in Azure DevOps. DotNetCoreCLI task, Artifacts, test results. license MIT targets ["*"] tags ["testing","dotnet","skill"] version 0.0.1 author dotnet-agent-harness invocable true claudecode {"allowed-tools":["Read","Grep","Glob","Bash","Write","Edit"]} codexcli {"short-description":".NET skill guidance for testing tasks"} opencode {"allowed-tools":["Read","Grep","Glob","Bash","Write","Edit"]} copilot {} geminicli {} antigravity {}
dotnet-ado-build-test
.NET build and test pipeline patterns for Azure DevOps: DotNetCoreCLI@2 task for build, test, and pack operations,
NuGet restore with Azure Artifacts feeds using NuGetAuthenticate@1, test result publishing with PublishTestResults@2
for TRX and JUnit formats, code coverage with PublishCodeCoverageResults@2 for Cobertura and JaCoCo formats, and
multi-TFM matrix strategy across net8.0 and net9.0.
Version assumptions: DotNetCoreCLI@2 task (current). UseDotNet@2 for SDK installation. NuGetAuthenticate@1 for
Azure Artifacts. PublishTestResults@2 and PublishCodeCoverageResults@2 for reporting.
Scope
DotNetCoreCLI@2 task for build, test, pack, and custom commands
NuGet restore with Azure Artifacts feeds (NuGetAuthenticate@1)
Test result publishing with PublishTestResults@2 (TRX, JUnit)
Code coverage with PublishCodeCoverageResults@2 (Cobertura)
Multi-TFM matrix strategy across TFMs and operating systems
Out of scope
Starter CI templates -- see [skill:dotnet-add-ci]
Test architecture and strategy -- see [skill:dotnet-testing-strategy]
Benchmark regression detection in CI -- see [skill:dotnet-ci-benchmarking]
Publishing and deployment -- see [skill:dotnet-ado-publish] and [skill:dotnet-ado-unique]
GitHub Actions build/test workflows -- see [skill:dotnet-gha-build-test]
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.
DotNetCoreCLI@2 Task
Build
steps:
- task: UseDotNet@2
displayName: 'Install .NET SDK'
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName:
'Restore'
inputs:
command:
'restore'
projects:
'MyApp.sln'
-
task:
DotNetCoreCLI@2
displayName:
'Build'
inputs:
command:
'build'
projects:
'MyApp.sln'
arguments:
'-c Release --no-restore'
```bash
```yaml
-
task:
DotNetCoreCLI@2
displayName:
'Run tests'
inputs:
command:
'test'
projects:
'**/*Tests.csproj'
arguments:
>-
-c Release --logger "trx;LogFileName=test-results.trx" --results-directory
$(Build.ArtifactStagingDirectory)/test-results
```csharp
```yaml
-
task:
DotNetCoreCLI@2
displayName:
'Pack NuGet packages'
inputs:
command:
'pack'
packagesToPack:
'src/**/*.csproj'
configuration:
'Release'
outputDir:
'$(Build.ArtifactStagingDirectory)/nupkgs'
nobuild:
true
```csharp
For
commands
not
directly
supported
by
the
task
(e.g.,
`dotnet
tool
install`):
```yaml
-
task:
DotNetCoreCLI@2
displayName:
'Install dotnet tools'
inputs:
command:
'custom'
custom:
'tool'
arguments:
'restore'
```bash
Install multiple SDK versions for multi-TFM builds:
```yaml
-
task:
UseDotNet@2
displayName:
'Install .NET 8'
inputs:
packageType:
'sdk'
version:
'8.0.x'
-
task:
UseDotNet@2
displayName:
'Install .NET 9'
inputs:
packageType:
'sdk'
version:
'9.0.x'
```text
Each
`UseDotNet@2`
invocation
adds
the
SDK
version
to
PATH.
The
last
installed
version
becomes
the
default,
but
all
versions
are
available
via
`--framework`
targeting.
---
```yaml
steps:
-
task:
NuGetAuthenticate@1
displayName:
'Authenticate NuGet feeds'
-
task:
DotNetCoreCLI@2
displayName:
'Restore'
inputs:
command:
'restore'
projects:
'MyApp.sln'
feedsToUse:
'config'
nugetConfigPath:
'nuget.config'
```bash
The
`NuGetAuthenticate@1`
task
configures
credentials
for
all
Azure
Artifacts
feeds
referenced
in
`nuget.config`.
No
explicit
PAT
or
API
key
is
needed
--
the
task
uses
the
pipeline's
identity.
For
simple
setups
without
a
`nuget.config`,
select feeds directly in the restore task:
```yaml
-
task:
DotNetCoreCLI@2
displayName:
'Restore with Azure Artifacts'
inputs:
command:
'restore'
projects:
'MyApp.sln'
feedsToUse:
'select'
vstsFeed:
'MyProject/MyFeed'
includeNuGetOrg:
true
```text
Azure
Artifacts
feeds
can
proxy
nuget.org
as
an
upstream
source.
When
configured,
a
single
feed
reference
provides
access to both private packages and public NuGet packages:
```xml
<!--
nuget.config
with
Azure
Artifacts
upstream
-->
<?xml
version="1.0"
encoding="utf-8"?>
<configuration>
<packageSources>
<clear
/>
<add
key="MyFeed"
value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json"
/>
</packageSources>
</configuration>
```json
With
upstream
sources
enabled
on
the
feed,
nuget.org
packages
are
cached
in
the
Azure
Artifacts
feed,
providing
a
single
authenticated
source
for
all
packages.
For
feeds
in
different
Azure
DevOps
organizations,
use a service connection:
```yaml
-
task:
NuGetAuthenticate@1
displayName:
'Authenticate external feed'
inputs:
nuGetServiceConnections:
'ExternalOrgFeedConnection'
-
task:
DotNetCoreCLI@2
displayName:
'Restore'
inputs:
command:
'restore'
projects:
'MyApp.sln'
feedsToUse:
'config'
nugetConfigPath:
'nuget.config'
```bash
---
```yaml
-
task:
DotNetCoreCLI@2
displayName:
'Run tests'
inputs:
command:
'test'
projects:
'**/*Tests.csproj'
arguments:
>-
-c Release --logger "trx;LogFileName=results.trx" --results-directory $(Common.TestResultsDirectory)
continueOnError:
true
-
task:
PublishTestResults@2
displayName:
'Publish test results'
condition:
always()
inputs:
testResultsFormat:
'VSTest'
testResultsFiles:
'$(Common.TestResultsDirectory)/**/*.trx'
mergeTestResults:
true
testRunTitle:
'.NET Unit Tests'
```text
**Key
decisions:**
-
`continueOnError:
true
`
on
the
test
task
ensures
the
publish
step
always
runs,
even
on
test
failures
-
`condition:
always()`
on
the
publish
task
runs
regardless
of
previous
step
outcome
-
`mergeTestResults:
true
`
combines
results
from
multiple
test
projects
into
a
single
test
run
-
`testRunTitle`
provides
a
descriptive
name
in
the
Azure
DevOps
Test
tab
Some
third-party
test
frameworks
output
JUnit
XML.
Use
the
`JUnit`
format:
```yaml
-
task:
PublishTestResults@2
displayName:
'Publish JUnit results'
condition:
always()
inputs:
testResultsFormat:
'JUnit'
testResultsFiles:
'**/junit-results.xml'
mergeTestResults:
true
```xml
Attach screenshots or logs to test results for debugging failed tests:
```yaml
-
task:
DotNetCoreCLI@2
displayName:
'Run tests with attachments'
inputs:
command:
'test'
projects:
'**/*Tests.csproj'
arguments:
>-
-c Release --logger "trx;LogFileName=results.trx" --results-directory $(Common.TestResultsDirectory)
--collect:"XPlat Code Coverage"
continueOnError:
true
-
task:
PublishTestResults@2
displayName:
'Publish test results'
condition:
always()
inputs:
testResultsFormat:
'VSTest'
testResultsFiles:
'$(Common.TestResultsDirectory)/**/*.trx'
mergeTestResults:
true
testRunTitle:
'.NET Tests'
publishRunAttachments:
true
```text
---
```yaml
-
task:
DotNetCoreCLI@2
displayName:
'Test with coverage'
inputs:
command:
'test'
projects:
'**/*Tests.csproj'
arguments:
>-
-c Release --collect:"XPlat Code Coverage" --results-directory $(Agent.TempDirectory)/coverage
-
task:
PublishCodeCoverageResults@2
displayName:
'Publish code coverage'
inputs:
summaryFileLocation:
'$(Agent.TempDirectory)/coverage/**/coverage.cobertura.xml'
```xml
The
`PublishCodeCoverageResults@2`
task
(v2)
auto-generates
HTML
coverage
reports
in
the
Azure
DevOps
Build
Summary
tab
without
requiring
`reportgenerator`.
For custom coverage reports beyond the built-in rendering:
```yaml
-
task:
DotNetCoreCLI@2
displayName:
'Test with coverage'
inputs:
command:
'test'
projects:
'**/*Tests.csproj'
arguments:
>-
-c Release --collect:"XPlat Code Coverage" --results-directory $(Agent.TempDirectory)/coverage
-
script:
|
set -euo pipefail
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator \
-reports:$(Agent.TempDirectory)/coverage/**/coverage.cobertura.xml \
-targetdir:$(Build.ArtifactStagingDirectory)/coverage-report \
-reporttypes:HtmlInline_AzurePipelines\;Cobertura
displayName:
'Generate coverage report'
-
task:
PublishCodeCoverageResults@2
displayName:
'Publish coverage'
inputs:
summaryFileLocation:
'$(Build.ArtifactStagingDirectory)/coverage-report/Cobertura.xml'
-
task:
PublishPipelineArtifact@1
displayName:
'Upload coverage report'
inputs:
targetPath:
'$(Build.ArtifactStagingDirectory)/coverage-report'
artifactName:
'coverage-report'
```text
Enforce minimum coverage by parsing the Cobertura XML in a script step:
```yaml
-
script:
|
set -euo pipefail
COVERAGE_FILE=$(find $(Agent.TempDirectory)/coverage -name 'coverage.cobertura.xml' | head -1)
COVERAGE=$(python3 -c "
import xml.etree.ElementTree as ET
tree = ET.parse('$COVERAGE_FILE')
print(float(tree.getroot().attrib['line-rate']) * 100)
")
echo "Line coverage: ${COVERAGE}%"
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "##vso[task.logissue type=error]Coverage ${COVERAGE}% is below 80% threshold"
exit 1
fi
displayName:
'Enforce coverage threshold'
```text
---
```yaml
jobs:
-
job:
Test
strategy:
matrix:
Linux_net80:
vmImage:
'ubuntu-latest'
tfm:
'net8.0'
dotnetVersion:
'8.0.x'
Linux_net90:
vmImage:
'ubuntu-latest'
tfm:
'net9.0'
dotnetVersion:
'9.0.x'
Windows_net80:
vmImage:
'windows-latest'
tfm:
'net8.0'
dotnetVersion:
'8.0.x'
Windows_net90:
vmImage:
'windows-latest'
tfm:
'net9.0'
dotnetVersion:
'9.0.x'
pool:
vmImage:
$(vmImage)
steps:
-
task:
UseDotNet@2
displayName:
'Install .NET $(dotnetVersion)'
inputs:
packageType:
'sdk'
version:
$(dotnetVersion)
-
task:
DotNetCoreCLI@2
displayName:
'Test $(tfm) on $(vmImage)'
inputs:
command:
'test'
projects:
'**/*Tests.csproj'
arguments:
>-
-c Release --framework $(tfm) --logger "trx;LogFileName=$(tfm)-results.trx" --results-directory
$(Common.TestResultsDirectory)
continueOnError:
true
-
task:
PublishTestResults@2
displayName:
'Publish $(tfm) results'
condition:
always()
inputs:
testResultsFormat:
'VSTest'
testResultsFiles:
'$(Common.TestResultsDirectory)/**/*.trx'
testRunTitle:
'$(tfm) on $(vmImage)'
```text
When
running
all
TFMs
in
one
job
(instead
of
matrix),
install all required SDKs:
```yaml
steps:
-
task:
UseDotNet@2
displayName:
'Install .NET 8'
inputs:
packageType:
'sdk'
version:
'8.0.x'
-
task:
UseDotNet@2
displayName:
'Install .NET 9'
inputs:
packageType:
'sdk'
version:
'9.0.x'
-
task:
DotNetCoreCLI@2
displayName:
'Test all TFMs'
inputs:
command:
'test'
projects:
'**/*Tests.csproj'
arguments:
'-c Release'
```bash
Without
the
matching
SDK
installed,
`dotnet
test`
cannot
build
for
that
TFM
and
fails
with
`NETSDK1045`.
```yaml
parameters:
-
name:
configurations
type:
object
default:
-
tfm:
'net8.0'
dotnetVersion:
'8.0.x'
-
tfm:
'net9.0'
dotnetVersion:
'9.0.x'
jobs:
-
${{
each
config
in
parameters.configurations
}}:
-
job:
Test_${{
replace(config.tfm,
'.'
,
'_'
)
}}
displayName:
'Test ${{ config.tfm }}'
pool:
vmImage:
'ubuntu-latest'
steps:
-
task:
UseDotNet@2
inputs:
packageType:
'sdk'
version:
${{
config.dotnetVersion
}}
-
task:
DotNetCoreCLI@2
displayName:
'Test ${{ config.tfm }}'
inputs:
command:
'test'
projects:
'**/*Tests.csproj'
arguments:
'-c Release --framework ${{ config.tfm }}'
```bash
---
**Primary approach:** Use Serena symbol operations for efficient code navigation:
1. **Find definitions**:
`serena_find_symbol`
instead
of
text
search
2. **Understand structure**:
`serena_get_symbols_overview`
for
file
organization
3. **Track references**:
`serena_find_referencing_symbols`
for
impact
analysis
4. **Precise edits**:
`serena_replace_symbol_body`
for
clean
modifications
**When
to
use
Serena
vs
traditional
tools:**
-
✅
**Use Serena**:
Navigation,
refactoring,
dependency
analysis,
precise
edits
-
✅
**Use Read/Grep**:
Reading
full
files,
pattern
matching,
simple
text
operations
-
✅
**Fallback**:
If
Serena
unavailable,
traditional
tools
work
fine
**Example
workflow:**
```text
Read:
src/Services/OrderService.cs
Grep:
"public void ProcessOrder"
serena_find_symbol:
"OrderService/ProcessOrder"
serena_get_symbols_overview:
"src/Services/OrderService.cs"
```
1
.
**Use
`set
-euo
pipefail`
in
multi-line
`script:`
steps**
--
ADO
`script:`
tasks
on
Linux
default
to
`set
-e`
but
do
not
set
`pipefail`
or
`nounset`;
without
`pipefail`,
a
failure
in
a
piped
command
is
silently
swallowed.
2
.
**Use
`continueOnError:
true
`
on
the
test
task,
not
on
the
result
publisher**
--
the
test
task
must
not
fail
the
pipeline
before
results
are
published,
but
the
publisher
should
reflect
the
actual
test
outcome.
3
.
**Install
all
required
SDK
versions
for
multi-TFM
builds**
--
`dotnet
test`
without
the
matching
SDK
produces
`NETSDK1045`;
add
a
`UseDotNet@2`
step
for
each
required
version.
4
.
**`NuGetAuthenticate@1`
must
precede
the
restore
step**
--
authentication
tokens
are
injected
into
the
agent's
NuGet
config
at
task
execution
time;
restoring
before
authentication
fails
with
401
.
5
.
**Use
`feedsToUse:
'config'
`
with
`nuget.config`
for
complex
feed
setups**
--
`feedsToUse:
'select'
`
supports
only
one
Azure
Artifacts
feed;
multi-feed
scenarios
require
a
`nuget.config`
file.
6
.
**Coverage
collection
requires
`--collect:"XPlat
Code
Coverage"`**
--
the
default
`dotnet
test`
does
not
produce
coverage
files;
the
`XPlat
Code
Coverage`
collector
is
built
into
the
.NET
SDK.
7
.
**`PublishCodeCoverageResults@2`
expects
Cobertura
XML**
--
passing
TRX
or
other
formats
to
the
coverage
publisher
produces
no
output;
ensure
the
collector
outputs
Cobertura
format.
8
.
**ADO
matrix
syntax
differs
from
GHA**
--
ADO
uses
named
matrix
entries
with
key-value
pairs,
not
arrays;
each
entry
must
define
all
variable
names
used
in
the
job.
9
.
**Never
hardcode
credentials
in
pipeline
YAML**
--
use
variable
groups
linked
to
Azure
Key
Vault
or
pipeline-level
secret
variables;
hardcoded
secrets
are
visible
in
repository
history.