Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 19 additions & 74 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
@@ -1,107 +1,52 @@
name: Publish project release action

on:
push:
branches: [ main, develop ]
workflow_dispatch:
schedule:
# Weekly full build/publish of both branches. Routine merges only smoke-test; this scheduled run republishes
# everything (also refreshing the Docker base image).
- cron: '0 2 * * MON'

# Real publishes share one global group so they serialize: they push both branches' shared Docker tags/caches and
# releases regardless of ref, so a ref-scoped group could double-push. Non-publishing push runs get a unique per-run
# group so they don't queue behind a real publish.
# A publish is a deliberate dispatch, so runs serialize on one group; queue rather than cancel so a run is never
# left with a half-created GitHub release.
concurrency:
group: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || vars.PUBLISH_ON_MERGE == 'true') && github.workflow || format('{0}-noop-{1}', github.workflow, github.run_id) }}
# Queue instead of cancel: cancelling a publish mid-flight can leave a partially pushed multi-arch tag set or a
# half-created GitHub release.
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:

# Decide which branches to publish and whether to publish at all: push -> only the pushed branch, and only when the
# PUBLISH_ON_MERGE variable is true (default two-phase model: merges don't publish); schedule/dispatch -> both
# branches.
setup:
name: Resolve publish plan job
runs-on: ubuntu-latest
outputs:
branches: ${{ steps.plan.outputs.branches }}
publish: ${{ steps.plan.outputs.publish }}
steps:
- name: Compute publish plan step
id: plan
env:
# Repository variable; unset reads as empty string, so the default is the two-phase model.
PUBLISH_ON_MERGE: ${{ vars.PUBLISH_ON_MERGE }}
run: |
set -euo pipefail
# Schedule/dispatch builds both branches regardless of triggering ref. A dispatch on a non-default ref
# mis-versions the main leg (NBGV can't resolve the public main ref), so fail fast: dispatch from default only.
if [[ "${{ github.event_name }}" == "workflow_dispatch" \
&& "${{ github.ref_name }}" != "${{ github.event.repository.default_branch }}" ]]; then
echo "::error::Dispatch publish-release from the default branch (${{ github.event.repository.default_branch }}); the matrix builds both branches. Re-dispatch on the default branch."
exit 1
fi
case "${{ github.event_name }}" in
push)
branches='["${{ github.ref_name }}"]'
if [[ "${PUBLISH_ON_MERGE:-}" == "true" ]]; then
publish=true
else
publish=false
fi
;;
*)
# schedule / workflow_dispatch
branches='["main","develop"]'
publish=true
;;
esac
echo "Event=${{ github.event_name }} branches=$branches publish=$publish"
echo "branches=$branches" >> "$GITHUB_OUTPUT"
echo "publish=$publish" >> "$GITHUB_OUTPUT"

# Full build + publish of every target per planned branch. The matrix lets one run publish main (Release/latest)
# Publish each planned branch: NBGV computes the tag from the checked-out branch, then a GitHub release is created
# (tag + auto source archive + README + LICENSE). Source-only repo - no package or image targets.
# Publish the dispatched branch (main => release, develop => prerelease): NBGV computes the tag from the ref, then
# a GitHub release is created (tag + auto source archive + README + LICENSE). Source-only repo - no build targets.
publish:
name: Publish project release job
needs: [setup]
if: ${{ needs.setup.outputs.publish == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: write
strategy:
fail-fast: false
matrix:
branch: ${{ fromJSON(needs.setup.outputs.branches) }}
runs-on: ubuntu-latest

steps:

- name: Assert dispatch ref step
run: |
set -euo pipefail
if [ "${{ github.ref_name }}" != "main" ] && [ "${{ github.ref_name }}" != "develop" ]; then
echo "::error::Dispatch publish-release from main (release) or develop (prerelease); got ${{ github.ref_name }}."
exit 1
fi

- name: Setup .NET SDK step
uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0
with:
dotnet-version: 10.x

# Full history so NBGV can compute the git height for the checked-out branch.
# Full history so NBGV can compute the git height for the branch.
- name: Checkout code step
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ matrix.branch }}
ref: ${{ github.ref_name }}
fetch-depth: 0

# nbgv floats on @master (its tag stream lags master). IGNORE_GITHUB_REF versions the checked-out branch, not the
# CI ref, so a dispatch from main still classifies the develop leg as a prerelease.
# NBGV versions the dispatched ref: main is the public-release ref (clean X.Y.Z), develop a prerelease.
- name: Compute version step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: "true"

# The weekly publisher re-runs with no new commits, so the tag may already exist. Skip create on an existing tag
# (no-op republish); a manual dispatch refreshes it.
# Skip create on an existing tag (no-op republish); a re-dispatch refreshes it.
- name: Check for existing release step
id: release-exists
env:
Expand All @@ -124,7 +69,7 @@ jobs:
generate_release_notes: true
tag_name: ${{ steps.nbgv.outputs.SemVer2 }}
target_commitish: ${{ steps.nbgv.outputs.GitCommitId }}
prerelease: ${{ matrix.branch != 'main' }}
prerelease: ${{ github.ref_name != 'main' }}
Comment thread
ptr727 marked this conversation as resolved.
files: |
LICENSE
README.md
Loading