Skip to content

refactor: extract an OpenSegment helper in SplitIntoSegments (#35) #7

refactor: extract an OpenSegment helper in SplitIntoSegments (#35)

refactor: extract an OpenSegment helper in SplitIntoSegments (#35) #7

Workflow file for this run

name: Publish NuGet
on:
push:
# Fire on ALL tag pushes so the format guard (below) catches mistakes
# like `v0.1.0-alpha` loudly instead of silently no-op-ing.
tags:
- '*'
permissions:
contents: write
id-token: write # Required for NuGet trusted publishing (OIDC token exchange).
jobs:
publish-nuget:
name: publish-nuget
runs-on: ubuntu-latest
environment: nuget # Must match the environment named in the nuget.org Trusted Publisher policy.
steps:
- name: "Assert tag is a bare version number"
shell: bash
run: |
# ShellSyntaxTree convention: tags are SemVer version numbers WITHOUT
# a leading 'v'. E.g., `0.1.0-alpha`, NOT `v0.1.0-alpha`. The tag is
# the package version verbatim.
TAG="${GITHUB_REF_NAME}"
if [[ "$TAG" == v* ]]; then
echo "::error::Tag '$TAG' starts with 'v'. ShellSyntaxTree tags must be bare SemVer version numbers (e.g., '0.1.0-alpha', not 'v0.1.0-alpha'). Delete this tag and retag without the leading 'v'."
exit 1
fi
if ! [[ "$TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$ ]]; then
echo "::error::Tag '$TAG' is not a valid SemVer version. Expected '<major>.<minor>.<patch>' or '<major>.<minor>.<patch>-<prerelease>' (e.g., '1.0.0' or '0.2.0-beta.1')."
exit 1
fi
echo "PACKAGE_VERSION=${TAG}" >> "$GITHUB_ENV"
echo "Tag '$TAG' is a valid bare version. Publishing package version: ${TAG}"
- name: "Checkout"
uses: actions/checkout@v6.0.2
with:
lfs: true
fetch-depth: 0
- name: "Install .NET SDK"
uses: actions/setup-dotnet@v5.1.0
with:
global-json-file: "./global.json"
- name: "Restore .NET tools"
run: dotnet tool restore
- name: "dotnet pack"
run: dotnet pack /p:PackageVersion=${{ env.PACKAGE_VERSION }} -c Release -o ./output
- name: "NuGet login (OIDC)"
# Exchanges the workflow's OIDC token for a short-lived NuGet API key
# under the Trusted Publisher policy configured on nuget.org.
# Requires:
# - permissions.id-token: write at the workflow level (above)
# - environment: nuget on this job (matches the policy)
# - NUGET_USER repo secret = the package owner's nuget.org username
# See https://learn.microsoft.com/en-us/nuget/nuget-org/trusted-publishing
uses: NuGet/login@v1
id: nuget-login
with:
user: ${{ secrets.NUGET_USER }}
- name: "dotnet nuget push"
run: |
dotnet nuget push "output/*.nupkg" \
--api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }} \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate
dotnet nuget push "output/*.snupkg" \
--api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }} \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate
- name: "Extract latest release notes"
shell: pwsh
run: |
# RELEASE_NOTES.md uses `#### X.Y.Z[-suffix] <date> ####` per-section
# headings. Capture only the BODY of the first section (no heading)
# so the GitHub release page doesn't duplicate the version string in
# both the title and the first line of the body, and so a stale
# hand-typed date in the heading doesn't fight the published date
# GitHub renders automatically.
if (-not (Test-Path RELEASE_NOTES.md)) {
"No release notes available." | Set-Content RELEASE_NOTES_LATEST.md
exit 0
}
$content = Get-Content RELEASE_NOTES.md -Raw
if ($content -match '(?s)####[^\r\n]*\r?\n+(.+?)(?=\r?\n####|\z)') {
$Matches[1].Trim() | Set-Content RELEASE_NOTES_LATEST.md
} else {
$content | Set-Content RELEASE_NOTES_LATEST.md
}
- name: "Create GitHub release"
uses: softprops/action-gh-release@v2
with:
name: "ShellSyntaxTree ${{ github.ref_name }}"
tag_name: ${{ github.ref_name }}
body_path: RELEASE_NOTES_LATEST.md
files: |
output/*.nupkg
output/*.snupkg
draft: false
prerelease: ${{ contains(github.ref_name, '-') }}
env:
GITHUB_TOKEN: ${{ github.token }}