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
110 changes: 110 additions & 0 deletions .github/workflows/publish-github-packages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Publish GitHub Packages

# Packs the public TensorSharp packages and pushes them to the repository
# owner's GitHub Packages NuGet feed (nuget.pkg.github.com/<owner>).
#
# Trigger: push a version tag like `v2.8.6` — the tag (with the leading `v`
# stripped) becomes the package version, overriding the default in
# Directory.Build.props. `workflow_dispatch` is also available for manual
# publishes; it accepts an explicit `version` and a `dry_run` that packs and
# verifies without pushing.
#
# Packing is managed-only: the native libraries (GGML/CUDA/MLX) are not
# embedded in the .nupkg, so this job skips the native build (-SkipNativeBuild)
# and runs on a stock GitHub-hosted runner with no GPU/CMake toolchain.
#
# Authentication: the workflow's own GITHUB_TOKEN with `packages: write`.
# No external feed, no OIDC, no API keys. GitHub Packages does not accept
# symbol packages, so only *.nupkg is pushed; *.snupkg remain available as
# workflow artifacts.
#
# Packages are pushed one at a time rather than by glob so a rejected package
# is visible in the log instead of hidden behind a later failure.

on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: "Package version to publish (e.g. 2.8.6). Required when not run from a tag."
required: false
default: ""
dry_run:
description: "Pack and verify only; do not push."
required: false
type: boolean
default: false

permissions:
contents: read
packages: write

concurrency:
# Never cancel an in-flight publish — a half-pushed release is worse than a queue.
group: publish-github-packages-${{ github.ref }}
cancel-in-progress: false

jobs:
publish:
name: Pack & publish
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
# Native libraries are not packed, so the ggml sources are not needed.
submodules: false

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

- name: Resolve package version
id: ver
shell: bash
run: |
set -euo pipefail
V="${{ github.event.inputs.version }}"
if [ -z "$V" ] && [ "${{ github.ref_type }}" = "tag" ]; then
V="${GITHUB_REF_NAME#v}"
fi
if [ -z "$V" ]; then
echo "::error::No version resolved. Push a tag like v2.8.6 or supply the 'version' input." >&2
exit 1
fi
echo "version=$V" >> "$GITHUB_OUTPUT"
echo "Resolved package version: $V"

- name: Pack & verify packages
shell: pwsh
run: >-
./eng/verify-packages.ps1
-PackageVersion '${{ steps.ver.outputs.version }}'
-SkipNativeBuild
-OutputDirectory artifacts/packages

- name: Upload package artifacts
uses: actions/upload-artifact@v4
with:
name: nuget-packages-${{ steps.ver.outputs.version }}
path: |
artifacts/packages/*.nupkg
artifacts/packages/*.snupkg
retention-days: 30

- name: Push to GitHub Packages
if: ${{ !inputs.dry_run }}
shell: bash
run: |
set -euo pipefail
# GitHub Packages does not accept symbol packages, so only *.nupkg here.
for pkg in artifacts/packages/*.nupkg; do
echo "::group::$(basename "$pkg")"
dotnet nuget push "$pkg" \
--source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \
--api-key "${{ secrets.GITHUB_TOKEN }}" \
--skip-duplicate
echo "::endgroup::"
done
28 changes: 24 additions & 4 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ The repository is split along package boundaries so consumers can depend on only

What is on [NuGet.org](https://www.nuget.org/profiles/TensorSharp) today is a subset: **eight** ids at version **3.1.2**, published 2026-07-21 — `TensorSharp.Tensors`, `TensorSharp.Runtime`, `TensorSharp.Models`, `TensorSharp.Backends.GGML`, `TensorSharp.Backends.Cuda`, `TensorSharp.Backends.MLX`, `TensorSharp.Server`, and `TensorSharp.Cli`. Those packages lag the current source and the v3.3.0.0 application release; in particular the published `TensorSharp.Server` predates the logging and chat splits, so it does not match the layering described here.

The remaining five — `TensorSharp.Runtime.Logging`, `TensorSharp.AgentHost`, `TensorSharp.Chat`, `TensorSharp.Server.Host`, and `TensorSharp.Distributed` — are packable and verified but have never been pushed. Until a publish channel is re-established, consumers of those layers need project references from a source checkout.
The remaining five — `TensorSharp.Runtime.Logging`, `TensorSharp.AgentHost`, `TensorSharp.Chat`, `TensorSharp.Server.Host`, and `TensorSharp.Distributed` — are packable and verified but have never been pushed to any feed; they ship with the next version tag. Until then, consumers of those layers need project references from a source checkout.

| Project | NuGet package | Public namespace | Responsibility |
|---|---|---|---|
Expand Down Expand Up @@ -586,14 +586,34 @@ The verifier runs `dotnet pack` for the public packages above and fails if an in

### Publishing a package release (maintainers)

CI no longer publishes NuGet packages: the `publish-nuget.yml` workflow was removed, so version tags trigger only the binary release workflow and nothing is pushed to NuGet.org or GitHub Packages. To pack the public packages locally — managed-only, the native GGML/CUDA/MLX libraries are not embedded — and validate metadata and dependency boundaries:
The [`Publish GitHub Packages`](.github/workflows/publish-github-packages.yml) workflow packs the public projects above and pushes them to the organization's GitHub Packages NuGet feed. Nothing is pushed to NuGet.org from CI. Trigger it by pushing a version tag — the tag (leading `v` stripped) overrides `TensorSharpVersion` for every package, so all packages ship with a single coordinated version — or manually via `workflow_dispatch`, which accepts an explicit `version` and a `dry_run` rehearsal that packs and verifies without pushing:

```bash
git tag vX.Y.Z.W
git push origin vX.Y.Z.W
```

Packing is managed-only — the native GGML/CUDA/MLX libraries are not embedded in the packages — and is gated by `eng/verify-packages.ps1 -SkipNativeBuild`. Authentication uses the workflow's own `GITHUB_TOKEN` with `packages: write`; there are no external accounts or API keys. GitHub Packages does not accept symbol packages, so only `.nupkg` files are pushed and `.snupkg` remain available as workflow artifacts. `ContinuousIntegrationBuild` is set only under GitHub Actions, so local packs keep their normal source paths.

Packages land at `https://nuget.pkg.github.com/MotusLabs/index.json`. New packages are private by default; an org admin can make them public in the organization's Packages settings. To consume the feed, configure a NuGet source with a classic PAT that has `read:packages` (GitHub Packages' NuGet feed requires authenticated restore even for public packages):

```bash
dotnet nuget add source \
--username <github-username> \
--password <ghp_...> \
--store-password-in-clear-text \
--name motuslabs \
"https://nuget.pkg.github.com/MotusLabs/index.json"

dotnet add package TensorSharp.Tensors
```

To validate package metadata and README dependency boundaries without publishing:

```powershell
pwsh ./eng/verify-packages.ps1
```

`ContinuousIntegrationBuild` is set only under GitHub Actions, so local packs keep their normal source paths.

### Platform binary release status

**Status verified 2026-09-01:** [v3.3.0.0](https://github.com/zhongkaifu/TensorSharp/releases/tag/v3.3.0.0) publishes ten self-contained application archives of **TensorSharp.Server** and **TensorSharp.Cli**, including the .NET 10 runtime and native libraries. There is one Server archive and one CLI archive for each of the five platform/backend suffixes below. Check the [Releases page](https://github.com/zhongkaifu/TensorSharp/releases) for newer versions instead of assuming that this stamped version remains latest.
Expand Down
4 changes: 2 additions & 2 deletions DEVELOPMENT_zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ TensorSharp/

当前真正发布到 [NuGet.org](https://www.nuget.org/profiles/TensorSharp) 的只是其中一个子集:**8** 个包 ID,版本 **3.1.2**,发布于 2026-07-21——`TensorSharp.Tensors`、`TensorSharp.Runtime`、`TensorSharp.Models`、`TensorSharp.Backends.GGML`、`TensorSharp.Backends.Cuda`、`TensorSharp.Backends.MLX`、`TensorSharp.Server` 与 `TensorSharp.Cli`。它们落后于当前源码与 v3.3.0.0 应用发行版;尤其是已发布的 `TensorSharp.Server` 早于日志层与聊天层拆分,与这里描述的分层并不一致。

其余 5 个——`TensorSharp.Runtime.Logging`、`TensorSharp.AgentHost`、`TensorSharp.Chat`、`TensorSharp.Server.Host` 与 `TensorSharp.Distributed`——已可打包并通过校验,但尚未推送。在发布渠道恢复之前,使用这些层仍需从源码 checkout 添加项目引用。
其余 5 个——`TensorSharp.Runtime.Logging`、`TensorSharp.AgentHost`、`TensorSharp.Chat`、`TensorSharp.Server.Host` 与 `TensorSharp.Distributed`——已可打包并通过校验,但尚未推送到任何源;它们将随下一个版本标签一同发布到 GitHub Packages。在此之前,使用这些层仍需从源码 checkout 添加项目引用。

| 项目 | NuGet 包 | 对外 namespace | 职责 |
|---|---|---|---|
Expand Down Expand Up @@ -406,7 +406,7 @@ v3.3.0.0 已发布的归档矩阵如下:
| `linux-x64-cuda` | GGML CUDA + 纯 C# CUDA(PTX)+ CUDA 12.x 运行时 | `.tar.gz` |
| `osx-arm64` | GGML Metal + MLX | `.tar.gz` |

- 推送 `v*` 标签会触发归档工作流;只有所需 job 全部成功后才会发布产物。
- 推送 `v*` 标签会触发归档与 GitHub Packages 发布工作流;只有所需 job 全部成功后才会发布产物。
- `-cuda` 归档已内置 CUDA 运行时库(`cudart` / `cublas` / `cublasLt`),但运行时仍需 NVIDIA GPU 与兼容驱动;`-cpu` 归档可在任意机器运行。macOS 归档需 Apple Silicon。
- 如需预演,可手动触发该工作流(`workflow_dispatch`)并填写 `version` 输入——它会构建全部平台并创建**草稿** Release。可用 `cuda_arch` 输入覆盖 CUDA 构建的目标 GPU 架构。

Expand Down
Loading