-
Notifications
You must be signed in to change notification settings - Fork 6
188 lines (168 loc) · 6.75 KB
/
Copy pathrelease.yml
File metadata and controls
188 lines (168 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
name: Package Release
# Generic release workflow for the Codout.Framework packages, one package at a
# time. Mapping from short name to .csproj lives in .github/release-packages.json.
#
# Trigger by pushing a tag in the form "<short>-v<version>", e.g. "ef-v6.3.0",
# "mongo-v6.2.3", "mailer-razor-v6.2.2". The Codout.Framework.Mcp package keeps
# its own dedicated workflow (mcp-release.yml), so "mcp-v*" tags are excluded
# here to avoid a double release.
#
# workflow_dispatch builds and packs without publishing, useful for smoke-
# testing a package locally before tagging.
on:
push:
tags:
- '*-v*.*.*'
- '!mcp-v*'
workflow_dispatch:
inputs:
package:
description: 'Package short name (see .github/release-packages.json).'
type: string
required: true
version:
description: 'Optional version override (e.g. 6.3.1). Leave empty to use the <Version> from the .csproj.'
required: false
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
CONFIGURATION: Release
MAPPING: .github/release-packages.json
jobs:
build-pack:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
package: ${{ steps.resolve.outputs.package }}
project: ${{ steps.resolve.outputs.project }}
version: ${{ steps.resolve.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
# Full history so the master-ancestry gate can resolve merge-base.
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
- name: Verify tag is on master
if: startsWith(github.ref, 'refs/tags/')
run: |
set -euo pipefail
git fetch origin master --quiet
if ! git merge-base --is-ancestor HEAD origin/master; then
echo "::error::Tag '${GITHUB_REF_NAME}' is not an ancestor of origin/master."
echo "Releases must be cut from commits that have been merged into master."
exit 1
fi
echo "Tag '${GITHUB_REF_NAME}' is on master: OK"
- name: Resolve package and version
id: resolve
run: |
set -euo pipefail
if [ -n "${{ github.event.inputs.package }}" ]; then
PKG="${{ github.event.inputs.package }}"
VERSION="${{ github.event.inputs.version }}"
else
TAG="${GITHUB_REF#refs/tags/}"
PKG="${TAG%-v*}"
VERSION="${TAG##*-v}"
fi
PROJECT=$(jq -r --arg p "$PKG" '.[$p] // empty' "$MAPPING")
if [ -z "$PROJECT" ]; then
echo "::error::Unknown package '$PKG'."
echo "Known packages:"
jq -r 'keys[]' "$MAPPING" | sed 's/^/ - /'
exit 1
fi
if [ ! -f "$PROJECT" ]; then
echo "::error::Mapped project not found on disk: $PROJECT"
exit 1
fi
echo "package=$PKG" | tee -a "$GITHUB_OUTPUT"
echo "project=$PROJECT" | tee -a "$GITHUB_OUTPUT"
echo "version=$VERSION" | tee -a "$GITHUB_OUTPUT"
# Build + test the whole solution as a safety net. The solution currently
# has no tests registered in it (tests live in side projects with external
# infra dependencies, see appsettings.json), so `dotnet test` here is a
# no-op today and will pick up tests automatically once they are added.
- name: Restore (solution)
run: dotnet restore Codout.Framework.sln
- name: Build (solution)
run: dotnet build Codout.Framework.sln --configuration "$CONFIGURATION" --no-restore
- name: Test (solution)
run: dotnet test Codout.Framework.sln --configuration "$CONFIGURATION" --no-build --verbosity normal
- name: Build (target project)
run: |
# Build the target project explicitly with --verbosity normal. The
# solution build above does not cover out-of-solution packages
# (Cosmos, DocumentDB, etc.) and may leave the target unbuilt anyway,
# so we build it here and pack with --no-build below. Splitting
# build and pack also keeps build errors visible — relying on
# `dotnet pack`'s implicit build can silently swallow failures (see
# the api-dto NU5026 incident that motivated this pattern in
# mass-release.yml).
dotnet build "${{ steps.resolve.outputs.project }}" \
--configuration "$CONFIGURATION" \
--verbosity normal
- name: Pack
run: |
set -euo pipefail
VERSION="${{ steps.resolve.outputs.version }}"
PROJECT="${{ steps.resolve.outputs.project }}"
# IMPORTANT: when overriding the package version via workflow_dispatch,
# use ONLY -p:PackageVersion=. Passing -p:Version= cascades to every
# project in the build graph (including ProjectReferences), which
# silently rewrites dependency versions in the generated .nuspec and
# produces broken packages. -p:PackageVersion only affects the
# outgoing package and leaves ProjectReference resolution alone.
if [ -n "$VERSION" ]; then
dotnet pack "$PROJECT" --configuration "$CONFIGURATION" --no-build \
-p:PackageVersion="$VERSION" \
--output ./artifacts
else
dotnet pack "$PROJECT" --configuration "$CONFIGURATION" --no-build \
--output ./artifacts
fi
ls -la ./artifacts
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: ${{ steps.resolve.outputs.package }}-nupkg
path: |
./artifacts/*.nupkg
./artifacts/*.snupkg
if-no-files-found: error
publish:
needs: build-pack
runs-on: ubuntu-latest
# Only push to NuGet for real release tags. workflow_dispatch (manual) runs
# are build/pack-only smoke tests.
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: read
steps:
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
- name: Download artifacts
uses: actions/download-artifact@v8
with:
name: ${{ needs.build-pack.outputs.package }}-nupkg
path: ./artifacts
- name: Push to NuGet.org
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
set -euo pipefail
if [ -z "${NUGET_API_KEY:-}" ]; then
echo "::error::NUGET_API_KEY secret is not set; aborting."
exit 1
fi
dotnet nuget push "./artifacts/*.nupkg" \
--api-key "$NUGET_API_KEY" \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate