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
94 changes: 94 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ jobs:
shell: pwsh
run: .\build\pack.ps1

- name: Smoke-test the packed package (Windows)
shell: pwsh
run: .\build\test-package.ps1

- name: Upload win-x64 Native Artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: native-win-x64
path: artifacts/native/win-x64/*
if-no-files-found: warn

- name: Upload NuGet Packages
uses: actions/upload-artifact@v4
if: always()
Expand All @@ -124,3 +136,85 @@ jobs:
name: symbol-packages
path: artifacts/nuget/*.snupkg
if-no-files-found: warn

# ---------------------------------------------------------------------------
# Linux: prove the *cross-platform* package (packed on Windows above) actually
# works on Linux. Downloads the finished 'nuget-packages' artifact and consumes
# it as a real NuGet package via build/test-package.sh: restore -> the bundled
# Linux idlc runs code generation -> DllImport resolves libddsc.so -> pub/sub
# round-trip, then the ddsmonitor tool is installed and served. No native build.
# ---------------------------------------------------------------------------
linux-verify:
runs-on: ubuntu-latest
needs: [ build ]

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Required for Nerdbank.GitVersioning (applies to the smoke-test project)

- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
8.0.x
10.0.x

- name: Download cross-platform packages
uses: actions/download-artifact@v4
with:
name: nuget-packages
path: artifacts/nuget/

- name: Smoke-test the cross-platform package (Linux)
shell: bash
run: build/test-package.sh

# ---------------------------------------------------------------------------
# Publish to NuGet.org — ONLY on a version tag (vX.Y.Z), and ONLY after the
# cross-platform package has been verified on both Windows (build) and Linux
# (linux-verify). Pushes the packages produced by the build job (both
# CycloneDDS.NET and CycloneDDS.NET.DdsMonitor) plus their symbol packages.
#
# Requires a repository secret named NUGET_API_KEY:
# Repo -> Settings -> Secrets and variables -> Actions -> New repository secret.
# To release: create a GitHub Release with a tag matching the NBGV version of
# the target commit (e.g. v0.3.2 — check with `nbgv get-version` first).
# ---------------------------------------------------------------------------
publish:
runs-on: ubuntu-latest
needs: [ build, linux-verify ]
if: startsWith(github.ref, 'refs/tags/v')

steps:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 10.0.x

- name: Download packages
uses: actions/download-artifact@v4
with:
name: nuget-packages
path: artifacts/nuget/

- name: Download symbol packages
uses: actions/download-artifact@v4
with:
name: symbol-packages
path: artifacts/nuget/

- name: Push to NuGet.org
shell: bash
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
if [ -z "$NUGET_API_KEY" ]; then
echo "::error::NUGET_API_KEY secret is not set — cannot publish." >&2
exit 1
fi
# dotnet expands the wildcard and auto-pushes the matching .snupkg for each .nupkg.
dotnet nuget push "artifacts/nuget/*.nupkg" \
--api-key "$NUGET_API_KEY" \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## unreleased
nothing yet

## 0.3.2

### Fixed
- **SourceLink symbols for the whole library.** `CycloneDDS.Core` and
`CycloneDDS.Schema` now ship their SourceLink-enabled PDBs in `lib/net8.0`
(previously only `CycloneDDS.Runtime` did), so consumers can step into all three
assemblies straight from the package.

### Added
- **Automatic NuGet publish on a version tag.** Pushing a `vX.Y.Z` tag (e.g. via a
GitHub Release) builds and verifies the cross-platform package on Windows and
Linux, then publishes it — and the `ddsmonitor` tool — to NuGet.org. Requires the
`NUGET_API_KEY` repository secret.
- **CI now verifies the packaged output on both platforms** before publishing (a
Windows smoke test + a Linux job that consumes the finished package), and uploads
the `win-x64` native as a workflow artifact.
- **`examples/PackageSmokeTest`** and **`build/test-package.{sh,ps1}`** for
smoke-testing the package (and the `ddsmonitor` tool) locally on either OS.

### Changed
- Packing now succeeds on Linux too (Windows-only pack entries are `Exists`-guarded),
so a per-platform package can be built locally on either OS.
- CI builds set `ContinuousIntegrationBuild` for deterministic PDBs with normalized
SourceLink source paths.

## 0.3.1

### Added
Expand Down
3 changes: 3 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- On CI (the builds that get published), produce deterministic PDBs with
normalized source paths so SourceLink maps cleanly to GitHub. -->
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
</PropertyGroup>
Expand Down
142 changes: 135 additions & 7 deletions RELEASE-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,97 @@ Before you begin, ensure you have:
1. **Maintainer Access** to the GitHub repository
2. **NuGet API Key** with push permissions for the CycloneDDS.NET package
3. **Development Environment** with:
- .NET 8.0 SDK or later
- PowerShell
- **.NET 10 SDK** — the code uses C# 13 language features, so building requires it; the produced binaries still target `net8.0`. (The .NET 8 runtime is also handy for running the `net8.0` tests.)
- **CMake 3.16+**
- **Windows:** PowerShell and Visual Studio 2022 (*C++ Desktop Development* workload) for native compilation.
- **Linux:** a C toolchain and `patchelf` — `sudo apt-get install -y cmake build-essential patchelf`.
- Git command-line tools

## Building & Testing a Multi-Platform Package Locally

The published `CycloneDDS.NET` and `CycloneDDS.NET.DdsMonitor` packages ship native
assets for **both** `win-x64` and `linux-x64`. Every green CI run already produces
these as artifacts, so **you rarely need to build them yourself** — the options
below are ordered easiest first.

> **How the cross-platform package is assembled.** The pack step includes whatever
> native artifacts are present under `artifacts/native/<rid>/` (Windows-only entries
> are `Exists`-guarded), so a cross-platform package needs *both* platforms' natives
> on one pack host. Because the packages bundle the Windows apphost `.exe` launchers
> for the build-time tools, the final cross-platform pack runs on **Windows**.
> Packing on Linux is fully supported but yields a `linux-x64`-only package.

CI publishes three artifacts per run: **`nuget-packages`** (the finished
cross-platform `.nupkg` + `.snupkg`), **`native-win-x64`**, and
**`native-linux-x64`**. Download them with the GitHub CLI (`gh`, recommended —
`winget install GitHub.cli` on Windows) or from the Actions run page.

### Option A — Download the finished package from CI (easiest, no build)

```bash
# Grab the cross-platform packages from the latest green run on main:
gh run download --repo pjanec/CycloneDds.NET -n nuget-packages -D artifacts/nuget
build/test-package.sh # smoke-test them on this OS (PowerShell: .\build\test-package.ps1)
```

Then publish `artifacts/nuget/*.nupkg` manually (see *Publishing* below). Run
`test-package` on both a Windows and a Linux box against the same package before
publishing.

### Option B — Assemble the package locally without a C++ toolchain

Download **both** natives from CI and pack — no Visual Studio / CMake needed, just
the .NET 10 SDK:

```powershell
gh run download --repo pjanec/CycloneDds.NET -n native-win-x64 -D artifacts\native\win-x64
gh run download --repo pjanec/CycloneDds.NET -n native-linux-x64 -D artifacts\native\linux-x64
dotnet build CycloneDDS.NET.Core.slnf -c Release
dotnet pack src\CycloneDDS.Runtime\CycloneDDS.Runtime.csproj -c Release --no-build -o artifacts\nuget
dotnet pack tools\DdsMonitor\DdsMonitor.Blazor\DdsMonitor.csproj -c Release --no-build -o artifacts\nuget
.\build\test-package.ps1
```

### Option C — Full local build from source

```powershell
# Windows (needs VS 2022 C++ workload + CMake): builds win native, downloads linux native, packs both
.\build\native-win.ps1
gh run download --repo pjanec/CycloneDds.NET -n native-linux-x64 -D artifacts\native\linux-x64
.\build\pack.ps1
.\build\test-package.ps1
```

```bash
# Linux (needs cmake/gcc/patchelf): produces a linux-x64-only package, enough to validate the Linux side
build/native-linux.sh Release
dotnet build CycloneDDS.NET.Core.slnf -c Release
dotnet pack src/CycloneDDS.Runtime/CycloneDDS.Runtime.csproj -c Release --no-build -o artifacts/nuget
dotnet pack tools/DdsMonitor/DdsMonitor.Blazor/DdsMonitor.csproj -c Release --no-build -o artifacts/nuget
build/test-package.sh
```

### The smoke test (`build/test-package.{sh,ps1}`)

Both scripts pick the **newest** package in the feed by write-time (so a cluttered
`artifacts/nuget` with old builds is fine — do **not** name-sort), then:

1. Consume `CycloneDDS.NET` as a real NuGet **package** via `examples/PackageSmokeTest`
— which declares a `[DdsTopic]` (so the packaged code generator + `idlc` run at
build time) and does a publish/subscribe round-trip. Expect
`[smoke] PASS: round-trip Id=42 ...`.
2. Install the `ddsmonitor` global tool, confirm it serves HTTP 200 (native loaded),
and uninstall it.

```
build/test-package.sh [FEED_DIR] # default artifacts/nuget; NO_DDSMON=1 to skip the tool
.\build\test-package.ps1 [-FeedDir <d>] [-NoDdsMon]
```

Run the smoke test on **both** a Windows and a Linux box before publishing. Both
were validated during development — Linux locally + in CI, Windows in the CI
`build` job.

## Version Management

This project uses **Nerdbank.GitVersioning (NBGV)** for automatic semantic versioning.
Expand Down Expand Up @@ -133,8 +220,20 @@ Expand-Archive artifacts/nuget/CycloneDDS.NET.1.0.0.nupkg -DestinationPath temp_
# - ThirdPartyNotices.txt is present
# - Native binaries are in runtimes/ folder
# - Build tools are in build/ or buildTransitive/ folder
# - lib/net8.0/ has *.dll AND matching *.pdb for Runtime, Core and Schema
# (SourceLink debugging), and a .snupkg was produced alongside the .nupkg
```

**Debugging support (SourceLink).** The package embeds SourceLink so consumers can
step into the library sources straight from GitHub. Symbols ship two ways: the
`lib/net8.0/*.pdb` travel inside the `.nupkg` (Visual Studio loads them directly),
and a `.snupkg` is published to the NuGet symbol server. Verify with the
[`sourcelink`](https://www.nuget.org/packages/sourcelink) tool, e.g.
`sourcelink print-urls lib\net8.0\CycloneDDS.Runtime.pdb` should list
`https://raw.githubusercontent.com/pjanec/CycloneDds.NET/<commit>/...` URLs.
Publish **both** the `.nupkg` and the `.snupkg` (see below). SourceLink URLs only
resolve for commits pushed to GitHub, so publish from a CI build on `main`/a tag.

**Key Things to Check:**
- [ ] Package version is correct (no `-alpha` suffix for stable)
- [ ] `icon.png` is at package root
Expand All @@ -146,13 +245,42 @@ Expand-Archive artifacts/nuget/CycloneDDS.NET.1.0.0.nupkg -DestinationPath temp_

## Publishing to NuGet.org

### Option A: Automatic Publishing (CI/CD)
### Option A: Automatic Publishing (CI/CD) — recommended

CI publishes to NuGet.org automatically when you push a **version tag** (`vX.Y.Z`),
but only after the cross-platform package has passed the Windows and Linux
verification jobs. The `publish` job pushes both `CycloneDDS.NET` and
`CycloneDDS.NET.DdsMonitor` (plus their `.snupkg` symbols).

If CI is configured to auto-publish on tags:
**One-time setup — store the NuGet API key as a repository secret:**

1. **Wait for CI to complete** after pushing the tag
2. **Verify on NuGet.org** that the new version appears
3. **Create a GitHub Release** with release notes
1. Create an API key at <https://www.nuget.org/account/apikeys> with **"Push new
packages and package versions"**. Scope the *Package glob* to `CycloneDDS.NET*`
so it covers both packages. (For the very first push of a brand-new package id,
a key scoped to *all* packages / your account may be required until the id
exists.)
2. In GitHub: **Repo → Settings → Secrets and variables → Actions → New repository
secret**. Name it exactly **`NUGET_API_KEY`** and paste the key. GitHub encrypts
it and masks it in logs; the workflow reads it as `secrets.NUGET_API_KEY`. You
never commit the key.

**Releasing:**

1. Make sure `main` is green and at the commit you want to ship.
2. Check the version NBGV will produce for that commit:
```bash
nbgv get-version # e.g. 0.3.2 (dotnet tool install -g nbgv)
```
The published version is `version.json` base + git height — the tag name does
**not** set it, so name the tag to match (e.g. `v0.3.2`).
3. **Create a GitHub Release** with tag `vX.Y.Z` targeting that commit (or
`git tag v0.3.2 && git push origin v0.3.2`). The tag push runs CI; on success
the `publish` job pushes to NuGet.org.
4. **Verify on NuGet.org** that the new version (and the DdsMonitor tool) appear.

> The tag is added to `publicReleaseRefSpec` in `version.json`, so a tag build gets
> a clean version (no `-gSHA` prerelease suffix). SourceLink URLs resolve because
> the tagged commit is on GitHub.

### Option B: Manual Publishing

Expand Down
Loading
Loading