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
7 changes: 7 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
"husky"
],
"rollForward": false
},
"microsoft.openapi.kiota": {
"version": "1.31.1",
"commands": [
"kiota"
],
"rollForward": false
}
}
}
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 ProxmoxSharp.Api build.
- name: Restore tools
run: dotnet tool restore

# Build regenerates the ProxmoxSharp.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
# ProxmoxSharp.Api client from the pinned schema 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
60 changes: 43 additions & 17 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,65 @@
name: publish

# Publishes both packages to GitHub Packages:
# ProxmoxSharp.Api (version = Proxmox API release, e.g. 9.2.2)
# ProxmoxSharp (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.ProxmoxSharp.Api (version tracks the Proxmox API release, e.g. 9.2.2)
# Chrison.ProxmoxSharp (independent SemVer, e.g. 0.2.0)
# Chrison.ProxmoxSharp.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), 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 ProxmoxSharp.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[@]}"
42 changes: 27 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,18 @@ touching the API version; bump the API when you regenerate from a new Proxmox re

## 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 ProxmoxSharp.Api from the schema if it changed, then compiles
dotnet test
./build.sh # default: Test (Compile regenerates ProxmoxSharp.Api from the schema, then compiles)
./build.sh Pack # produce the Chrison.* nupkgs into artifacts/
```

CI (`.github/workflows/ci.yml`) does the same on push/PR — a clean checkout
regenerates the client fresh.
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 (`.github/workflows/ci.yml`) runs
`./build.sh Test` on push/PR — a clean checkout regenerates the client fresh.

## Use it

Expand All @@ -65,7 +69,7 @@ the shell. It's self-contained (bundles the library + generated client), so inst
needs only the `ProxmoxSharp.Cli` package, not its dependencies.

```bash
dotnet tool install -g ProxmoxSharp.Cli # from the GitHub Packages feed (read:packages)
dotnet tool install -g Chrison.ProxmoxSharp.Cli # from nuget.org (public)

export PROXMOX_BASE_URL="https://192.168.179.3:8006/api2/json"
export PROXMOX_TOKEN_ID="root@pam!token"
Expand Down Expand Up @@ -96,23 +100,31 @@ pwsh scripts/new-dev-token.ps1 -Node hpe-01

## Packages

Published to **GitHub Packages**:
Published to **nuget.org** (public) under the `Chrison.*` prefix, via **Trusted
Publishing** (OIDC — no stored API key):

| ID | Versioning |
| --- | --- |
| `Chrison.ProxmoxSharp` | independent SemVer (`0.2.0`) |
| `Chrison.ProxmoxSharp.Api` | tracks the Proxmox API release (`9.2.2`) |
| `Chrison.ProxmoxSharp.Cli` | `dotnet` tool, co-versioned with the library |

| Trigger | Versions | Workflow |
| --- | --- | --- |
| push to `main` | **prerelease** — `…-preview.<run>` (e.g. `0.1.0-preview.42`) | `ci.yml` |
| `v*` tag | **stable** — from `VersionPrefix` (`0.1.0` / `9.2.2`) | `publish.yml` |
| push to `main` | **prerelease** — `…-preview.<run>` | `publish.yml` |
| `v*` tag | **stable** — from `VersionPrefix` | `publish.yml` |

So every merge to `main` ships a referenceable prerelease; tagging cuts a stable
release. `ProxmoxSharp.Api` versions to the Proxmox release (e.g. `9.2.2`),
`ProxmoxSharp` to its own SemVer, and the library depends on the matching `.Api`.
release. The library depends on the matching `.Api`. IDs use the `Chrison.*` prefix
because the bare `ProxmoxSharp` ID is taken on nuget.org by an unrelated project;
assembly names and namespaces stay `ProxmoxSharp`, so `using ProxmoxSharp;` is unchanged.

Consuming needs the GitHub feed (`nuget.config`) + a PAT with `read:packages`.
To track the latest prerelease, float it: `<PackageReference Include="ProxmoxSharp" Version="0.1.0-preview.*" />`.
Consume from nuget.org like any public package. To track the latest prerelease, float it:
`<PackageReference Include="Chrison.ProxmoxSharp" Version="0.2.0-preview.*" />`.

## Status

M1–M5 done. Generated client reads the live cluster; `ProxmoxDiscovery` produces
a structured `ClusterSnapshot` (nodes → LXC/QEMU/storage/network); both packages
publish to GitHub Packages. Coverage: `/version,/nodes,/cluster,/storage,/access`
a structured `ClusterSnapshot` (nodes → LXC/QEMU/storage/network); the packages
publish to nuget.org. Coverage: `/version,/nodes,/cluster,/storage,/access`
(338 GET ops). Next: the hub consumes the package; BL-014 CLI; write path (BL-010).
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
# ProxmoxSharp 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
# ProxmoxSharp 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