This repository contains reusable GitHub Actions workflows for .NET projects.
Update once here β use everywhere.
Automatically formats C# with dotnet format
and commits changes.
Consumer Usage
name: Format
on:
push:
workflow_run:
workflows: [ Create Prerelease, Create Release ]
types: [requested]
workflow_dispatch:
pull_request:
types: [opened, edited, synchronize, reopened]
branches: [ main, develop ]
jobs:
format:
uses: Github Organization Name/shared-workflows/.github/workflows/format.yml@main
with:
dotnet_version: "9.0.x"
secrets:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Builds and tests the solution. Uploads .trx
as artifacts.
Consumer Usage
name:Run Tests
on:
workflow_run:
workflows: [ Create Prerelease, Create Release ]
types: [requested]
workflow_dispatch:
pull_request:
types: [opened, edited, synchronize, reopened]
branches: [ main, develop ]
jobs:
test:
uses: Github Organization Name/shared-workflows/.github/workflows/run_tests.yml@main
with:
dotnet_version: "9.0.x"
solution_name: ${{ vars.SOLUTION_NAME }}
secrets:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Turns uploaded .trx
into a GitHub Checks report.
Consumer Usage
name: Test Report
run-name: "Generate Test Report for ${{ github.event.workflow_run.name }} #${{ github.event.workflow_run.run_number }} on ${{ github.event.workflow_run.head_branch }}"
on:
workflow_run:
workflows: [ "Test" ]
types: [ completed ]
permissions:
contents: read
actions: read
checks: write
jobs:
report:
uses: Github Organization Name/shared-workflows/.github/workflows/test_report.yml@main
with:
artifact_name: "test-results"
test_report_name: "Unit Tests"
path: "*.trx"
Creates a branch when issues/PRs are opened or assigned.
Consumer Usage
name: Issue Branch
on:
issues: { types: [ opened, assigned ] }
issue_comment: { types: [ created ] }
pull_request: { types: [ opened, closed ] }
jobs:
create_issue_branch_job:
uses: Github Organization Name/shared-workflows/.github/workflows/issue_branch.yml@main
secrets:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Computes & sets the version via Nerdbank.GitVersioning and pushes version.json
.
Guarantees the version always increases and the tag = v<NuGetPackageVersion> is unique (auto-bumps if needed).
Reusable: .github/workflows/set_version.yml
Inputs: target_branch
, mode
(auto|bump|explicit
), optional version
, increment
, prerelease
Outputs: tag
, new_simple
, new_prerelease
, new_nuget
Consumer Usage
jobs:
set-version:
uses: Github Organization Name/shared-workflows/.github/workflows/set_version.yml@main
with:
target_branch: ${{ github.ref_name }}
mode: auto
version: ""
increment: patch
prerelease: ""
secrets:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Creates/updates a draft GitHub Release for the provided tag.
Builds notes from CHANGELOG.md
(falls back to commit list + compare link).
Reusable: .github/workflows/prepare_release.yml
Inputs: target_branch
, tag
, optional prerelease
, draft
(default true)
Consumer Usage
jobs:
prepare-release:
needs: set-version
uses: Github Organization Name/shared-workflows/.github/workflows/prepare_release.yml@main
with:
target_branch: ${{ github.ref_name }}
tag: ${{ needs.set-version.outputs.tag }}
prerelease: ${{ needs.set-version.outputs.new_prerelease }}
draft: true
secrets:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Restores, builds, tests, then packs and pushes to NuGet.
For stable builds, sets PublicRelease=true
.
Reusable: .github/workflows/pack_and_publish.yml
Inputs: build_configuration
(Release|Debug
)
Consumer Usage (triggered on Release published)
name: Publish
on:
release:
types: [ published ]
permissions:
contents: write
pull-requests: write
packages: write
jobs:
set-config:
uses: Github Organization Name/shared-workflows/.github/workflows/determine_build_configuration.yml@main
with:
trigger: release
target_branch: ${{ github.event.release.target_commitish }}
override_build_configuration: ''
prerelease: ${{ github.event.release.prerelease }}
publish:
needs: set-config
uses: Github Organization Name/shared-workflows/.github/workflows/dotnet_pack.yml@main
with:
build_configuration: ${{ needs.set-config.outputs.build_configuration }}
secrets:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
Resolves Release
vs Debug
for downstream jobs.
Release events β prerelease=false
β Release
, else Debug
.
Manual runs can pass an override.
Reusable: .github/workflows/determine_build_configuration.yml
Inputs: trigger
, target_branch
, override_build_configuration
, prerelease
Outputs: build_configuration
Consumer Usage (example for manual CI)
jobs:
set-config:
uses: Github Organization Name/shared-workflows/.github/workflows/determine_build_configuration.yml@main
with:
trigger: workflow_dispatch
target_branch: ${{ github.ref_name }}
override_build_configuration: 'Debug'
prerelease: false
-
Repository variable
SOLUTION_NAME
β e.g.,MyProject.sln
-
Versioning:
version.json
- Root
version.json
managed by NBGV (Nerdbank GitVersioning) (baseline rules in your repo).
- Root
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
"version": "1.0.0",
"publicReleaseRefSpec": [
"^refs/heads/main$",
"^refs/heads/hotfix$",
"^refs/heads/v\\d+\\.\\d+$"
]
}
- MSBuild props (at repo root)
- File must be named
Directory.Build.props
. - Minimal recommended content:
- File must be named
<Project>
<!-- Shared package refs -->
<ItemGroup>
<!-- NBGV drives versions; PrivateAssets=all keeps it out of consumers -->
<PackageReference Include="Nerdbank.GitVersioning" Version="3.8.38-alpha" PrivateAssets="all" />
<!-- SourceLink for GitHub -->
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<!-- SourceLink / build hygiene -->
<PropertyGroup>
<!-- Deterministic builds + embed sources for better debugging -->
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
<Deterministic>true</Deterministic>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
</PropertyGroup>
<!-- Package metadata applied only to packable projects -->
<PropertyGroup Condition="'$(IsPackable)' == 'true'">
<!-- NuGet README -->
<PackageReadmeFile>README.md</PackageReadmeFile>
<!-- NuGet Release Notes link -->
<PackageReleaseNotes>https://github.com/Stillpoint-Software/Hyperbee.XS/releases/latest</PackageReleaseNotes>
<!-- Repository metadata (shows on NuGet) -->
<RepositoryUrl>https://github.com/Stillpoint-Software/Hyperbee</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageProjectUrl>https://github.com/Stillpoint-Software/Hyperbee</PackageProjectUrl>
</PropertyGroup>
<!-- Pull the root README into the package root -->
<ItemGroup Condition="'$(IsPackable)' == 'true'">
<None Include="$(MSBuildThisFileDirectory)README.md"
Pack="true"
PackagePath="\"
Link="README.md" />
</ItemGroup>
</Project>
- Use
${{ secrets.GITHUB_TOKEN }}
as GH_TOKEN in consumers. set_version.yml
pushesversion.json
. Ensure branch protections allow workflow pushes (or switch it to open a PR).- Tag is always
v<NuGetPackageVersion>
. Releases are created as draft by default. - For prereleases (develop/hotfix), Nerdbank.GitVersioning baseline is
-alpha
;main
is always stable. - NuGet push uses
--skip-duplicate
to keep reruns green.