Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5168175
feat: Forgejo backend with one-job runners on proxmox Linux VMs
jfro Oct 18, 2026
89f177c
feat: destroy Forgejo runners whose job never starts
jfro Oct 18, 2026
cd27340
fix: grace period before a runner with a missing VM counts as lost
jfro Oct 18, 2026
42d2192
docs: required_labels applies to every forge
jfro Oct 18, 2026
62df3e1
fix: Forgejo startup check needs runner write access; e2e results
jfro Oct 18, 2026
02b6c9d
feat: publish forgejo-runner builds for every platform on kuiper-forge
jfro Oct 18, 2026
a180d8c
feat: Forgejo jobs on tart (macOS) agents and proxmox Windows VMs
jfro Oct 18, 2026
b4b8079
Merge origin/main into feat/forgejo-backend
jfro Oct 20, 2026
7e00791
feat: Forgejo user (@name) and instance (*) runner scopes
jfro Oct 20, 2026
7e0bf9f
fix: [runner_scope] only required in fixed-capacity mode
jfro Oct 20, 2026
d8ac0ea
docs: macOS Forgejo runner confirmed on a real tart host
jfro Oct 20, 2026
d3ec76b
docs: table Windows runners, Forgejo 17 webhooks and Gitea until afte…
jfro Oct 20, 2026
5417dec
fix(proxmox): only destroy a VM while its VMID still belongs to it
jfro Oct 20, 2026
8096b49
fix(proxmox): SSH keepalive, and stop waiting on a runner whose VM is…
jfro Oct 20, 2026
b159eaf
fix(agents): keep runner tokens out of SSH debug logs
jfro Oct 20, 2026
c9288ce
ci(forgejo-runner): pass the version input through env, pin setup-go
jfro Oct 20, 2026
a9a1f17
fix(forgejo): page runners until an empty page
jfro Oct 20, 2026
5f8acd2
fix(auth): read max_vms as i32 so listing agents works on Postgres
jfro Oct 20, 2026
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
116 changes: 116 additions & 0 deletions .github/workflows/forgejo-runner.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Publishes forgejo-runner builds for kuiper's agents. Upstream only releases Linux
# binaries; this cross-compiles the unmodified upstream tag for every platform the
# agents run Forgejo jobs on, so all of them download one pinned version from here.
#
# Release: push a tag like forgejo-runner-v13.2.0, or run the workflow by hand with
# the version. forgejo-runner is GPLv3, so each release also carries the upstream
# source archive it was built from and the license.
name: forgejo-runner

on:
push:
tags:
- "forgejo-runner-v*"
workflow_dispatch:
inputs:
version:
description: "forgejo-runner version to build (e.g. 13.2.0, at least 13.1.0)"
required: true

permissions:
contents: write

jobs:
build:
name: Build and release
runs-on: ubuntu-latest
steps:
- name: Version
id: version
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
if [ -n "$INPUT_VERSION" ]; then
VERSION="$INPUT_VERSION"
else
VERSION="${GITHUB_REF_NAME#forgejo-runner-v}"
fi
VERSION="${VERSION#v}"
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid version '$VERSION'"; exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=forgejo-runner-v$VERSION" >> "$GITHUB_OUTPUT"

- name: Fetch upstream source
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
SRC="forgejo-runner-${VERSION}-source.tar.gz"
curl -fsSL --retry 3 -o "$SRC" "https://code.forgejo.org/forgejo/runner/archive/v${VERSION}.tar.gz"
mkdir src
tar xzf "$SRC" -C src --strip-components=1
cp src/LICENSE LICENSE-forgejo-runner
head -1 src/go.mod

- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: src/go.mod
cache: false

- name: Build
env:
VERSION: ${{ steps.version.outputs.version }}
working-directory: src
run: |
set -euo pipefail
MODULE="$(awk '/^module /{print $2}' go.mod)"
mkdir -p ../dist
for target in linux/amd64 linux/arm64 darwin/arm64 darwin/amd64 windows/amd64; do
os="${target%/*}"; arch="${target#*/}"
ext=""; [ "$os" = windows ] && ext=".exe"
out="../dist/forgejo-runner-${VERSION}-${os}-${arch}${ext}"
echo "Building $out"
CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" go build -trimpath -tags 'netgo osusergo' \
-ldflags "-s -w -X ${MODULE}/internal/pkg/ver.version=v${VERSION}" -o "$out" .
done
../dist/forgejo-runner-${VERSION}-linux-amd64 --version

- name: Checksums
working-directory: dist
run: |
set -euo pipefail
for f in forgejo-runner-*; do
sha256sum "$f" > "$f.sha256"
done
cat ./*.sha256

- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
VERSION: ${{ steps.version.outputs.version }}
TAG: ${{ steps.version.outputs.tag }}
run: |
set -euo pipefail
cat > notes.md <<NOTES
forgejo-runner v${VERSION} for kuiper agents, built from the unmodified upstream tag
[v${VERSION}](https://code.forgejo.org/forgejo/runner/src/tag/v${VERSION}) with Go
$(go env GOVERSION), \`CGO_ENABLED=0\`, tags \`netgo osusergo\`.

Upstream only publishes Linux binaries and supports Linux; the macOS and Windows
builds here run Forgejo jobs on kuiper's tart and proxmox Windows agents.

forgejo-runner is licensed under the GPLv3 (\`LICENSE-forgejo-runner\`); its source is
attached as \`forgejo-runner-${VERSION}-source.tar.gz\`.
NOTES
files=(dist/* "forgejo-runner-${VERSION}-source.tar.gz" LICENSE-forgejo-runner)
if gh release view "$TAG" >/dev/null 2>&1; then
gh release upload "$TAG" "${files[@]}" --clobber
else
gh release create "$TAG" --target "$GITHUB_SHA" --latest=false \
--title "forgejo-runner v${VERSION}" --notes-file notes.md "${files[@]}"
fi
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ See `examples/` for sample configuration files.

- **Fixed Capacity** (default) - Maintains a constant pool of ready runners, sized per image/template mapping with `pool`
- **Webhook** - Creates runners on-demand via GitHub webhook events
- **Polling** - Creates runners on-demand for queued jobs found by periodically scanning the GitHub API; no inbound webhooks needed
- **Polling** - Creates runners on-demand for queued jobs found by periodically scanning the forges' APIs (GitHub, Forgejo); no inbound webhooks needed

One coordinator can serve several forges via `[[forges]]`. Forgejo support is in progress; see [docs/forge-support.md](docs/forge-support.md).
One coordinator can serve several forges via `[[forges]]`, including Forgejo 15+ in polling mode (one-job runners on proxmox Linux and Windows VMs and tart macOS VMs). See [docs/forge-support.md](docs/forge-support.md).

## Requirements

Expand Down
Loading
Loading