Skip to content

Commit 0fbf66e

Browse files
committed
Restructure release workflow: package apps in build, merge release jobs
- Add PackageApp NUKE target to zip publish output into installers - Move app packaging into build-and-test job (no redundant builds) - Merge release-packages and create-release into single release job - GitHub Release assets contain only installer zips (not nupkg) - NuGet packages publish to NuGet.org only (skip if no API key) - deploy-docs now depends on release job Made-with: Cursor
1 parent 763b230 commit 0fbf66e

3 files changed

Lines changed: 93 additions & 107 deletions

File tree

.github/workflows/ci.yml

Lines changed: 74 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -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"

build/BuildTask.Parameters.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ partial class BuildTask
3838
AbsolutePath TestResultsDirectory => ArtifactsDirectory / "test-results";
3939
AbsolutePath PackagesDirectory => ArtifactsDirectory / "packages";
4040
AbsolutePath PublishDirectory => ArtifactsDirectory / "publish";
41+
AbsolutePath InstallersDirectory => ArtifactsDirectory / "installers";
4142

4243
AbsolutePath ReleaseManifestFile => PackagesDirectory / "release-manifest.json";
4344
AbsolutePath BuildOutputsMarkerFile => ArtifactsDirectory / ".build-outputs" / "build-outputs.json";
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using Nuke.Common;
3+
using Nuke.Common.IO;
4+
5+
partial class BuildTask
6+
{
7+
Target PackageApp => _ => _
8+
.DependsOn(Publish)
9+
.Requires(() => !string.IsNullOrWhiteSpace(Runtime))
10+
.Executes(() =>
11+
{
12+
InstallersDirectory.CreateOrCleanDirectory();
13+
var sourceDir = PublishDirectory / Runtime;
14+
var zipFile = InstallersDirectory / $"app-{Runtime}.zip";
15+
sourceDir.ZipTo(zipFile);
16+
Console.WriteLine($"Created installer: {zipFile}");
17+
});
18+
}

0 commit comments

Comments
 (0)