-
Notifications
You must be signed in to change notification settings - Fork 0
351 lines (310 loc) Β· 12.5 KB
/
Copy pathpublish-nuget.yml
File metadata and controls
351 lines (310 loc) Β· 12.5 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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
name: Publish to NuGet
# This workflow publishes 8 provider packages to NuGet.org
# Each provider package includes the core MultiLock framework embedded within it
# Users only need to install one provider package (e.g., MultiLock.Redis)
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version to publish (e.g., 1.0.0). Leave empty to use MinVer from current commit.'
required: false
type: string
dry_run:
description: 'Dry run - build and validate packages without publishing'
required: false
type: boolean
default: false
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for MinVer to calculate version from git history
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Install dotnet-validate tool
run: dotnet tool install -g dotnet-validate
- name: Restore dependencies
run: dotnet restore
- name: Build solution
run: dotnet build --configuration Release --no-restore
- name: Start Docker Compose services and wait for health
run: docker compose up -d --wait
working-directory: ./tests
- name: Run all tests
run: dotnet test --configuration Release --no-build --verbosity normal --blame-hang-timeout 150s --logger "trx;LogFileName=test-results.trx" --collect:"XPlat Code Coverage"
timeout-minutes: 10
- name: Upload coverage to CodeCov
uses: codecov/codecov-action@v4
if: always()
with:
files: '**/TestResults/**/coverage.cobertura.xml'
fail_ci_if_error: false
verbose: true
- name: Stop Docker Compose services
if: always()
run: docker compose down
working-directory: ./tests
- name: Pack NuGet packages
run: dotnet pack --configuration Release --no-build --output ./artifacts
env:
# Override version if provided via workflow_dispatch
MinVerVersion: ${{ inputs.version }}
- name: Display package information
run: |
echo "π¦ Packages created:"
ls -lh ./artifacts/*.nupkg
echo ""
echo "π Publishing plan:"
echo " β
Provider packages (will be published):"
for pkg in ./artifacts/*.nupkg; do
pkg_name=$(basename "$pkg")
if [[ "$pkg_name" =~ \.(AzureBlobStorage|Consul|FileSystem|InMemory|PostgreSQL|Redis|SqlServer|ZooKeeper)\. ]]; then
echo " - $pkg_name"
fi
done
echo ""
echo " βοΈ Core package (will be skipped - embedded in providers):"
for pkg in ./artifacts/*.nupkg; do
pkg_name=$(basename "$pkg")
if [[ "$pkg_name" =~ ^MultiLock\.[0-9] ]] || [[ "$pkg_name" == "MultiLock."*".nupkg" && ! "$pkg_name" =~ \.(AzureBlobStorage|Consul|FileSystem|InMemory|PostgreSQL|Redis|SqlServer|ZooKeeper)\. ]]; then
echo " - $pkg_name"
fi
done
echo ""
echo "π Package details:"
for pkg in ./artifacts/*.nupkg; do
pkg_name=$(basename "$pkg")
# Only show details for provider packages
if [[ "$pkg_name" =~ \.(AzureBlobStorage|Consul|FileSystem|InMemory|PostgreSQL|Redis|SqlServer|ZooKeeper)\. ]]; then
echo "----------------------------------------"
echo "Package: $pkg_name"
unzip -l "$pkg" | grep -E '\.dll$|\.xml$|README|LICENSE' || true
fi
done
- name: Validate packages
run: |
echo "π Validating NuGet packages..."
for pkg in ./artifacts/*.nupkg; do
echo "Validating $(basename $pkg)..."
dotnet validate package local "$pkg" || exit 1
done
echo "β
All packages validated successfully"
- name: Check for required package metadata
run: |
echo "π Checking package metadata..."
for pkg in ./artifacts/*.nupkg; do
echo "Checking $(basename $pkg)..."
# Extract nuspec and check for required fields
unzip -q -o "$pkg" -d temp_extract
if [ -f temp_extract/*.nuspec ]; then
nuspec_file=$(find temp_extract -name "*.nuspec" | head -n 1)
# Check for required metadata
if ! grep -q "<license" "$nuspec_file"; then
echo "β Missing license information in $(basename $pkg)"
exit 1
fi
if ! grep -q "<repository" "$nuspec_file"; then
echo "β οΈ Warning: Missing repository information in $(basename $pkg)"
fi
echo "β
Metadata check passed for $(basename $pkg)"
fi
rm -rf temp_extract
done
- name: Upload packages as artifacts
uses: actions/upload-artifact@v4
with:
name: nuget-packages
path: ./artifacts/*.nupkg
retention-days: 30
- name: Upload symbol packages as artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: symbol-packages
path: ./artifacts/*.snupkg
retention-days: 30
- name: Push to NuGet.org
if: ${{ !inputs.dry_run }}
run: |
echo "π€ Publishing packages to NuGet.org..."
echo ""
echo "βΉοΈ Note: Excluding MultiLock.*.nupkg (core package is embedded in provider packages)"
echo ""
# Publish only provider packages (exclude the standalone MultiLock package)
for pkg in ./artifacts/*.nupkg; do
pkg_name=$(basename "$pkg")
# Skip the core MultiLock package (it's embedded in provider packages)
if [[ "$pkg_name" =~ ^MultiLock\.[0-9] ]] || [[ "$pkg_name" == "MultiLock."*".nupkg" && ! "$pkg_name" =~ \.(AzureBlobStorage|Consul|FileSystem|InMemory|PostgreSQL|Redis|SqlServer|ZooKeeper)\. ]]; then
echo "βοΈ Skipping $pkg_name (core package - embedded in providers)"
continue
fi
echo "π¦ Publishing $pkg_name..."
dotnet nuget push "$pkg" \
--api-key ${{ secrets.NUGET_API_KEY }} \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate \
--no-symbols
done
echo ""
echo "β
All provider packages published successfully"
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
- name: Push symbol packages to NuGet.org
if: ${{ !inputs.dry_run }}
run: |
if ls ./artifacts/*.snupkg 1> /dev/null 2>&1; then
echo "π€ Publishing symbol packages to NuGet.org..."
echo ""
echo "βΉοΈ Note: Excluding MultiLock.*.snupkg (core package is embedded in provider packages)"
echo ""
for pkg in ./artifacts/*.snupkg; do
pkg_name=$(basename "$pkg")
# Skip the core MultiLock symbol package (it's embedded in provider packages)
if [[ "$pkg_name" =~ ^MultiLock\.[0-9] ]] || [[ "$pkg_name" == "MultiLock."*".snupkg" && ! "$pkg_name" =~ \.(AzureBlobStorage|Consul|FileSystem|InMemory|PostgreSQL|Redis|SqlServer|ZooKeeper)\. ]]; then
echo "βοΈ Skipping $pkg_name (core package - embedded in providers)"
continue
fi
echo "π¦ Publishing $pkg_name..."
dotnet nuget push "$pkg" \
--api-key ${{ secrets.NUGET_API_KEY }} \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate
done
echo ""
echo "β
All provider symbol packages published successfully"
else
echo "βΉοΈ No symbol packages found to publish"
fi
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
- name: Extract version from tag
if: startsWith(github.ref, 'refs/tags/v')
id: get_version
run: |
VERSION=${GITHUB_REF#refs/tags/v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "π Version: $VERSION"
- name: Publish Release with Release Drafter
if: startsWith(github.ref, 'refs/tags/v') && !inputs.dry_run
id: release_drafter
uses: release-drafter/release-drafter@v6
with:
config-name: release-drafter.yml
version: ${{ steps.get_version.outputs.version }}
tag: ${{ github.ref_name }}
publish: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload packages to GitHub Release
if: startsWith(github.ref, 'refs/tags/v') && !inputs.dry_run
uses: softprops/action-gh-release@v2
with:
files: |
./artifacts/*.nupkg
./artifacts/*.snupkg
fail_on_unmatched_files: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update CHANGELOG.md
if: startsWith(github.ref, 'refs/tags/v') && !inputs.dry_run
run: |
echo "π Updating CHANGELOG.md..."
# Get the release notes from the published release
RELEASE_NOTES=$(gh release view ${{ github.ref_name }} --json body -q .body)
# Create or update CHANGELOG.md
if [ -f CHANGELOG.md ]; then
# Find the first ## heading (first release entry) and preserve everything after it
# This is more robust than counting lines
if grep -q "^## \[" CHANGELOG.md; then
# Extract header (everything before first ## heading)
HEADER=$(sed -n '1,/^## \[/p' CHANGELOG.md | sed '$d')
# Extract existing releases (everything from first ## heading onwards)
EXISTING_RELEASES=$(sed -n '/^## \[/,$p' CHANGELOG.md)
# Rebuild CHANGELOG with new release inserted
{
echo "$HEADER"
echo "## [${{ steps.get_version.outputs.version }}] - $(date +%Y-%m-%d)"
echo ""
echo "$RELEASE_NOTES"
echo ""
echo "$EXISTING_RELEASES"
} > CHANGELOG.md.new
else
# No existing releases, just append after header
{
cat CHANGELOG.md
echo ""
echo "## [${{ steps.get_version.outputs.version }}] - $(date +%Y-%m-%d)"
echo ""
echo "$RELEASE_NOTES"
} > CHANGELOG.md.new
fi
mv CHANGELOG.md.new CHANGELOG.md
else
# Create new CHANGELOG.md
{
echo "# Changelog"
echo ""
echo "All notable changes to this project will be documented in this file."
echo ""
echo "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),"
echo "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)."
echo ""
echo "## [${{ steps.get_version.outputs.version }}] - $(date +%Y-%m-%d)"
echo ""
echo "$RELEASE_NOTES"
} > CHANGELOG.md
fi
echo "β
CHANGELOG.md updated"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit and push CHANGELOG.md
if: startsWith(github.ref, 'refs/tags/v') && !inputs.dry_run
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add CHANGELOG.md
if git diff --staged --quiet; then
echo "βΉοΈ No changes to CHANGELOG.md"
else
git commit -m "chore: update CHANGELOG.md for v${{ steps.get_version.outputs.version }} [skip ci]"
git push origin HEAD:main
echo "β
CHANGELOG.md committed and pushed"
fi
- name: Dry run summary
if: inputs.dry_run
run: |
echo "π DRY RUN COMPLETED"
echo "===================="
echo "β
Packages built successfully"
echo "β
Packages validated successfully"
echo "β
Tests passed"
echo ""
echo "βΉοΈ Packages were NOT published to NuGet.org (dry run mode)"
echo ""
echo "π¦ Packages that would be published:"
ls -1 ./artifacts/*.nupkg | xargs -n1 basename
- name: Summary
if: ${{ !inputs.dry_run && !failure() }}
run: |
echo "π PUBLISH COMPLETED SUCCESSFULLY"
echo "=================================="
echo "β
All packages published to NuGet.org"
echo "β
GitHub release created"
echo ""
echo "π¦ Published packages:"
ls -1 ./artifacts/*.nupkg | xargs -n1 basename
echo ""
echo "π View packages at: https://www.nuget.org/profiles/steingran"