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
85 changes: 85 additions & 0 deletions .github/workflows/nuget-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Publish to NuGet.org

# The single publishing workflow: nuget.org's Trusted Publishing policy pins
# one workflow file, so every path to a publish goes through this one.
#
# - Runs automatically when a Release workflow run completes successfully
# (a tag-triggered run's head branch is the tag).
# - Runs manually for an existing release tag -- one cut before the policy
# existed, or a retry.
#
# No long-lived API key anywhere: the job exchanges a GitHub OIDC token for
# a one-hour key via NuGet/login, and --skip-duplicate keeps re-runs
# idempotent.

on:
workflow_run:
workflows: ["Release"]
types: [completed]
workflow_dispatch:
inputs:
tag:
description: "Release tag whose packages to publish (e.g. v0.6.0)"
required: true

permissions:
contents: read
id-token: write

jobs:
push:
name: Push release packages
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
steps:
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.4xx"

- name: Resolve the release tag
id: tag
env:
DISPATCH_TAG: ${{ inputs.tag }}
RUN_TAG: ${{ github.event.workflow_run.head_branch }}
run: |
set -euo pipefail
TAG="${DISPATCH_TAG:-$RUN_TAG}"
case "$TAG" in
v*) echo "tag=$TAG" >> "$GITHUB_OUTPUT" ;;
*)
echo "::error::'$TAG' is not a release tag."
exit 1
;;
esac

- name: Download packages from the release
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
gh release download "${{ steps.tag.outputs.tag }}" \
--repo "${{ github.repository }}" \
--pattern '*.nupkg' \
--dir packages
ls -la packages

- name: Exchange the OIDC token for a one-hour API key
id: login
uses: NuGet/login@v1
with:
# The nuget.org profile that owns the packages. Public on the
# package pages, so not a secret; the trusted-publishing policy is
# what gates publishing, not this name.
user: ademar

- name: Push to NuGet.org
env:
NUGET_API_KEY: ${{ steps.login.outputs.NUGET_API_KEY }}
run: |
set -euo pipefail
for pkg in packages/*.nupkg; do
dotnet nuget push "$pkg" \
--source https://api.nuget.org/v3/index.json \
--api-key "$NUGET_API_KEY" \
--skip-duplicate
done
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ results from the same machine and runtime.
### CI & releases

- **CI** (`.github/workflows/ci.yml`) runs `dotnet test` on Ubuntu for pushes/PRs to `main`/`master`.
- **Release** (`.github/workflows/release.yml`) triggers on tags `v*` (e.g. `v0.4.0`): verifies the tag matches the root [`version`](version) file, tests on Linux, then publishes self-contained single-file binaries for `linux-x64`, `win-x64`, `osx-arm64`, and `osx-x64`, plus NuGet packages for `IronKernel.Tool` and `IronKernel.Sdk`. Binaries are attached as `ironkernel-<rid>.tar.gz` (binary + `kernel.ikr` / `promises.ikr`).
- **Release** (`.github/workflows/release.yml`) triggers on tags `v*` (e.g. `v0.4.0`): verifies the tag matches the root [`version`](version) file, tests on Linux, then publishes self-contained single-file binaries for `linux-x64`, `win-x64`, `osx-arm64`, and `osx-x64`, plus NuGet packages for `IronKernel.Tool` and `IronKernel.Sdk`. The **Publish to NuGet.org** workflow (`nuget-publish.yml`) pushes them via [Trusted Publishing](https://learn.microsoft.com/nuget/nuget-org/trusted-publishing) — a nuget.org policy pinned to that workflow file exchanges a GitHub OIDC token for a one-hour key, no stored API key — automatically after each successful Release run, or manually by tag for retries. Binaries are attached as `ironkernel-<rid>.tar.gz` (binary + `kernel.ikr` / `promises.ikr`).
- **Versioning:** edit the root `version` file (single source of truth via `Directory.Build.props`). Commit, then tag and push `v$(tr -d '[:space:]' < version)`. The release job fails if the tag and file disagree. `ik --version` and the REPL banner read the assembly informational version produced from that file.

### Website
Expand Down
Loading