Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Composable GitHub Actions workflow patterns for .NET projects: reusable workflows with workflow_call, composite
actions for shared step sequences, matrix builds across TFMs and operating systems, path-based triggers, concurrency
groups for duplicate run cancellation, environment protection rules, NuGet and SDK caching strategies, and
workflow_dispatch inputs for manual triggers.
Version assumptions: GitHub Actions workflow syntax v2. actions/setup-dotnet@v4 for .NET 8/9/10 support.
actions/cache@v4 for dependency caching.
Scope
Reusable workflows with workflow_call
Composite actions for shared step sequences
Matrix builds across TFMs and operating systems
Path-based triggers and concurrency groups
NuGet and SDK caching strategies
workflow_dispatch inputs for manual triggers
Out of scope
Starter CI/CD templates -- see [skill:dotnet-add-ci]
CLI release pipelines (tag-triggered build-package-release for CLI tools) -- see [skill:dotnet-cli-release-pipeline]
Benchmark CI workflows -- see [skill:dotnet-ci-benchmarking]
Azure DevOps pipeline patterns -- see [skill:dotnet-ado-patterns]
Build/test specifics -- see [skill:dotnet-gha-build-test]
Publishing workflows -- see [skill:dotnet-gha-publish]
Deployment patterns -- see [skill:dotnet-gha-deploy]
Cross-references: [skill:dotnet-add-ci] for starter templates that these patterns extend,
[skill:dotnet-cli-release-pipeline] for CLI-specific release automation, [skill:dotnet-ci-benchmarking] for
benchmark-specific CI integration.
Reusable Workflows (workflow_call)
Defining a Reusable Workflow
Reusable workflows allow callers to invoke an entire workflow as a single step. Define inputs, outputs, and secrets for
a clean contract:
# .github/workflows/build-reusable.ymlname:Build(Reusable)on:workflow_call:inputs:dotnet-version:description:'.NET SDK version to install'required:false
[]
[]
[, , ]
[, ]
[]
[]
[]
type:
string
default:
'8.0.x'
configuration:
description:
'Build configuration'
required:
false
type:
string
default:
'Release'
project-path:
description:
'Path to solution or project file'
required:
true
type:
string
outputs:
artifact-name:
description:
'Name of the uploaded build artifact'
value:
${{
jobs.build.outputs.artifact-name
}}
secrets:
NUGET_AUTH_TOKEN:
description:
'NuGet feed authentication token'
required:
false
jobs:
build:
runs-on:
ubuntu-latest
outputs:
artifact-name:
build-${{
github.sha
}}
steps:
-
uses:
actions/checkout@v4
-
name:
Setup
.NET
uses:
actions/setup-dotnet@v4
with:
dotnet-version:
${{
inputs.dotnet-version
}}
-
name:
Restore
run:
dotnet
restore
${{
inputs.project-path
}}
-
name:
Build
run:
dotnet
build
${{
inputs.project-path
}}
-c
${{
inputs.configuration
}}
--no-restore
-
name:
Upload
build
artifact
uses:
actions/upload-artifact@v4
with:
name:
build-${{
github.sha
}}
path:
|
**/bin/${{ inputs.configuration }}/**
retention-days:
7
```text
### Calling a Reusable Workflow
```yaml
# .github/workflows/ci.yml
name:
CI
on:
push:
branches:
main
pull_request:
branches:
main
jobs:
build:
uses:
./.github/workflows/build-reusable.yml
with:
dotnet-version:
'8.0.x'
project-path:
MyApp.sln
secrets:
NUGET_AUTH_TOKEN:
${{
secrets.NUGET_AUTH_TOKEN
}}
test:
needs:
build
uses:
./.github/workflows/test-reusable.yml
with:
dotnet-version:
'8.0.x'
project-path:
MyApp.sln
```yaml
### Cross-Repository Reusable Workflows
Reference workflows from other repositories using the full path:
'Install .NET SDK and restore NuGet packages with caching'
inputs:
dotnet-version:
description:
'.NET SDK version'
required:
false
default:
'8.0.x'
project-path:
description:
'Path to solution or project'
required:
true
runs:
using:
'composite'
steps:
-
name:
Setup
.NET
SDK
uses:
actions/setup-dotnet@v4
with:
dotnet-version:
${{
inputs.dotnet-version
}}
-
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
shell:
bash
run:
dotnet
restore
${{
inputs.project-path
}}
```bash
### Using a Composite Action
```yaml
jobs:
build:
runs-on:
ubuntu-latest
steps:
-
uses:
actions/checkout@v4
-
name:
Setup
.NET
environment
uses:
./.github/actions/dotnet-setup
with:
dotnet-version:
'9.0.x'
project-path:
MyApp.sln
-
name:
Build
run:
dotnet
build
MyApp.sln
-c
Release
--no-restore
```text
### Reusable Workflow vs Composite Action
|
Feature
|
Reusable
Workflow
|
Composite
Action
|
|
----------------
|
-------------------------------
|
-------------------------------
|
|
Scope
|
Entire
job
with
runner
|
Steps
within
a
job
|
|
Runner
selection
|
Own
`runs-on`
|
Caller's
runner
|
|
Secrets
access
|
Explicit
or
`inherit`
|
Caller's
context
|
|
Outputs
|
Job-level
outputs
|
Step-level
outputs
|
|
Best
for
|
Complete
build/test/deploy
jobs
|
Shared
setup/teardown
sequences
|
---
## Matrix Builds
### Multi-TFM and Multi-OS Matrix
```yaml
jobs:
test:
strategy:
fail-fast:
false
matrix:
os:
ubuntu-latest
windows-latest
macos-latest
dotnet-version:
'8.0.x'
'9.0.x'
include:
-
os:
ubuntu-latest
dotnet-version:
'10.0.x'
exclude:
-
os:
macos-latest
dotnet-version:
'8.0.x'
runs-on:
${{
matrix.os
}}
steps:
-
uses:
actions/checkout@v4
-
name:
Setup
.NET
${{
matrix.dotnet-version
}}
uses:
actions/setup-dotnet@v4
with:
dotnet-version:
${{
matrix.dotnet-version
}}
-
name:
Test
run:
dotnet
test
--framework
net${{
matrix.dotnet-version
==
'8.0.x'
&&
'8.0'
||
matrix.dotnet-version
==
'9.0.x'
&&
'9.0'
||
'10.0'
}}
```text
**Key
decisions:**
-
`fail-fast:
false
`
ensures
all
matrix
combinations
run
even
if
one
fails,
giving
full
signal
on
which
platforms/TFMs
are
broken
-
`include`
adds
specific
combinations
not
in
the
Cartesian
product
-
`exclude`
removes
combinations
that
are
unnecessary
or
unsupported
### Dynamic Matrix from JSON
Generate matrix values dynamically for complex scenarios:
```yaml
jobs:
compute-matrix:
runs-on:
ubuntu-latest
outputs:
matrix:
${{
steps.set-matrix.outputs.matrix
}}
steps:
-
uses:
actions/checkout@v4
-
id:
set-matrix
shell:
bash
run:
|
set -euo pipefail
# Extract TFMs from Directory.Build.props or csproj files
TFMS=$(grep -rh '<TargetFrameworks\?>' **/*.csproj | \
sed 's/.*<TargetFrameworks\?>//' | sed 's/<.*//' | \
tr ';' '\n' | sort -u | jq -R . | jq -sc .)
echo "matrix={\"tfm\":$TFMS}" >> "$GITHUB_OUTPUT"
test:
needs:
compute-matrix
strategy:
matrix:
${{
fromJson(needs.compute-matrix.outputs.matrix)
}}
runs-on:
ubuntu-latest
steps:
-
uses:
actions/checkout@v4
-
run:
dotnet
test
--framework
${{
matrix.tfm
}}
```text
---
## Path-Based Triggers
### Selective Workflow Execution
Trigger workflows only when relevant files change. Reduces CI cost and feedback time:
```yaml
on:
push:
branches:
main
paths:
-
'src/**'
-
'tests/**'
-
'*.sln'
-
'Directory.Build.props'
-
'Directory.Packages.props'
-
'.github/workflows/ci.yml'
pull_request:
branches:
main
paths:
-
'src/**'
-
'tests/**'
-
'*.sln'
-
'Directory.Build.props'
-
'Directory.Packages.props'
```xml
### Ignoring Non-Code Changes
Use
`paths-ignore`
to skip builds for documentation-only changes:
```yaml
on:
push:
branches:
main
paths-ignore:
-
'docs/**'
-
'*.md'
-
'LICENSE'
-
'.editorconfig'
```markdown
**Choose
`paths`
or
`paths-ignore`,
not
both.**
When
both
are
specified
on
the
same
event,
`paths-ignore`
is
ignored.
Use
`paths`
(allowlist)
for
focused
workflows;
use
`paths-ignore`
(denylist)
for
broad
workflows.
---
## Concurrency Groups
### Cancelling Duplicate Runs
Prevent wasted CI time by cancelling in-progress runs when new commits are pushed to the same branch or PR:
```yaml
concurrency:
group:
ci-${{
github.ref
}}
cancel-in-progress:
true
```yaml
### Environment-Scoped Concurrency
Prevent parallel deployments to the same environment:
```yaml
concurrency:
group:
deploy-production
cancel-in-progress:
false
# queue, do not cancel deployments
```yaml
Use
`cancel-in-progress:
true
`
for
build/test
(newer
commit
supersedes
older),
but
`cancel-in-progress:
false
`
for
deployments
(do
not
cancel
an
in-progress
deploy).
---
## Environment Protection Rules
### Configuring Environments
```yaml
jobs:
deploy-staging:
runs-on:
ubuntu-latest
environment:
name:
staging
url:
https://staging.example.com
steps:
-
name:
Deploy
to
staging
run:
echo
"Deploying..."
deploy-production:
needs:
deploy-staging
runs-on:
ubuntu-latest
environment:
name:
production
url:
https://example.com
steps:
-
name:
Deploy
to
production
run:
echo
"Deploying..."
```text
Configure
protection
rules
in
GitHub
Settings
>
Environments:
|
Rule
|
Purpose
|
|
----------------------------------
|
----------------------------------------------
|
|
Required
reviewers
|
Manual
approval
before
deployment
|
|
Wait
timer
|
Cooldown
period
(e.g.,
15
minutes)
|
|
Branch
restrictions
|
Only
`main`
or
`release/*`
branches
can
deploy
|
|
Custom
deployment
protection
rules
|
Third-party
integrations
(monitoring
checks)
|
### Environment Secrets
Environments
can
have
their
own
secrets
that
override
repository-level
secrets.
Use
environment-scoped
secrets
for
deployment credentials:
```yaml
jobs:
deploy:
environment:
production
runs-on:
ubuntu-latest
steps:
-
name:
Deploy
env:
# These resolve to environment-specific values
CONNECTION_STRING:
${{
secrets.CONNECTION_STRING
}}
API_KEY:
${{
secrets.API_KEY
}}
run:
./deploy.sh
```text
---
## Caching Strategies
### NuGet Package Cache
```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 }}-
```csharp
The
`restore-keys`
prefix
match
ensures
a
partial
cache
hit
when
csproj
files
change
(most
packages
remain
cached).
### .NET SDK Cache
For self-hosted runners or scenarios where SDK installation is slow:
```yaml
-
name:
Setup
.NET
with
cache
uses:
actions/setup-dotnet@v4
with:
dotnet-version:
'8.0.x'
cache:
true
cache-dependency-path:
'**/packages.lock.json'
```json
The
`cache:
true
`
option
in
`actions/setup-dotnet@v4`
enables
built-in
NuGet
caching
using
`packages.lock.json`
as
the
cache
key.
### Build Output Cache (.NET 9+)
.NET
9 introduced MSBuild build-check caching. For incremental CI builds:
```yaml
-
name:
Cache
build
output
uses:
actions/cache@v4
with:
path:
|
**/bin/
**/obj/
key:
build-${{
runner.os
}}-${{
hashFiles('**/*.csproj',
'**/*.cs'
)
}}
restore-keys:
|
build-${{ runner.os }}-
```csharp
Use
build
output
caching
cautiously
--
stale
caches
can
mask
build
errors.
Prefer
NuGet
caching
as
the
primary
CI
speed
optimization.
---
## `workflow_dispatch` Inputs
### Manual Trigger with Parameters
```yaml
on:
workflow_dispatch:
inputs:
environment:
description:
'Target deployment environment'
required:
true
type:
choice
options:
-
staging
-
production
default:
staging
version:
description:
'Version to deploy (e.g., 1.2.3)'
required:
true
type:
string
dry-run:
description:
'Simulate deployment without applying changes'
required:
false
type:
boolean
default:
false
jobs:
deploy:
runs-on:
ubuntu-latest
environment:
${{
inputs.environment
}}
steps:
-
uses:
actions/checkout@v4
with:
ref:
v${{
inputs.version
}}
-
name:
Deploy
env:
DRY_RUN:
${{
inputs.dry-run
}}
run:
|
set -euo pipefail
if [ "$DRY_RUN" = "true" ]; then
echo "DRY RUN: would deploy v${{ inputs.version }} to ${{ inputs.environment }}"
else
./deploy.sh --version ${{ inputs.version }}
fi
```text
Input types:
`string`,
`boolean`,
`choice`,
`environment`
(selects
from
configured
environments).
---
## Agent Gotchas
1
.
**Do
not
mix
`paths`
and
`paths-ignore`
on
the
same
event**
--
when
both
are
specified,
`paths-ignore`
is
silently
ignored.
Use
one
or
the
other.
2
.
**Set
`fail-fast:
false
`
on
matrix
builds**
--
default
`fail-fast:
true
`
cancels
sibling
jobs
when
one
fails,
hiding
which
other
combinations
also
break.
3
.
**Use
`set
-euo
pipefail`
in
all
bash
steps**
--
without
`pipefail`,
a
non-zero
exit
from
a
piped
command
(e.g.,
`script
|
tee`)
does
not
fail
the
step.
4
.
**Reusable
workflow
inputs
are
strings
by
default**
--
boolean
and
number
types
must
be
explicitly
declared
with
`type:`
in
the
workflow_call
inputs.
5
.
**Cache
keys
must
include
`runner.os`**
--
NuGet
packages
are
OS-dependent;
a
Linux-built
cache
restoring
on
Windows
causes
restore
failures.
6
.
**Do
not
hardcode
TFMs
in
workflow
files**
--
use
matrix
variables
or
extract
from
csproj
to
keep
workflows
in
sync
with
project
configuration.
7
.
**`secrets:
inherit`
passes
all
caller
secrets**
--
use
explicit
secret
declarations
for
security-sensitive
reusable
workflows
to
limit
exposure.
8
.
**Concurrency
groups
for
deploys
must
use
`cancel-in-progress:
false
`**
--
cancelling
an
in-progress
deployment
can
leave
infrastructure
in
an
inconsistent
state.
Code Navigation (Serena MCP)
Primary approach: Use Serena symbol operations for efficient code navigation:
Find definitions: serena_find_symbol instead of text search
Understand structure: serena_get_symbols_overview for file organization
Track references: serena_find_referencing_symbols for impact analysis
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