corrections
8740f46 · gmorell · 2026-05-22 14:45
Files changed
modified
lib/git_gud/workflows.ex
+10
−1
@@ -239,11 +239,20 @@ defmodule GitGud.Workflows do
| 239 | 239 | def claim_next_job(_runner), do: nil |
| 240 | 240 | |
| 241 | 241 | defp do_claim_next_job(%Runner{id: rid} = runner, labels) do |
| 242 | + # GitHub-Actions semantics: `runs-on: self-hosted` matches any | |
| 243 | + # self-registered runner regardless of OS label. So if the runner | |
| 244 | + # was minted via `Runners.create_offline/2` we implicitly add | |
| 245 | + # `self-hosted` to the match set for the query. Operators who want | |
| 246 | + # strict label matching can still register a runner without the | |
| 247 | + # `self-hosted` label — but everything created via this codebase | |
| 248 | + # is by definition self-hosted, so the implicit wildcard is safe. | |
| 249 | + match_labels = if "self-hosted" in labels, do: labels, else: ["self-hosted" | labels] | |
| 250 | + | |
| 242 | 251 | Repo.transaction(fn -> |
| 243 | 252 | job = |
| 244 | 253 | scoped_job_query(runner) |
| 245 | 254 | |> where([j], j.status == "queued") |
| 246 | − |> where([j], fragment("(?->>'value') = ANY(?)", j.runs_on, ^labels)) | |
| 255 | + |> where([j], fragment("(?->>'value') = ANY(?)", j.runs_on, ^match_labels)) | |
| 247 | 256 | |> order_by([j], asc: j.id) |
| 248 | 257 | |> limit(1) |
| 249 | 258 | |> lock("FOR UPDATE SKIP LOCKED") |
modified
lib/git_gud_web/controllers/runner_controller.ex
+11
−1
@@ -130,9 +130,19 @@ defmodule GitGudWeb.RunnerController do
| 130 | 130 | %RunnerSchema{} = runner <- authenticate(conn) do |
| 131 | 131 | _ = Runners.touch_last_seen(runner) |
| 132 | 132 | |
| 133 | + # `tasks_version` MUST be non-zero on the wire — proto3 elides | |
| 134 | + # default values, so `tasks_version: 0` yields a 0-byte | |
| 135 | + # `FetchTaskResponse`. Connect-Go (the version `runner:12` | |
| 136 | + # links against) decodes empty unary bodies as "method not | |
| 137 | + # implemented" and surfaces it to the runner as | |
| 138 | + # `unimplemented: 404 Not Found` even though the HTTP status | |
| 139 | + # was 200. Echoing `tv + 1` matches Forgejo's reference impl | |
| 140 | + # — they keep the counter monotonic across "no work" polls | |
| 141 | + # too. The runner persists the highest value it's seen, so | |
| 142 | + # bumping on every reply is safe even when there's no job. | |
| 133 | 143 | case Workflows.claim_next_job(runner) do |
| 134 | 144 | nil -> |
| 135 | − respond(conn, %FetchTaskResponse{task: nil, tasks_version: tv}) | |
| 145 | + respond(conn, %FetchTaskResponse{task: nil, tasks_version: tv + 1}) | |
| 136 | 146 | |
| 137 | 147 | job -> |
| 138 | 148 | task = build_task(job) |
modified
lib/git_gud_web/live/org_live/settings_runners.ex
+1
−1
@@ -142,7 +142,7 @@ defmodule GitGudWeb.OrgLive.SettingsRunners do
| 142 | 142 | <input |
| 143 | 143 | type="text" |
| 144 | 144 | name="labels" |
| 145 | − value="ubuntu-latest" | |
| 145 | + value="self-hosted,ubuntu-latest" | |
| 146 | 146 | class="input input-sm input-bordered w-full font-mono" |
| 147 | 147 | /> |
| 148 | 148 | </label> |
modified
lib/git_gud_web/live/repo_live/settings_runners.ex
+1
−1
@@ -173,7 +173,7 @@ defmodule GitGudWeb.RepoLive.SettingsRunners do
| 173 | 173 | <input |
| 174 | 174 | type="text" |
| 175 | 175 | name="labels" |
| 176 | − value="ubuntu-latest" | |
| 176 | + value="self-hosted,ubuntu-latest" | |
| 177 | 177 | class="input input-sm input-bordered w-full font-mono" |
| 178 | 178 | /> |
| 179 | 179 | </label> |
Parents: 8f35827