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
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{".":"1.8.0"}
{".":"1.9.0"}
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [1.9.0](https://github.com/unraid/ci-runner-farm/compare/v1.8.0...v1.9.0) (2026-08-06)


### Features

* add GitLab runner provider ([#44](https://github.com/unraid/ci-runner-farm/issues/44)) ([ae09e32](https://github.com/unraid/ci-runner-farm/commit/ae09e3256a5e5fc1c69ccb524c0bbdb5207a95da))

## [1.8.0](https://github.com/unraid/ci-runner-farm/compare/v1.7.0...v1.8.0) (2026-07-30)


Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.8.0
1.9.0
98 changes: 77 additions & 21 deletions ci-runner-farm.plg
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
<!DOCTYPE PLUGIN [
<!ENTITY name "ci-runner-farm">
<!ENTITY author "Lime Technology">
<!ENTITY version "2026.07.30.2209.38-1.8.0">
<!ENTITY pluginVersion "1.8.0">
<!ENTITY releaseTag "v1.8.0">
<!ENTITY version "2026.08.06.1344.40-1.9.0">
<!ENTITY pluginVersion "1.9.0">
<!ENTITY releaseTag "v1.9.0">
<!ENTITY pluginURL "https://github.com/unraid/ci-runner-farm/releases/latest/download/ci-runner-farm.plg">
<!ENTITY packageName "ci-runner-farm-2026.07.30.2209.38-1.8.0.tgz">
<!ENTITY packageURL "https://github.com/unraid/ci-runner-farm/releases/download/v1.8.0/ci-runner-farm-2026.07.30.2209.38-1.8.0.tgz">
<!ENTITY packageMD5 "cbce9faac2adbc721bdaebe389105527">
<!ENTITY packageName "ci-runner-farm-2026.08.06.1344.40-1.9.0.tgz">
<!ENTITY packageURL "https://github.com/unraid/ci-runner-farm/releases/download/v1.9.0/ci-runner-farm-2026.08.06.1344.40-1.9.0.tgz">
<!ENTITY packageMD5 "2e9d7e649a921c3e2ad78eb02adb20ea">
<!ENTITY plgdir "/usr/local/emhttp/plugins/&name;">
<!ENTITY cfgdir "/boot/config/plugins/&name;">
]>
Expand All @@ -23,7 +23,7 @@
<CHANGES>
### &version;
### Features
* **auth:** add PAT scope presets ([#42](https://github.com/unraid/ci-runner-farm/issues/42)) ([15f073e](https://github.com/unraid/ci-runner-farm/commit/15f073efe45d5874f2dd05cf17802bfee102484a))
* add GitLab runner provider ([#44](https://github.com/unraid/ci-runner-farm/issues/44)) ([ae09e32](https://github.com/unraid/ci-runner-farm/commit/ae09e3256a5e5fc1c69ccb524c0bbdb5207a95da))
</CHANGES>

<!-- plugin package: Unraid downloads it to flash and verifies the MD5 -->
Expand All @@ -40,11 +40,11 @@ PLGDIR="/usr/local/emhttp/plugins/ci-runner-farm"
CFGDIR="/boot/config/plugins/ci-runner-farm"
mkdir -p "$CFGDIR" "$PLGDIR"
# Sweep any older package versions off flash, keeping this build's package.
find "$CFGDIR" -maxdepth 1 -name 'ci-runner-farm-*.tgz' ! -name 'ci-runner-farm-2026.07.30.2209.38-1.8.0.tgz' -delete 2>/dev/null || true
find "$CFGDIR" -maxdepth 1 -name 'ci-runner-farm-*.tgz' ! -name 'ci-runner-farm-2026.08.06.1344.40-1.9.0.tgz' -delete 2>/dev/null || true
# Extract ONLY into the plugin dir; --no-same-owner forces root ownership;
# --no-overwrite-dir leaves existing dir metadata alone. System dirs untouched.
# The .tgz is kept on flash so the on-boot reinstall works without a download.
tar -xzf "$CFGDIR/ci-runner-farm-2026.07.30.2209.38-1.8.0.tgz" --no-same-owner --no-overwrite-dir -C "$PLGDIR"
tar -xzf "$CFGDIR/ci-runner-farm-2026.08.06.1344.40-1.9.0.tgz" --no-same-owner --no-overwrite-dir -C "$PLGDIR"
chown -R root:root "$PLGDIR"
find "$PLGDIR" -type d -exec chmod 0755 {} +
find "$PLGDIR" -type f -exec chmod 0644 {} +
Expand All @@ -54,15 +54,26 @@ chmod 0755 "$PLGDIR/include/runner-farm.sh"
[ -d "$PLGDIR/event" ] && find "$PLGDIR/event" -type f -exec chmod 0755 {} +
# Config defaults are NOT seeded to flash — the settings page and runner-farm.sh
# both fall back to built-in defaults, so flash only ever holds what the user set.
[ -f "$CFGDIR/Dockerfile" ] || cp "$PLGDIR/default.Dockerfile" "$CFGDIR/Dockerfile"
# Migrate saved Dockerfiles seeded before the cache-ownership fix: without
# Provider-specific editable Dockerfiles keep a GitLab job-image build from
# replacing a customized GitHub runner image (and vice versa). Existing installs
# used the unsuffixed Dockerfile; copy it forward once as the GitHub source while
# retaining the old file as a compatibility/downgrade fallback.
if [ ! -f "$CFGDIR/Dockerfile.github" ]; then
if [ -f "$CFGDIR/Dockerfile" ]; then
cp "$CFGDIR/Dockerfile" "$CFGDIR/Dockerfile.github"
else
cp "$PLGDIR/default.github.Dockerfile" "$CFGDIR/Dockerfile.github"
fi
fi
[ -f "$CFGDIR/Dockerfile.gitlab" ] || cp "$PLGDIR/default.gitlab.Dockerfile" "$CFGDIR/Dockerfile.gitlab"
# Migrate GitHub Dockerfiles seeded before the cache-ownership fix: without
# runner-owned CACHE_MOUNTS destinations baked into the image, Docker's
# bind-mount auto-creation leaves root-owned parents and a non-root runner
# fails writing beside them (rustup: "could not create bin directory
# '/home/runner/.cargo/bin'"). Patch only files that still carry the stock
# packages marker and lack the fix; customized files without the marker get a
# notice instead.
DF="$CFGDIR/Dockerfile"
DF="$CFGDIR/Dockerfile.github"
if [ -f "$DF" ] && ! grep -q 'mkdir -p /home/runner/.cargo/registry' "$DF"; then
if grep -q '^# && rm -rf /var/lib/apt/lists/\*' "$DF"; then
BLK=$(mktemp)
Expand All @@ -82,33 +93,78 @@ EOF_CACHEDIRS
rm -f "$BLK"
echo "ci-runner-farm: patched saved Dockerfile to pre-create runner-owned cache dirs (press Build to rebuild the runner image)."
else
echo "ci-runner-farm: NOTE - saved $DF lacks the runner-owned cache-dir block from default.Dockerfile; merge it manually so non-root runners can write beside the cache mounts."
echo "ci-runner-farm: NOTE - saved $DF lacks the runner-owned cache-dir block from default.github.Dockerfile; merge it manually so non-root runners can write beside the cache mounts."
fi
fi
( docker pull myoung34/github-runner:latest >/dev/null 2>&1 & ) || true
( docker pull gitlab/gitlab-runner:alpine >/dev/null 2>&1 & ) || true
# Bring the fleet + autoscaler up. Runs on manual install AND on every boot
# (rc.local reinstalls plugins), detached so it waits for dockerd+array without
# blocking. No-op until a GitHub token is configured.
# blocking. No-op until the selected provider's runner token is configured.
( nohup "$PLGDIR/include/runner-farm.sh" boot-autostart >>"$CFGDIR/boot.log" 2>&1 & ) || true
echo ""
echo "+=============================================================+"
echo "| ci-runner-farm 2026.07.30.2209.38-1.8.0 installed. "
echo "| ci-runner-farm 2026.08.06.1344.40-1.9.0 installed. "
echo "| Settings > Utilities > CI Runner Farm "
echo "| Set a GitHub PAT, then Start (or Validate without a token). "
echo "| Select GitHub or GitLab, save its token, then Start. "
echo "+=============================================================+"
]]></INLINE>
</FILE>

<!-- remove -->
<FILE Run="/bin/bash" Method="remove">
<INLINE><![CDATA[
set -euo pipefail
PLGDIR="/usr/local/emhttp/plugins/ci-runner-farm"
CFGDIR="/boot/config/plugins/ci-runner-farm"
"$PLGDIR/include/runner-farm.sh" stop 2>/dev/null || true
rm -rf "$PLGDIR"
# The downloaded package is just a cache; drop it. Config + token stay.
rm -f "$CFGDIR"/ci-runner-farm-*.tgz
echo "ci-runner-farm removed. Config + token left in /boot/config/plugins/ci-runner-farm (delete manually to purge)."
ENGINE="$PLGDIR/include/runner-farm.sh"
if [ -x "$ENGINE" ]; then
if ! "$PLGDIR/include/runner-farm.sh" stop >>"$CFGDIR/boot.log" 2>&1; then
echo "ci-runner-farm NOT removed: one or more runners, jobs, or privileged sidecars could not be stopped safely." >&2
echo "Review $CFGDIR/boot.log, retry Stop, or use the separately confirmed local-forget recovery action if GitLab is permanently unreachable." >&2
exit 1
fi
else
# A partially deleted runtime cannot perform the normal ownership-verified
# teardown. Never interpret that as an empty farm: prove through Docker that
# no plugin-labelled manager, validation container, privileged DinD sidecar,
# host-socket executor workload, or registry mirror survives before allowing
# the remaining package files to be removed.
command -v docker >/dev/null 2>&1 || {
echo "ci-runner-farm NOT removed: cleanup engine is missing and Docker is unavailable, so owned runtime resources cannot be enumerated." >&2
echo "Start Docker or restore the plugin runtime, then retry removal." >&2
exit 1
}
owned_runtime=""
for filter in 'label=net.unraid.ci-runner-farm.managed=true' 'label=net.unraid.ci-runner-farm.sidecar=true' 'label=net.unraid.ci-runner-farm.role=mirror'
do
if ! ids=$(docker ps -aq --filter "$filter" 2>/dev/null); then
echo "ci-runner-farm NOT removed: cleanup engine is missing and Docker ownership enumeration failed." >&2
exit 1
fi
[ -z "$ids" ] || owned_runtime="${owned_runtime}${ids} "
done
if ! ids=$(docker ps -aq --filter 'label=com.gitlab.gitlab-runner.managed=true' --filter 'label=net.unraid.ci-runner-farm.provider=gitlab' 2>/dev/null); then
echo "ci-runner-farm NOT removed: cleanup engine is missing and GitLab executor ownership enumeration failed." >&2
exit 1
fi
[ -z "$ids" ] || owned_runtime="${owned_runtime}${ids} "
if [ -n "$owned_runtime" ]; then
echo "ci-runner-farm NOT removed: the cleanup engine is missing while plugin-owned Docker resources still exist." >&2
echo "Restore the plugin runtime, then retry removal so those resources can be stopped safely." >&2
exit 1
fi
fi
if ! rm -rf -- "$PLGDIR" || [ -e "$PLGDIR" ]; then
echo "ci-runner-farm NOT fully removed: failed to delete the installed runtime at $PLGDIR." >&2
exit 1
fi
# The downloaded package is just a cache; drop it. Config + credentials stay.
if ! rm -f -- "$CFGDIR"/ci-runner-farm-*.tgz; then
echo "ci-runner-farm NOT fully removed: runtime cleanup succeeded, but a cached package could not be deleted from $CFGDIR." >&2
exit 1
fi
echo "ci-runner-farm removed. Config + credentials left in /boot/config/plugins/ci-runner-farm (delete manually to purge)."
]]></INLINE>
</FILE>

Expand Down