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
83 changes: 40 additions & 43 deletions .github/workflows/Publish.yml
Original file line number Diff line number Diff line change
@@ -1,54 +1,40 @@
name: Publish
name: Publish NuGet Package
# This job builds and publishes the package to NuGet.
# It depends on the included tests job to complete successfully.
# The version number is determined by the existing tag provided
# when manually triggering the workflow.
# The tag is not limited to a certain branch.
# This workflow finds the most recent tag that starts with
# the selected major version (sorted by creatordate)
# and runs the test, build and publish tasks for that tag.
on:
workflow_dispatch:
inputs:
version_tag:
description: 'Enter an existing version tag to publish (e.g., "v5.1.0" or "v6.0.0-pre.1")'
required: true
type: string

inputs:
major_version:
description: 'Select the major version to publish (tag prefix). The workflow will pick the most recent tag that starts with this value (e.g. v3 -> v3.2.1).'
required: true
type: choice
options:
- v3
# - v4
jobs:
tests:
runs-on: ubuntu-22.04
# ubuntu-latest = ubuntu-24.04 does not include mono needed for tests (2025-08-01)
runs-on: ubuntu-22.04 # ubuntu-24.04 does not include mono needed for net4x tests
outputs:
VERSION: ${{ steps.set_version.outputs.VERSION }}
VERSION: ${{ steps.resolve.outputs.VERSION }}
TAG_NAME: ${{ steps.resolve.outputs.TAG_NAME }}
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # Fetch all history for all tags and branches

- name: Verify tag exists
run: |
git fetch --tags --quiet
if ! git rev-parse "${{ inputs.version_tag }}" >/dev/null 2>&1; then
echo "::error::Tag '${{ inputs.version_tag }}' does not exist."
echo "Available tags:"
git tag -l
exit 1
fi

- name: Checkout tag
uses: actions/checkout@v5
with:
fetch-depth: 0 # Fetch all history for all tags and branches
ref: ${{ inputs.version_tag }}

- name: Set VERSION output
id: set_version
- name: Show matching major version tags and select latest by creatordate
id: resolve
shell: bash
run: |
Version="${{ inputs.version_tag }}"
# Strip 'v' prefix for VERSION variable
Version="${Version#v}"
echo "VERSION=$Version" >> $GITHUB_ENV
echo "VERSION=$Version" >> $GITHUB_OUTPUT
echo "Version: $Version"
set -euo pipefail
# Call the script to resolve the latest tag for the requested major version.
# Script writes TAG_NAME and VERSION to $GITHUB_OUTPUT and $GITHUB_ENV when run on Actions.
chmod +x .github/workflows/PublishResolveVersion.sh
.github/workflows/PublishResolveVersion.sh "${{ github.event.inputs.major_version }}"

- name: Set Git config for line endings
run: git config --global core.autocrlf true
Expand All @@ -57,12 +43,20 @@ jobs:
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
10.0.x
8.0.x
6.0.x
3.1.x

- name: Checkout tag
uses: actions/checkout@v5
with:
fetch-depth: 0 # Fetch all history for all tags and branches
ref: ${{ steps.resolve.outputs.TAG_NAME }}

- name: Remove Demo
run: dotnet sln ./src/SmartFormat.sln remove ./src/Demo/Demo.csproj

- name: Restore dependencies
run: dotnet restore ./src/SmartFormat.sln

Expand All @@ -73,15 +67,16 @@ jobs:
run: dotnet test ./src/SmartFormat.sln --no-build --configuration Release --verbosity quiet

publish:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
needs: tests

steps:
- name: Checkout tag
uses: actions/checkout@v5
with:
fetch-depth: 0 # Fetch all history for all tags and branches
ref: ${{ inputs.version_tag }}
# Reuse the tag name from tests job
ref: ${{ needs.tests.outputs.TAG_NAME }}

- name: Set Git config for line endings
run: git config --global core.autocrlf true
Expand All @@ -90,7 +85,7 @@ jobs:
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
8.0.x
10.0.x

- name: Use verified version
run: |
Expand All @@ -112,7 +107,7 @@ jobs:

- name: Build and pack for publishing
run: |
# For version e.g. "5.1.0-pre.1", the FileVersion will be "5.1.0" and the AssemblyVersion will be "5.0.0"
# For version e.g. "3.1.0-pre.1", the FileVersion will be "3.1.0" and the AssemblyVersion will be "3.0.0"
# AssemblyVersion must only change for major releases
dotnet build ./src/SmartFormat.Deploy.sln --configuration Release \
-p:Version=${{env.VERSION}} \
Expand All @@ -134,14 +129,16 @@ jobs:
- name: Store artifacts
uses: actions/upload-artifact@v4
with:
name: nuget-packages_${{env.VERSION}}.${{github.run_number}}
name: SmartFormat-Packages_${{env.VERSION}}.${{github.run_number}}
path: |
${{ github.workspace }}/artifacts/

- name: Push package to NuGet
# Does not fail, if the package already exists
# Note: Symbol packages get uploaded automatically with the main package
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
for pkg in ${{ github.workspace }}/artifacts/*.nupkg; do
dotnet nuget push "$pkg" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
dotnet nuget push "$pkg" --source https://api.nuget.org/v3/index.json --api-key "$NUGET_API_KEY" --skip-duplicate
done
52 changes: 52 additions & 0 deletions .github/workflows/PublishResolveVersion.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# Enable strict mode when running inside GitHub Actions runner
if [ "${GITHUB_ACTIONS:-false}" = "true" ]; then
set -euo pipefail
fi

Major="${1:-}"
if [ -z "$Major" ]; then
echo "::error::No major version argument supplied. Usage: $0 <major> (e.g. v3)" >&2
exit 1
fi
echo "Looking for tags that start with: $Major"

# Fetch tags
git fetch --tags --quiet

# Collect matching tags (newest first by creatordate)
mapfile -t MATCHING < <(
git for-each-ref --sort=-creatordate --format='%(refname:short)' refs/tags \
| grep -E "^${Major}(\.|$)" || true
)

if [ ${#MATCHING[@]} -eq 0 ]; then
echo "::error::No tag found starting with '${Major}'. Showing latest tags:"
git for-each-ref --sort=-creatordate --format='%(refname:short)' refs/tags | head -n 10
exit 1
fi

echo "Showing up to 10 of top ${#MATCHING[@]} matching tags (newest first):"
for tag in "${MATCHING[@]:0:10}"; do
echo " - $tag"
done

Tag="${MATCHING[0]}"
Version="${Tag#v}"

echo "Selected tag: $Tag -> version: $Version"

# If running in GitHub Actions, write to the runner files
if [ -n "${GITHUB_OUTPUT-}" ]; then
printf 'TAG_NAME=%s\n' "$Tag" >> "$GITHUB_OUTPUT"
printf 'VERSION=%s\n' "$Version" >> "$GITHUB_OUTPUT"
fi

if [ -n "${GITHUB_ENV-}" ]; then
printf 'TAG_NAME=%s\n' "$Tag" >> "$GITHUB_ENV"
printf 'VERSION=%s\n' "$Version" >> "$GITHUB_ENV"
fi

# Always print results
printf 'TAG_NAME=%s\n' "$Tag"
printf 'VERSION=%s\n' "$Version"