sigit-code 1.5.2__tar.gz → 1.5.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/AGENTS.md +56 -3
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.github/workflows/ci.yml +1 -1
- sigit_code-1.5.4/.github/workflows/release-aur.yml +99 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.github/workflows/release-github.yml +111 -10
- sigit_code-1.5.4/.github/workflows/release-nuget.yml +315 -0
- sigit_code-1.5.4/.github/workflows/release-scoop.yml +140 -0
- sigit_code-1.5.4/.github/workflows/release-winget.yml +71 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.gitignore +1 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/AGENTS.md +56 -3
- {sigit_code-1.5.2 → sigit_code-1.5.4}/CHANGELOG.md +54 -1
- {sigit_code-1.5.2 → sigit_code-1.5.4}/CLAUDE.md +56 -3
- {sigit_code-1.5.2 → sigit_code-1.5.4}/Cargo.lock +734 -674
- {sigit_code-1.5.2 → sigit_code-1.5.4}/Cargo.toml +14 -1
- {sigit_code-1.5.2 → sigit_code-1.5.4}/LICENSE +1 -1
- {sigit_code-1.5.2 → sigit_code-1.5.4}/PKG-INFO +2 -2
- {sigit_code-1.5.2 → sigit_code-1.5.4}/README.md +6 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/README.md.tmpl +1 -1
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/sigit/README.md +1 -1
- sigit_code-1.5.4/nuget/.gitignore +5 -0
- sigit_code-1.5.4/nuget/sigit/Program.cs +114 -0
- sigit_code-1.5.4/nuget/sigit/README.md +65 -0
- sigit_code-1.5.4/nuget/sigit/SiGit.Code.csproj +41 -0
- sigit_code-1.5.4/packaging/aur/PKGBUILD.in +31 -0
- sigit_code-1.5.4/packaging/nfpm.yaml +39 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/pypi/README.md +1 -1
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/backend.rs +6 -0
- sigit_code-1.5.4/src/browser_auth.rs +521 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/chat.rs +24 -9
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/main.rs +170 -18
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/provider.rs +2 -1
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/tools.rs +2 -3
- {sigit_code-1.5.2 → sigit_code-1.5.4}/tests/acp_permissions.rs +6 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/skills/agent-client-protocol/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/skills/branding/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/skills/sigit-code-release/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.agents/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.claude/skills/agent-client-protocol/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.claude/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.claude/skills/branding/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.claude/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.claude/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.claude/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.claude/skills/sigit-code-release/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.claude/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.github/workflows/release-crates.yml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.github/workflows/release-homebrew.yml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.github/workflows/release-mcp-registry.yml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.github/workflows/release-npm.yml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.github/workflows/release-pypi.yml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/.nvmrc +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/docs/hooks.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/docs/mcp.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/examples/settings-with-hooks.toml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/examples/skills/README.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/examples/skills/commit-message/SKILL.md +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/package-main.json.tmpl +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/package.json.tmpl +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/scripts/render-main-package.cjs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/scripts/render-platform-package.cjs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/sigit/.gitignore +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/sigit/package.json +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/sigit/src/index.ts +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/npm/sigit/tsconfig.json +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/pypi/pyproject.toml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/pyproject.toml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/rust-toolchain.toml +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/server.json +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/account.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/commands.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/credentials.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/frontmatter.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/headless.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/hooks.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/instructions.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/mcp.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/models.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/permissions.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/session_store.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/settings.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/setup.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/skills.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/src/subagents.rs +0 -0
- {sigit_code-1.5.2 → sigit_code-1.5.4}/tests/headless_mode.rs +0 -0
|
@@ -211,6 +211,18 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
211
211
|
those read env vars once at init.
|
|
212
212
|
- **`src/account.rs`** — siGit Code Cloud auth (`/login`, `/logout`, `/whoami`); authenticates
|
|
213
213
|
against the account API and stores a session token. Performs no console I/O.
|
|
214
|
+
- **`src/browser_auth.rs`** — browser sign-in, the path the editor's "Sign in to siGit Code"
|
|
215
|
+
button takes. sigit is a public OAuth client (client id `sigit-code-cli`, no secret, PKCE
|
|
216
|
+
S256) against the authorization server at `$SIGIT_API_URL/oauth`. Two ways the code gets
|
|
217
|
+
back: a loopback listener on `127.0.0.1:0` (the registration lists `http://127.0.0.1/callback`
|
|
218
|
+
with no port, and RFC 8252 §7.3 matching ignores the port, so one registration covers every
|
|
219
|
+
run), or the out-of-band URN, where the server renders the code and the user pastes it. The
|
|
220
|
+
resulting token goes into `credentials` like any other, and is served by `/api/v1/user` rather
|
|
221
|
+
than the deprecated `/api/v1/me` — OAuth tokens are rejected there. The scopes requested are
|
|
222
|
+
`user:read code:agent`; `code:agent` is what reaches `chat/completions` and the official MCP
|
|
223
|
+
server. Surfaces: ACP `authenticate` (loopback only — nowhere to show a code), a bare `/login`
|
|
224
|
+
in either chat surface, and `sigit login` (which adds the paste fallback, plus `--paste` to
|
|
225
|
+
force it and `--password` for the old email/password prompt).
|
|
214
226
|
- **`src/credentials.rs`** — local session-token store (TOML, `0600` on Unix).
|
|
215
227
|
- **`src/models.rs`** — model-picker types shared across platforms.
|
|
216
228
|
|
|
@@ -249,6 +261,47 @@ mutating tools; the escape hatch for clients without permission-request support)
|
|
|
249
261
|
|
|
250
262
|
## Releasing
|
|
251
263
|
|
|
252
|
-
Version lives in `Cargo.toml`.
|
|
253
|
-
|
|
254
|
-
|
|
264
|
+
Version lives in `Cargo.toml`. Update `CHANGELOG.md` for releases.
|
|
265
|
+
|
|
266
|
+
Publishing splits into two groups. **Language registries** each get their own tag-triggered
|
|
267
|
+
workflow: `release-crates`, `release-npm`, `release-nuget`, `release-pypi`. The `npm/`, `nuget/`,
|
|
268
|
+
and `pypi/` dirs hold their wrapper-package templates.
|
|
269
|
+
|
|
270
|
+
**OS package managers** all publish somewhere outside this repo and all need checksums from the
|
|
271
|
+
GitHub release, so `release-github` builds the binaries, attaches the assets, and then dispatches
|
|
272
|
+
`release-homebrew`, `release-scoop`, `release-winget`, and `release-aur`. A dispatch failure in one
|
|
273
|
+
is logged as a warning rather than failing the others, so an unconfigured channel does not block a
|
|
274
|
+
release. Their inputs live in `packaging/`.
|
|
275
|
+
|
|
276
|
+
Every release asset now carries a `.sha256` sidecar, not just the macOS Homebrew tarball. Scoop,
|
|
277
|
+
winget, and the AUR PKGBUILD each need one, and they consume the raw binaries rather than the
|
|
278
|
+
tarball. `release-github` also builds a `.deb` and `.rpm` per Linux target with nfpm
|
|
279
|
+
(`packaging/nfpm.yaml`), packaging the already-built binary rather than re-invoking cargo.
|
|
280
|
+
|
|
281
|
+
Three of these need credentials or a one-time manual step before they work:
|
|
282
|
+
|
|
283
|
+
- Scoop needs a `getsigit/scoop-bucket` repo and a `SCOOP_BUCKET_TOKEN` secret, mirroring the
|
|
284
|
+
Homebrew tap setup.
|
|
285
|
+
- winget needs a `WINGET_TOKEN` (PAT with `public_repo`) so `wingetcreate` can fork
|
|
286
|
+
`microsoft/winget-pkgs`. The workflow only handles *updates*; the first submission has to be made
|
|
287
|
+
by hand with `wingetcreate new`, since a package must exist before it can be updated.
|
|
288
|
+
- The AUR needs `AUR_USERNAME`, `AUR_EMAIL`, and `AUR_SSH_PRIVATE_KEY`. It publishes `sigit-bin`
|
|
289
|
+
(a prebuilt binary) so Arch users are not compiling the on-device inference stack to install a
|
|
290
|
+
CLI.
|
|
291
|
+
|
|
292
|
+
`[profile.release]` sets `strip = "symbols"` because binary size is a distribution constraint, not
|
|
293
|
+
just a nicety. See the NuGet note below.
|
|
294
|
+
|
|
295
|
+
The NuGet package (`SiGit.Code`, installed with `dotnet tool install --global SiGit.Code`) is the
|
|
296
|
+
odd one out among the language registries: npm and PyPI publish one artifact per platform, but a
|
|
297
|
+
.NET tool is a single package, so `nuget/sigit/` bundles all six binaries under
|
|
298
|
+
`native/<os>-<arch>/` and a small managed shim (`Program.cs`) execs the right one. That shim leaves
|
|
299
|
+
stdin/stdout/stderr unredirected on purpose, since siGit Code chooses TUI or ACP mode by testing
|
|
300
|
+
whether stdin is a TTY. It also sets `RollForward=Major`: it targets `net8.0`, and without that a
|
|
301
|
+
machine carrying only the .NET 10 runtime installs a tool that refuses to start.
|
|
302
|
+
|
|
303
|
+
Bundling every target means the package is large, so `release-nuget.yml` fails the pack job if the
|
|
304
|
+
`.nupkg` crosses nuget.org's 250 MB limit. At v1.5.1 it lands around 160 MB. If a future release
|
|
305
|
+
trips that check, the fix is not to drop targets but to split into RID-specific tool packages
|
|
306
|
+
(.NET 10's `DotnetToolRidPackage`), which ship one binary per platform the way npm already does.
|
|
307
|
+
That also needs a fallback package for pre-.NET-10 SDKs.
|
|
@@ -78,7 +78,7 @@ jobs:
|
|
|
78
78
|
key: clippy-${{ matrix.target }}
|
|
79
79
|
|
|
80
80
|
- name: Clippy
|
|
81
|
-
run: cargo clippy --tests --target ${{ matrix.target }} -- -D warnings
|
|
81
|
+
run: cargo clippy --locked --tests --target ${{ matrix.target }} -- -D warnings
|
|
82
82
|
|
|
83
83
|
test:
|
|
84
84
|
name: Test — ${{ matrix.name }}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
name: AUR Release
|
|
2
|
+
|
|
3
|
+
# Dispatched by release-github.yml once the release and its checksums exist.
|
|
4
|
+
#
|
|
5
|
+
# Publishes the `sigit-bin` package: a prebuilt binary rather than a source
|
|
6
|
+
# build, so Arch users are not compiling the whole dependency tree (and the
|
|
7
|
+
# on-device inference stack in particular) to install a CLI.
|
|
8
|
+
on:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
tag:
|
|
12
|
+
description: "Release tag (e.g. v1.5.2)"
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
env:
|
|
19
|
+
REPO: getsigit/sigit
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
publish-aur-package:
|
|
23
|
+
name: Publish sigit-bin to the AUR
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout
|
|
28
|
+
uses: actions/checkout@v6
|
|
29
|
+
with:
|
|
30
|
+
ref: ${{ github.event.inputs.tag }}
|
|
31
|
+
|
|
32
|
+
- name: Resolve tag and version
|
|
33
|
+
id: release
|
|
34
|
+
shell: bash
|
|
35
|
+
run: |
|
|
36
|
+
TAG="${{ github.event.inputs.tag }}"
|
|
37
|
+
VERSION="${TAG#v}"
|
|
38
|
+
|
|
39
|
+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
40
|
+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
41
|
+
|
|
42
|
+
- name: Read SHA256 checksums from release
|
|
43
|
+
id: sha
|
|
44
|
+
env:
|
|
45
|
+
GH_TOKEN: ${{ github.token }}
|
|
46
|
+
shell: bash
|
|
47
|
+
run: |
|
|
48
|
+
mkdir -p artifacts
|
|
49
|
+
|
|
50
|
+
gh release download "${{ steps.release.outputs.tag }}" \
|
|
51
|
+
--repo "${{ env.REPO }}" \
|
|
52
|
+
--pattern "sigit-linux-*.sha256" \
|
|
53
|
+
--dir artifacts/
|
|
54
|
+
|
|
55
|
+
X86_64_SHA=$(cat artifacts/sigit-linux-amd64.sha256)
|
|
56
|
+
AARCH64_SHA=$(cat artifacts/sigit-linux-arm64.sha256)
|
|
57
|
+
|
|
58
|
+
echo "x86_64=${X86_64_SHA}" >> "$GITHUB_OUTPUT"
|
|
59
|
+
echo "aarch64=${AARCH64_SHA}" >> "$GITHUB_OUTPUT"
|
|
60
|
+
|
|
61
|
+
echo "x86_64 SHA256: ${X86_64_SHA}"
|
|
62
|
+
echo "aarch64 SHA256: ${AARCH64_SHA}"
|
|
63
|
+
|
|
64
|
+
- name: Render PKGBUILD
|
|
65
|
+
shell: bash
|
|
66
|
+
run: |
|
|
67
|
+
mkdir -p aur-build
|
|
68
|
+
|
|
69
|
+
sed \
|
|
70
|
+
-e "s/@VERSION@/${{ steps.release.outputs.version }}/g" \
|
|
71
|
+
-e "s/@SHA256_X86_64@/${{ steps.sha.outputs.x86_64 }}/g" \
|
|
72
|
+
-e "s/@SHA256_AARCH64@/${{ steps.sha.outputs.aarch64 }}/g" \
|
|
73
|
+
packaging/aur/PKGBUILD.in > aur-build/PKGBUILD
|
|
74
|
+
|
|
75
|
+
if grep -q '@[A-Z0-9_]*@' aur-build/PKGBUILD; then
|
|
76
|
+
echo "::error::PKGBUILD still contains unsubstituted placeholders" >&2
|
|
77
|
+
grep -n '@[A-Z0-9_]*@' aur-build/PKGBUILD >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Catches an unbalanced quote or paren before it reaches the AUR.
|
|
82
|
+
bash -n aur-build/PKGBUILD
|
|
83
|
+
|
|
84
|
+
echo "Rendered PKGBUILD:"
|
|
85
|
+
cat aur-build/PKGBUILD
|
|
86
|
+
|
|
87
|
+
# The action runs makepkg in an Arch container to generate .SRCINFO and
|
|
88
|
+
# pushes over SSH. Generating .SRCINFO by hand is possible but drifts
|
|
89
|
+
# from the PKGBUILD the moment a field is added.
|
|
90
|
+
- name: Publish to the AUR
|
|
91
|
+
uses: KSXGitHub/github-actions-deploy-aur@v3
|
|
92
|
+
with:
|
|
93
|
+
pkgname: sigit-bin
|
|
94
|
+
pkgbuild: aur-build/PKGBUILD
|
|
95
|
+
commit_username: ${{ secrets.AUR_USERNAME }}
|
|
96
|
+
commit_email: ${{ secrets.AUR_EMAIL }}
|
|
97
|
+
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
|
98
|
+
commit_message: "Update sigit-bin to ${{ steps.release.outputs.version }}"
|
|
99
|
+
updpkgsums: false
|
|
@@ -119,6 +119,87 @@ jobs:
|
|
|
119
119
|
echo "Archive: ${ARCHIVE_NAME}"
|
|
120
120
|
echo "SHA256: $(cat "${ARCHIVE_NAME}.sha256")"
|
|
121
121
|
|
|
122
|
+
# Debian and RPM packages are built from the binary staged above rather
|
|
123
|
+
# than by re-invoking cargo, so each Linux target compiles once and gets
|
|
124
|
+
# packaged twice.
|
|
125
|
+
- name: Build Linux packages
|
|
126
|
+
if: contains(matrix.target, 'linux')
|
|
127
|
+
shell: bash
|
|
128
|
+
env:
|
|
129
|
+
NFPM_VERSION: "2.43.0"
|
|
130
|
+
run: |
|
|
131
|
+
case "$(uname -m)" in
|
|
132
|
+
x86_64) nfpm_arch="x86_64"; export PKG_ARCH="amd64" ;;
|
|
133
|
+
aarch64) nfpm_arch="arm64"; export PKG_ARCH="arm64" ;;
|
|
134
|
+
*) echo "Unsupported Linux build host $(uname -m)" >&2; exit 1 ;;
|
|
135
|
+
esac
|
|
136
|
+
|
|
137
|
+
curl -sSfL \
|
|
138
|
+
"https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_Linux_${nfpm_arch}.tar.gz" \
|
|
139
|
+
| tar -xz -C /tmp nfpm
|
|
140
|
+
|
|
141
|
+
export PKG_VERSION="${RELEASE_VERSION}"
|
|
142
|
+
export PKG_BINARY="./release/${PROJECT_NAME}-${{ matrix.name }}"
|
|
143
|
+
|
|
144
|
+
# An empty version is worse than a hard failure here: nfpm accepts it
|
|
145
|
+
# and silently emits a "0.0.0~rc0" package that would be attached to
|
|
146
|
+
# the release. Same for a missing binary, which only surfaces as an
|
|
147
|
+
# opaque glob error. Fail loudly instead.
|
|
148
|
+
if [ -z "${PKG_VERSION}" ]; then
|
|
149
|
+
echo "RELEASE_VERSION is empty; refusing to build packages" >&2
|
|
150
|
+
exit 1
|
|
151
|
+
fi
|
|
152
|
+
if [ ! -f "${PKG_BINARY}" ]; then
|
|
153
|
+
echo "Staged binary ${PKG_BINARY} not found" >&2
|
|
154
|
+
exit 1
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# nfpm expands ${VAR} in most fields but NOT in contents.src, so the
|
|
158
|
+
# config is rendered up front and nfpm only ever sees literal values.
|
|
159
|
+
# envsubst comes from gettext-base, preinstalled on the Ubuntu runner
|
|
160
|
+
# images. The explicit variable list keeps it from clobbering any
|
|
161
|
+
# other shell-looking text added to the config later.
|
|
162
|
+
if ! command -v envsubst >/dev/null 2>&1; then
|
|
163
|
+
sudo apt-get update && sudo apt-get install -y gettext-base
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
envsubst '${PKG_ARCH} ${PKG_VERSION} ${PKG_BINARY}' \
|
|
167
|
+
< packaging/nfpm.yaml > /tmp/nfpm.rendered.yaml
|
|
168
|
+
|
|
169
|
+
/tmp/nfpm package --config /tmp/nfpm.rendered.yaml --packager deb --target ./release/
|
|
170
|
+
/tmp/nfpm package --config /tmp/nfpm.rendered.yaml --packager rpm --target ./release/
|
|
171
|
+
|
|
172
|
+
# Guard against a packager silently producing nothing.
|
|
173
|
+
for ext in deb rpm; do
|
|
174
|
+
if ! compgen -G "./release/*.${ext}" >/dev/null; then
|
|
175
|
+
echo "No .${ext} produced" >&2
|
|
176
|
+
exit 1
|
|
177
|
+
fi
|
|
178
|
+
done
|
|
179
|
+
|
|
180
|
+
ls -la ./release/
|
|
181
|
+
|
|
182
|
+
# Homebrew has always had a checksum because the tap needs one. Scoop,
|
|
183
|
+
# winget, and the AUR PKGBUILD each need one too, and they consume the
|
|
184
|
+
# raw binaries rather than the macOS tarball, so every asset gets a
|
|
185
|
+
# sidecar. Windows runners use bash from Git for Windows, which has
|
|
186
|
+
# sha256sum; macOS only has shasum.
|
|
187
|
+
- name: Checksum release assets
|
|
188
|
+
shell: bash
|
|
189
|
+
run: |
|
|
190
|
+
cd release
|
|
191
|
+
for asset in *; do
|
|
192
|
+
case "${asset}" in *.sha256) continue ;; esac
|
|
193
|
+
|
|
194
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
195
|
+
sha256sum "${asset}" | awk '{print $1}' > "${asset}.sha256"
|
|
196
|
+
else
|
|
197
|
+
shasum -a 256 "${asset}" | awk '{print $1}' > "${asset}.sha256"
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
echo "${asset}: $(cat "${asset}.sha256")"
|
|
201
|
+
done
|
|
202
|
+
|
|
122
203
|
- name: Upload binary artifact
|
|
123
204
|
uses: actions/upload-artifact@v4
|
|
124
205
|
with:
|
|
@@ -171,17 +252,37 @@ jobs:
|
|
|
171
252
|
tag_name: ${{ steps.tag.outputs.tag }}
|
|
172
253
|
files: release/*
|
|
173
254
|
|
|
174
|
-
|
|
255
|
+
# These channels all publish somewhere outside this repo (a tap, a Scoop
|
|
256
|
+
# bucket, microsoft/winget-pkgs, the AUR) and every one of them reads
|
|
257
|
+
# checksums off the release created above, so they hang off this job
|
|
258
|
+
# rather than firing on the tag directly.
|
|
259
|
+
- name: Trigger OS package manager releases
|
|
175
260
|
uses: actions/github-script@v7
|
|
176
261
|
with:
|
|
177
262
|
script: |
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
263
|
+
const tag = '${{ steps.tag.outputs.tag }}'
|
|
264
|
+
const workflows = [
|
|
265
|
+
'release-homebrew.yml',
|
|
266
|
+
'release-scoop.yml',
|
|
267
|
+
'release-winget.yml',
|
|
268
|
+
// New AUR account registration is temporarily closed
|
|
269
|
+
//'release-aur.yml',
|
|
270
|
+
]
|
|
271
|
+
|
|
272
|
+
for (const workflow_id of workflows) {
|
|
273
|
+
try {
|
|
274
|
+
await github.rest.actions.createWorkflowDispatch({
|
|
275
|
+
owner: context.repo.owner,
|
|
276
|
+
repo: context.repo.repo,
|
|
277
|
+
workflow_id,
|
|
278
|
+
ref: 'main',
|
|
279
|
+
inputs: { tag },
|
|
280
|
+
})
|
|
281
|
+
console.log(`Dispatched ${workflow_id} for tag ${tag}`)
|
|
282
|
+
} catch (error) {
|
|
283
|
+
// One packaging channel being unconfigured (a missing secret,
|
|
284
|
+
// a bucket repo that does not exist yet) should not take the
|
|
285
|
+
// rest of the fan-out down with it.
|
|
286
|
+
core.warning(`Failed to dispatch ${workflow_id}: ${error.message}`)
|
|
185
287
|
}
|
|
186
|
-
}
|
|
187
|
-
console.log('Dispatched release-homebrew.yml for tag ${{ steps.tag.outputs.tag }}')
|
|
288
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
name: NuGet Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
tag:
|
|
10
|
+
description: "Release tag (e.g. v1.5.2)"
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
CARGO_TERM_COLOR: always
|
|
18
|
+
DOTNET_VERSION: 8.0.x
|
|
19
|
+
NUGET_PACKAGE_ID: SiGit.Code
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
build-native-binaries:
|
|
23
|
+
name: Build native binary (${{ matrix.build.NAME }})
|
|
24
|
+
runs-on: ${{ matrix.build.OS }}
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
build:
|
|
29
|
+
- {
|
|
30
|
+
NAME: linux-x64,
|
|
31
|
+
OS: ubuntu-latest,
|
|
32
|
+
TARGET: x86_64-unknown-linux-gnu,
|
|
33
|
+
}
|
|
34
|
+
- {
|
|
35
|
+
NAME: linux-arm64,
|
|
36
|
+
OS: ubuntu-24.04-arm,
|
|
37
|
+
TARGET: aarch64-unknown-linux-gnu,
|
|
38
|
+
}
|
|
39
|
+
- {
|
|
40
|
+
NAME: windows-x64,
|
|
41
|
+
OS: windows-2022,
|
|
42
|
+
TARGET: x86_64-pc-windows-msvc,
|
|
43
|
+
}
|
|
44
|
+
- {
|
|
45
|
+
NAME: windows-arm64,
|
|
46
|
+
OS: windows-2022,
|
|
47
|
+
TARGET: aarch64-pc-windows-msvc,
|
|
48
|
+
}
|
|
49
|
+
- { NAME: darwin-x64, OS: macos-26, TARGET: x86_64-apple-darwin }
|
|
50
|
+
- { NAME: darwin-arm64, OS: macos-26, TARGET: aarch64-apple-darwin }
|
|
51
|
+
steps:
|
|
52
|
+
- name: Checkout
|
|
53
|
+
uses: actions/checkout@v6
|
|
54
|
+
with:
|
|
55
|
+
ref: ${{ github.event.inputs.tag || github.ref }}
|
|
56
|
+
|
|
57
|
+
- name: Read Rust toolchain
|
|
58
|
+
shell: bash
|
|
59
|
+
run: |
|
|
60
|
+
rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
|
|
61
|
+
if [ -z "$rust_toolchain" ]; then
|
|
62
|
+
echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
|
|
66
|
+
|
|
67
|
+
- name: Install Rust toolchain
|
|
68
|
+
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
|
|
69
|
+
with:
|
|
70
|
+
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
71
|
+
|
|
72
|
+
- name: Install Rust target
|
|
73
|
+
shell: bash
|
|
74
|
+
run: |
|
|
75
|
+
rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }}
|
|
76
|
+
rustup target list --installed
|
|
77
|
+
|
|
78
|
+
- name: Setup Rust cache
|
|
79
|
+
uses: Swatinem/rust-cache@v2
|
|
80
|
+
with:
|
|
81
|
+
key: nuget-${{ matrix.build.TARGET }}
|
|
82
|
+
|
|
83
|
+
- name: Build binary
|
|
84
|
+
shell: bash
|
|
85
|
+
run: cargo build --locked --release --target ${{ matrix.build.TARGET }}
|
|
86
|
+
|
|
87
|
+
- name: Prepare artifact
|
|
88
|
+
shell: bash
|
|
89
|
+
run: |
|
|
90
|
+
executable_name="sigit"
|
|
91
|
+
if [[ "${{ matrix.build.OS }}" == "windows-2022" ]]; then
|
|
92
|
+
executable_name="sigit.exe"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
mkdir -p "nuget-artifacts/native/${{ matrix.build.NAME }}"
|
|
96
|
+
cp "target/${{ matrix.build.TARGET }}/release/${executable_name}" \
|
|
97
|
+
"nuget-artifacts/native/${{ matrix.build.NAME }}/${executable_name}"
|
|
98
|
+
|
|
99
|
+
- name: Upload native artifact
|
|
100
|
+
uses: actions/upload-artifact@v4
|
|
101
|
+
with:
|
|
102
|
+
name: nuget-native-${{ matrix.build.NAME }}
|
|
103
|
+
path: nuget-artifacts/native
|
|
104
|
+
|
|
105
|
+
pack-nuget:
|
|
106
|
+
name: Pack NuGet .NET tool
|
|
107
|
+
runs-on: ubuntu-latest
|
|
108
|
+
needs: build-native-binaries
|
|
109
|
+
steps:
|
|
110
|
+
- name: Checkout
|
|
111
|
+
uses: actions/checkout@v6
|
|
112
|
+
with:
|
|
113
|
+
ref: ${{ github.event.inputs.tag || github.ref }}
|
|
114
|
+
|
|
115
|
+
- name: Set the release version
|
|
116
|
+
shell: bash
|
|
117
|
+
run: |
|
|
118
|
+
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
|
119
|
+
release_version="${GITHUB_REF_NAME#v}"
|
|
120
|
+
else
|
|
121
|
+
release_version="${{ github.event.inputs.tag }}"
|
|
122
|
+
release_version="${release_version#v}"
|
|
123
|
+
fi
|
|
124
|
+
echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
|
|
125
|
+
|
|
126
|
+
- name: Download native artifacts
|
|
127
|
+
uses: actions/download-artifact@v4
|
|
128
|
+
with:
|
|
129
|
+
pattern: nuget-native-*
|
|
130
|
+
path: nuget/sigit/native
|
|
131
|
+
merge-multiple: true
|
|
132
|
+
|
|
133
|
+
- name: Setup .NET SDK
|
|
134
|
+
uses: actions/setup-dotnet@v4
|
|
135
|
+
with:
|
|
136
|
+
dotnet-version: ${{ env.DOTNET_VERSION }}
|
|
137
|
+
|
|
138
|
+
- name: Pack .NET tool
|
|
139
|
+
shell: bash
|
|
140
|
+
run: |
|
|
141
|
+
dotnet pack nuget/sigit/SiGit.Code.csproj \
|
|
142
|
+
--configuration Release \
|
|
143
|
+
--output nuget/dist \
|
|
144
|
+
-p:PackageVersion=${RELEASE_VERSION}
|
|
145
|
+
|
|
146
|
+
# All six binaries ship in one package, so this sits closer to nuget.org's
|
|
147
|
+
# 250 MB ceiling than the single-platform npm and PyPI artifacts do. Fail
|
|
148
|
+
# here with a clear message rather than at `dotnet nuget push`, where the
|
|
149
|
+
# error is just "the package file exceeds the size limit".
|
|
150
|
+
- name: Check package size against the NuGet limit
|
|
151
|
+
shell: bash
|
|
152
|
+
run: |
|
|
153
|
+
package="$(ls nuget/dist/*.nupkg | head -n 1)"
|
|
154
|
+
size_bytes="$(wc -c < "${package}")"
|
|
155
|
+
limit_bytes=$((250 * 1024 * 1024))
|
|
156
|
+
|
|
157
|
+
echo "Package: ${package}"
|
|
158
|
+
echo "Size: $((size_bytes / 1024 / 1024)) MiB"
|
|
159
|
+
|
|
160
|
+
if [ "${size_bytes}" -gt "${limit_bytes}" ]; then
|
|
161
|
+
echo "::error::${package} is over nuget.org's 250 MB package limit. Split the tool into RID-specific packages (.NET 10 DotnetToolRidPackage) instead of bundling every target." >&2
|
|
162
|
+
exit 1
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
- name: Upload package artifact
|
|
166
|
+
uses: actions/upload-artifact@v4
|
|
167
|
+
with:
|
|
168
|
+
name: nuget-package
|
|
169
|
+
path: nuget/dist/*.nupkg
|
|
170
|
+
|
|
171
|
+
smoke-test:
|
|
172
|
+
name: Smoke test (${{ matrix.os }})
|
|
173
|
+
runs-on: ${{ matrix.os }}
|
|
174
|
+
needs: pack-nuget
|
|
175
|
+
strategy:
|
|
176
|
+
fail-fast: false
|
|
177
|
+
matrix:
|
|
178
|
+
os:
|
|
179
|
+
- ubuntu-latest
|
|
180
|
+
- windows-2022
|
|
181
|
+
- macos-26
|
|
182
|
+
steps:
|
|
183
|
+
- name: Checkout
|
|
184
|
+
uses: actions/checkout@v6
|
|
185
|
+
with:
|
|
186
|
+
ref: ${{ github.event.inputs.tag || github.ref }}
|
|
187
|
+
|
|
188
|
+
- name: Set the release version
|
|
189
|
+
shell: bash
|
|
190
|
+
run: |
|
|
191
|
+
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
|
192
|
+
release_version="${GITHUB_REF_NAME#v}"
|
|
193
|
+
else
|
|
194
|
+
release_version="${{ github.event.inputs.tag }}"
|
|
195
|
+
release_version="${release_version#v}"
|
|
196
|
+
fi
|
|
197
|
+
echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
|
|
198
|
+
|
|
199
|
+
- name: Download package artifact
|
|
200
|
+
uses: actions/download-artifact@v4
|
|
201
|
+
with:
|
|
202
|
+
name: nuget-package
|
|
203
|
+
path: nuget/dist
|
|
204
|
+
|
|
205
|
+
- name: Setup .NET SDK
|
|
206
|
+
uses: actions/setup-dotnet@v4
|
|
207
|
+
with:
|
|
208
|
+
dotnet-version: ${{ env.DOTNET_VERSION }}
|
|
209
|
+
|
|
210
|
+
- name: Install tool from local package
|
|
211
|
+
shell: pwsh
|
|
212
|
+
run: |
|
|
213
|
+
$packageSource = (Resolve-Path "nuget/dist").Path
|
|
214
|
+
@"
|
|
215
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
216
|
+
<configuration>
|
|
217
|
+
<packageSources>
|
|
218
|
+
<clear />
|
|
219
|
+
<add key="local" value="$packageSource" />
|
|
220
|
+
</packageSources>
|
|
221
|
+
</configuration>
|
|
222
|
+
"@ | Set-Content -Path "nuget/NuGet.Config"
|
|
223
|
+
|
|
224
|
+
dotnet tool install `
|
|
225
|
+
--tool-path ".tool" `
|
|
226
|
+
--configfile "nuget/NuGet.Config" `
|
|
227
|
+
--version "$env:RELEASE_VERSION" `
|
|
228
|
+
"$env:NUGET_PACKAGE_ID"
|
|
229
|
+
|
|
230
|
+
- name: Verify bundled native binary
|
|
231
|
+
shell: pwsh
|
|
232
|
+
run: |
|
|
233
|
+
$runtimeIdentifier = if ($IsWindows) {
|
|
234
|
+
if ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) { "windows-arm64" } else { "windows-x64" }
|
|
235
|
+
} elseif ($IsMacOS) {
|
|
236
|
+
if ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) { "darwin-arm64" } else { "darwin-x64" }
|
|
237
|
+
} else {
|
|
238
|
+
if ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) { "linux-arm64" } else { "linux-x64" }
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
$binaryName = if ($IsWindows) { "sigit.exe" } else { "sigit" }
|
|
242
|
+
$nativeBinary = Get-ChildItem ".tool/.store" -Recurse -File | Where-Object {
|
|
243
|
+
$_.FullName -like "*native*${runtimeIdentifier}*${binaryName}"
|
|
244
|
+
} | Select-Object -First 1
|
|
245
|
+
|
|
246
|
+
if (-not $nativeBinary) {
|
|
247
|
+
Write-Error "The sigit native binary for ${runtimeIdentifier} was not bundled in the installed .NET tool package."
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
Write-Host "Found bundled native binary at $($nativeBinary.FullName)"
|
|
251
|
+
|
|
252
|
+
publish-nuget:
|
|
253
|
+
name: Publish to NuGet
|
|
254
|
+
runs-on: ubuntu-latest
|
|
255
|
+
needs: smoke-test
|
|
256
|
+
# Trusted Publishing exchanges a GitHub OIDC token for a short-lived NuGet
|
|
257
|
+
# API key, so no long-lived NUGET_API_KEY secret is stored. Requires the
|
|
258
|
+
# `sigit-nuget` trusted publisher policy on nuget.org (owner getsigit, repo
|
|
259
|
+
# sigit, workflow release-nuget.yml).
|
|
260
|
+
permissions:
|
|
261
|
+
contents: read
|
|
262
|
+
id-token: write
|
|
263
|
+
steps:
|
|
264
|
+
- name: Set the release version
|
|
265
|
+
shell: bash
|
|
266
|
+
run: |
|
|
267
|
+
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
|
268
|
+
release_version="${GITHUB_REF_NAME#v}"
|
|
269
|
+
else
|
|
270
|
+
release_version="${{ github.event.inputs.tag }}"
|
|
271
|
+
release_version="${release_version#v}"
|
|
272
|
+
fi
|
|
273
|
+
echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
|
|
274
|
+
|
|
275
|
+
- name: Download package artifact
|
|
276
|
+
uses: actions/download-artifact@v4
|
|
277
|
+
with:
|
|
278
|
+
name: nuget-package
|
|
279
|
+
path: nuget/dist
|
|
280
|
+
|
|
281
|
+
- name: Setup .NET SDK
|
|
282
|
+
uses: actions/setup-dotnet@v4
|
|
283
|
+
with:
|
|
284
|
+
dotnet-version: ${{ env.DOTNET_VERSION }}
|
|
285
|
+
|
|
286
|
+
- name: Check whether release already exists on NuGet
|
|
287
|
+
id: nuget-check
|
|
288
|
+
shell: bash
|
|
289
|
+
run: |
|
|
290
|
+
package_index_url="https://api.nuget.org/v3-flatcontainer/sigit.code/index.json"
|
|
291
|
+
if curl -fsS "${package_index_url}" | grep -F "\"${RELEASE_VERSION}\"" >/dev/null; then
|
|
292
|
+
echo "${NUGET_PACKAGE_ID} ${RELEASE_VERSION} already exists on NuGet, skipping publish"
|
|
293
|
+
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
294
|
+
else
|
|
295
|
+
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
296
|
+
fi
|
|
297
|
+
|
|
298
|
+
# Exchange the workflow's OIDC token for a short-lived NuGet API key. The
|
|
299
|
+
# key is written to the environment for the subsequent `dotnet nuget push`
|
|
300
|
+
# via the NUGET_API_KEY variable this action sets.
|
|
301
|
+
- name: NuGet trusted-publishing login
|
|
302
|
+
if: steps.nuget-check.outputs.exists != 'true'
|
|
303
|
+
uses: NuGet/login@v1
|
|
304
|
+
id: nuget-login
|
|
305
|
+
with:
|
|
306
|
+
user: setoelkahfi
|
|
307
|
+
|
|
308
|
+
- name: Publish package
|
|
309
|
+
if: steps.nuget-check.outputs.exists != 'true'
|
|
310
|
+
shell: bash
|
|
311
|
+
run: |
|
|
312
|
+
dotnet nuget push nuget/dist/*.nupkg \
|
|
313
|
+
--api-key "${{ steps.nuget-login.outputs.NUGET_API_KEY }}" \
|
|
314
|
+
--source https://api.nuget.org/v3/index.json \
|
|
315
|
+
--skip-duplicate
|