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
1 change: 1 addition & 0 deletions .fallout/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/temp
130 changes: 130 additions & 0 deletions .fallout/build.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"Host": {
"type": "string",
"enum": [
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
"Jenkins",
"Rider",
"SpaceAutomation",
"TeamCity",
"Terminal",
"TravisCI",
"VisualStudio",
"VSCode"
]
},
"ExecutableTarget": {
"type": "string",
"enum": [
"Clean",
"Compile",
"Pack",
"Publish",
"Test"
]
},
"Verbosity": {
"type": "string",
"description": "",
"enum": [
"Verbose",
"Normal",
"Minimal",
"Quiet"
]
},
"FalloutBuild": {
"properties": {
"Continue": {
"type": "boolean",
"description": "Indicates to continue a previously failed build attempt"
},
"Help": {
"type": "boolean",
"description": "Shows the help text for this build assembly"
},
"Host": {
"description": "Host for execution. Default is 'automatic'",
"$ref": "#/definitions/Host"
},
"NoLogo": {
"type": "boolean",
"description": "Disables displaying the NUKE logo"
},
"Partition": {
"type": "string",
"description": "Partition to use on CI"
},
"Plan": {
"type": "boolean",
"description": "Shows the execution plan (HTML)"
},
"Profile": {
"type": "array",
"description": "Defines the profiles to load",
"items": {
"type": "string"
}
},
"Root": {
"type": "string",
"description": "Root directory during build execution"
},
"Skip": {
"type": "array",
"description": "List of targets to be skipped. Empty list skips all dependencies",
"items": {
"$ref": "#/definitions/ExecutableTarget"
}
},
"Target": {
"type": "array",
"description": "List of targets to be invoked. Default is '{default_target}'",
"items": {
"$ref": "#/definitions/ExecutableTarget"
}
},
"Verbosity": {
"description": "Logging verbosity during build execution. Default is 'Normal'",
"$ref": "#/definitions/Verbosity"
},
"BuildProjectFile": {
"type": [
"null",
"string"
],
"description": "Path to the build project (.csproj) relative to the repository root. Defaults to 'build/_build.csproj' when unset. Read by the Fallout global tool's in-tool runner."
}
}
}
},
"allOf": [
{
"properties": {
"NuGetApiKey": {
"type": "string",
"description": "API key for the push. In CI this is the short-lived key from NuGet/login (Trusted Publishing), never a stored secret"
},
"NuGetSource": {
"type": "string",
"description": "nuget.org push source"
},
"VersionSuffix": {
"type": "string",
"description": "Prerelease suffix appended to VersionPrefix (e.g. 'preview.42'). Empty → stable"
}
}
},
{
"$ref": "#/definitions/FalloutBuild"
}
]
}
3 changes: 3 additions & 0 deletions .fallout/parameters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"$schema": "build.schema.json"
}
40 changes: 14 additions & 26 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ on:
pull_request:
branches: [main]

# Build + test only. Publishing (prerelease on main, stable on v* tag) lives in
# publish.yml and uses nuget.org Trusted Publishing (OIDC) — no packages: write here.
permissions:
contents: read
packages: write

jobs:
build:
Expand All @@ -20,28 +21,15 @@ jobs:
with:
dotnet-version: '10.0.x'

# Kiota (pinned in .config/dotnet-tools.json) — needed by the regenerate
# step that runs during the UnifiSharp.Api build.
- name: Restore tools
run: dotnet tool restore

# Build regenerates the UnifiSharp.Api client from the pinned schema
# (Generated/ is gitignored), then compiles everything.
- name: Build
run: dotnet build -c Release

# Live integration tests skip automatically without a secrets.env.
- name: Test
run: dotnet test -c Release --no-build

# On every push to main, publish a PRERELEASE to GitHub Packages so other
# projects can reference the latest build (e.g. 0.1.0-preview.42). Stable
# versions are published from the publish.yml workflow on a v* tag.
- name: Publish prerelease
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
dotnet pack -c Release -o artifacts --version-suffix "preview.${{ github.run_number }}"
dotnet nuget push "artifacts/*.nupkg" \
--source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \
--api-key "${{ secrets.GITHUB_TOKEN }}" \
--skip-duplicate --no-symbols
# Runs the Fallout build (Compile → Test). Compile regenerates the
# UnifiSharp.Api client from the committed OpenAPI spec via Kiota (Generated/
# is gitignored), then compiles everything; Test skips live integration tests
# automatically without a secrets.env.
#
# GITHUB_PACKAGES_PAT authenticates the Fallout-build package feed (nuget.config)
# so the build/ project can restore Fallout.*. PACKAGES_PAT is a PAT with
# read:packages on the Fallout-build org.
- name: Build & test (Fallout)
env:
GITHUB_PACKAGES_PAT: ${{ secrets.PACKAGES_PAT }}
run: ./build.sh Test
61 changes: 44 additions & 17 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,66 @@
name: publish

# Publishes both packages to GitHub Packages:
# UnifiSharp.Api (version = UniFi Network API release, e.g. 10.4.57)
# UnifiSharp (independent SemVer, e.g. 0.1.0)
# Versions come from the csprojs; a `v*` tag (the library release) just triggers it.
# Publishes the three packages to nuget.org via Trusted Publishing (OIDC — no
# stored API key):
# Chrison.UnifiSharp.Api (version tracks the UniFi Network API release, e.g. 10.4.57)
# Chrison.UnifiSharp (independent SemVer, e.g. 0.1.0)
# Chrison.UnifiSharp.Cli (dotnet tool; co-versioned with the library)
# Stable versions come from the csprojs' VersionPrefix; a `v*` tag just triggers a
# stable publish. A push to main publishes a PRERELEASE (…-preview.N).
#
# Requires a nuget.org Trusted Publishing policy for this repo + this workflow file
# (publish.yml) with Environment=Nuget.org, and the NUGET_USER secret (nuget.org
# profile name). GITHUB_PACKAGES_PAT (from PACKAGES_PAT) only authenticates the
# Fallout-build feed for the build/ project.
on:
push:
branches: [main]
tags: ['v*']
workflow_dispatch:

permissions:
id-token: write # enable GitHub OIDC token issuance (Trusted Publishing)
contents: read
packages: write

jobs:
publish:
runs-on: ubuntu-latest
# Must match the nuget.org Trusted Publishing policy's Environment field — the
# OIDC token only carries the environment claim when the job declares it here,
# and the policy rejects the exchange otherwise.
environment: Nuget.org
steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Restore tools
run: dotnet tool restore
# Stable on a v* tag (version = csproj VersionPrefix); prerelease otherwise.
- name: Compute version suffix
id: ver
run: |
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
echo "suffix=" >> "$GITHUB_OUTPUT"
else
echo "suffix=preview.${{ github.run_number }}" >> "$GITHUB_OUTPUT"
fi

# Pack regenerates UnifiSharp.Api from the schema, then packs the two
# packable projects (SchemaGen + Tests are IsPackable=false).
- name: Pack
run: dotnet pack -c Release -o artifacts
# Exchange the OIDC token for a short-lived (1h) nuget.org API key.
- name: NuGet login (OIDC → temporary API key)
uses: NuGet/login@v1
id: login
with:
user: ${{ secrets.NUGET_USER }}

- name: Push to GitHub Packages
run: >
dotnet nuget push "artifacts/*.nupkg"
--source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json"
--api-key "${{ secrets.GITHUB_TOKEN }}"
--skip-duplicate --no-symbols
# Fallout Pack + Publish. GITHUB_PACKAGES_PAT authenticates the Fallout-build
# feed (build/ project restore); the push uses the short-lived nuget.org key.
- name: Publish (Fallout → nuget.org)
env:
GITHUB_PACKAGES_PAT: ${{ secrets.PACKAGES_PAT }}
run: |
ARGS=(Publish --nuget-api-key "${{ steps.login.outputs.NUGET_API_KEY }}")
if [[ -n "${{ steps.ver.outputs.suffix }}" ]]; then
ARGS+=(--version-suffix "${{ steps.ver.outputs.suffix }}")
fi
./build.sh "${ARGS[@]}"
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,18 @@ on build** (only when the spec changes) and **not committed**.

## Build

Built with [Fallout](https://github.com/Fallout-build/Fallout) (Chris's C#/.NET
build system, a NUKE successor). Targets: `Compile` → `Test` → `Pack` → `Publish`.

```bash
dotnet tool restore # restore Kiota (the build invokes it to regenerate)
dotnet build # regenerates UnifiSharp.Api from the spec if it changed, then compiles
dotnet test
./build.sh # default: Test (Compile regenerates UnifiSharp.Api from the spec, then compiles)
./build.sh Pack # produce the Chrison.* nupkgs into artifacts/
```

Requires the .NET 10 SDK (see `global.json`) and `GITHUB_PACKAGES_PAT` in the
environment (a PAT with `read:packages` on the Fallout-build org — the build restores
`Fallout.*` from that feed, see `nuget.config`). CI runs `./build.sh Test` on push/PR.

## Use it

```csharp
Expand All @@ -62,9 +68,12 @@ var client = UnifiApi.Create(new UnifiClientOptions

## Packages

Published to GitHub Packages like ProxmoxSharp: prerelease on push to `main`
(`…-preview.N`), stable on a `v*` tag. `UnifiSharp.Api` tracks the UniFi API
release; `UnifiSharp` its own SemVer.
Published to **nuget.org** (public) under the `Chrison.*` prefix, via **Trusted
Publishing** (OIDC — no stored API key): `Chrison.UnifiSharp`, `Chrison.UnifiSharp.Api`,
`Chrison.UnifiSharp.Cli`. Prerelease on push to `main` (`…-preview.N`), stable on a
`v*` tag. `.Api` tracks the UniFi API release; the library its own SemVer. IDs use the
`Chrison.*` prefix because the bare `UnifiSharp` ID is taken on nuget.org by an unrelated
project; assembly names and namespaces stay `UnifiSharp`, so `using UnifiSharp;` is unchanged.

## Refresh the spec (new UniFi release)

Expand Down
12 changes: 12 additions & 0 deletions build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env pwsh
# UnifiSharp build entrypoint (Fallout build). Requires the .NET 10 SDK on PATH
# (see global.json) and, for restoring the Fallout.* build packages, GITHUB_PACKAGES_PAT
# in the environment (a PAT with read:packages on the Fallout-build org; see nuget.config).
#
# ./build.ps1 # default target: Test
# ./build.ps1 Pack --version-suffix preview.42
# ./build.ps1 Publish --nuget-api-key <key>
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
& dotnet run --project "$ScriptDir/build/_build.csproj" -- $args
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
11 changes: 11 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# UnifiSharp build entrypoint (Fallout build). Requires the .NET 10 SDK on PATH
# (see global.json) and, for restoring the Fallout.* build packages, GITHUB_PACKAGES_PAT
# in the environment (a PAT with read:packages on the Fallout-build org; see nuget.config).
#
# ./build.sh # default target: Test
# ./build.sh Pack --version-suffix preview.42
# ./build.sh Publish --nuget-api-key <key>
set -eo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec dotnet run --project "$SCRIPT_DIR/build/_build.csproj" -- "$@"
Loading
Loading