@@ -244,6 +244,16 @@ jobs:
244244 shell : pwsh
245245 run : ./build.ps1 Publish --Runtime "${{ matrix.runtime }}"
246246
247+ - name : Package app
248+ if : needs.resolve-version.outputs.is_release == 'true' && matrix.publish && runner.os != 'Windows'
249+ shell : bash
250+ run : ./build.sh PackageApp --Runtime "${{ matrix.runtime }}" --skip Publish
251+
252+ - name : Package app (Windows)
253+ if : needs.resolve-version.outputs.is_release == 'true' && matrix.publish && runner.os == 'Windows'
254+ shell : pwsh
255+ run : ./build.ps1 PackageApp --Runtime "${{ matrix.runtime }}" --skip Publish
256+
247257 - name : Upload test results
248258 if : always()
249259 uses : actions/upload-artifact@v7
@@ -260,29 +270,34 @@ jobs:
260270 path : artifacts/packages/**
261271 if-no-files-found : error
262272
263- - name : Upload app artifacts
273+ - name : Upload installer artifacts
264274 if : needs.resolve-version.outputs.is_release == 'true' && matrix.publish
265275 uses : actions/upload-artifact@v7
266276 with :
267- name : app -${{ matrix.runtime }}
268- path : artifacts/publish/${{ matrix.runtime }} /**
277+ name : installer -${{ matrix.runtime }}
278+ path : artifacts/installers /**
269279 if-no-files-found : error
270280
271- release-packages :
272- name : Release Packages
281+ release :
282+ name : Release
273283 needs : [resolve-version, build-and-test]
274284 if : needs.resolve-version.outputs.is_release == 'true'
275285 runs-on : ubuntu-latest
276286 timeout-minutes : 15
277287 environment : release
288+ permissions :
289+ contents : write
290+ concurrency :
291+ group : release-tag-${{ needs.resolve-version.outputs.tag }}
292+ cancel-in-progress : false
278293 env :
279294 HAS_NUGET_KEY : ${{ secrets.NUGET_API_KEY != '' }}
280295
281296 steps :
282297 - uses : actions/checkout@v6
283298 with :
284299 ref : ${{ needs.resolve-version.outputs.sha }}
285- sparse-checkout : global.json
300+ fetch-depth : 0
286301
287302 - uses : actions/setup-dotnet@v5
288303 with :
@@ -294,11 +309,17 @@ jobs:
294309 name : packages
295310 path : packages
296311
312+ - name : Download installers
313+ uses : actions/download-artifact@v8
314+ with :
315+ path : installers
316+ pattern : installer-*
317+ merge-multiple : true
318+
297319 - name : Verify release manifest
298320 shell : bash
299321 run : |
300322 set -euo pipefail
301- EXPECTED_VERSION="${{ needs.resolve-version.outputs.full_version }}"
302323 MANIFEST="packages/release-manifest.json"
303324
304325 if [ ! -f "$MANIFEST" ]; then
@@ -365,9 +386,54 @@ jobs:
365386 shell : bash
366387 run : echo "::warning::NUGET_API_KEY not configured. Skipping NuGet push."
367388
389+ - name : Create and push tag
390+ shell : bash
391+ run : |
392+ TAG="${{ needs.resolve-version.outputs.tag }}"
393+ SHA="${{ needs.resolve-version.outputs.sha }}"
394+
395+ git fetch --tags --force
396+ if git rev-parse "$TAG" >/dev/null 2>&1; then
397+ echo "::error::Tag $TAG already exists locally"
398+ exit 1
399+ fi
400+ if git ls-remote --tags origin "refs/tags/$TAG" | grep -q "$TAG"; then
401+ echo "::error::Tag $TAG already exists on remote"
402+ exit 1
403+ fi
404+
405+ git tag "$TAG" "$SHA"
406+ git push origin "$TAG"
407+ echo "Created and pushed tag $TAG at $SHA"
408+
409+ - name : Create GitHub Release
410+ shell : bash
411+ env :
412+ GH_TOKEN : ${{ github.token }}
413+ run : |
414+ TAG="${{ needs.resolve-version.outputs.tag }}"
415+ RELEASE_NAME="dotnet.CI.template $TAG"
416+
417+ shopt -s nullglob
418+ RELEASE_FILES=(installers/*.zip)
419+ if [ ${#RELEASE_FILES[@]} -eq 0 ]; then
420+ echo "::error::No installer zip files found"
421+ exit 1
422+ fi
423+
424+ if gh release view "$TAG" >/dev/null 2>&1; then
425+ echo "::error::Release already exists for tag $TAG"
426+ exit 1
427+ fi
428+
429+ gh release create "$TAG" "${RELEASE_FILES[@]}" \
430+ --title "$RELEASE_NAME" \
431+ --generate-notes
432+ echo "Created release $TAG with ${#RELEASE_FILES[@]} assets"
433+
368434 deploy-docs :
369435 name : Deploy Documentation
370- needs : [resolve-version, release-packages ]
436+ needs : [resolve-version, release]
371437 if : needs.resolve-version.outputs.is_release == 'true'
372438 runs-on : ubuntu-latest
373439 timeout-minutes : 15
@@ -421,102 +487,3 @@ jobs:
421487 if : steps.check-docs.outputs.has_docs == 'true'
422488 id : deployment
423489 uses : actions/deploy-pages@v4
424-
425- create-release :
426- name : Create Release
427- needs : [resolve-version, build-and-test, release-packages, deploy-docs]
428- if : |
429- always() &&
430- needs.release-packages.result == 'success' &&
431- (needs.deploy-docs.result == 'success' || needs.deploy-docs.result == 'skipped')
432- runs-on : ubuntu-latest
433- timeout-minutes : 15
434- permissions :
435- contents : write
436- concurrency :
437- group : release-tag-${{ needs.resolve-version.outputs.tag }}
438- cancel-in-progress : false
439-
440- steps :
441- - uses : actions/checkout@v6
442- with :
443- ref : ${{ needs.resolve-version.outputs.sha }}
444- fetch-depth : 0
445-
446- - name : Create and push tag
447- shell : bash
448- run : |
449- TAG="${{ needs.resolve-version.outputs.tag }}"
450- SHA="${{ needs.resolve-version.outputs.sha }}"
451-
452- git fetch --tags --force
453- if git rev-parse "$TAG" >/dev/null 2>&1; then
454- echo "::error::Tag $TAG already exists locally"
455- exit 1
456- fi
457- if git ls-remote --tags origin "refs/tags/$TAG" | grep -q "$TAG"; then
458- echo "::error::Tag $TAG already exists on remote"
459- exit 1
460- fi
461-
462- git tag "$TAG" "$SHA"
463- git push origin "$TAG"
464- echo "Created and pushed tag $TAG at $SHA"
465-
466- - name : Download packages
467- uses : actions/download-artifact@v8
468- with :
469- name : packages
470- path : release-assets/packages
471-
472- - name : Download app artifacts
473- uses : actions/download-artifact@v8
474- with :
475- path : release-assets/apps
476- pattern : app-*
477-
478- - name : Prepare release assets
479- shell : bash
480- run : |
481- shopt -s nullglob
482- mkdir -p release-assets/final
483-
484- for f in release-assets/packages/*.nupkg release-assets/packages/*.snupkg; do
485- [ -f "$f" ] && cp "$f" release-assets/final/
486- done
487-
488- for dir in release-assets/apps/app-*/; do
489- if [ -d "$dir" ]; then
490- runtime="$(basename "$dir")"
491- (cd "$dir" && zip -r "../../final/${runtime}.zip" .)
492- echo "Zipped $runtime"
493- fi
494- done
495-
496- echo "Release assets:"
497- ls -la release-assets/final/
498-
499- - name : Create GitHub Release
500- shell : bash
501- env :
502- GH_TOKEN : ${{ github.token }}
503- run : |
504- TAG="${{ needs.resolve-version.outputs.tag }}"
505- RELEASE_NAME="dotnet.CI.template $TAG"
506-
507- shopt -s nullglob
508- RELEASE_FILES=(release-assets/final/*)
509- if [ ${#RELEASE_FILES[@]} -eq 0 ]; then
510- echo "::error::No release files found"
511- exit 1
512- fi
513-
514- if gh release view "$TAG" >/dev/null 2>&1; then
515- echo "::error::Release already exists for tag $TAG"
516- exit 1
517- fi
518-
519- gh release create "$TAG" "${RELEASE_FILES[@]}" \
520- --title "$RELEASE_NAME" \
521- --generate-notes
522- echo "Created release $TAG with ${#RELEASE_FILES[@]} assets"
0 commit comments