corrections

8740f46 · gmorell · 2026-05-22 14:45

4 files +23 -4

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