Feature: Add per-runner “Disable/Pause” #36776
Conversation
|
Authorship: Reviewed by Codex (GPT-5.3) I reviewed PR #36776 end-to-end (models, migrations, API/web routes, conversion layer, templates, and integration tests) and I did not find any blocking issues. What I validated:
Local checks run:
@silverwind - first review with codex 5.3 😄 |
There was a problem hiding this comment.
Pull request overview
This PR adds a per-runner disable/pause feature for Gitea Actions, allowing admins to stop a registered runner from picking up new jobs without unregistering it. Disabled runners remain registered and online but are excluded from new task assignment; running tasks finish normally. Re-enabling a runner restores task pickup. The feature is exposed via REST API endpoints for all runner scopes (global/admin, org, user, repo) and through the existing web UI runner edit page.
Changes:
- DB migration (#326) adding
is_disabledcolumn toaction_runnertable, with model fieldIsDisabled, andSetRunnerDisabled()function that updates the field and bumps the task version inside a transaction - New
DisableRunner/EnableRunnerAPI endpoints at all four scopes (admin/org/user/repo), with updatedActionRunnerAPI struct exposing adisabledfield and corresponding swagger documentation - Web UI changes adding an enable/disable toggle button to the runner edit page, with a new
actions.runners.availabilitystatus indicator and locale strings
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
models/actions/runner.go |
Adds IsDisabled field and SetRunnerDisabled with transactional update + task version bump |
models/actions/task.go |
Adds IsDisabled guard in CreateTaskForRunner (defense-in-depth) |
models/migrations/v1_26/v326.go + v326_test.go |
DB migration adds is_disabled NOT NULL DEFAULT false column |
models/migrations/migrations.go |
Registers migration 326 |
modules/structs/repo_actions.go |
Adds Disabled bool to ActionRunner API struct |
services/actions/task.go |
Adds IsDisabled early-exit guard in PickTask |
services/actions/interface.go |
Adds DisableRunner/EnableRunner to the API interface |
services/convert/convert.go |
Maps runner.IsDisabled to Disabled in API response |
routers/api/v1/shared/runners.go |
Implements shared updateRunnerDisabled, DisableRunner, EnableRunner |
routers/api/v1/admin/runners.go + org/action.go + repo/action.go + user/runners.go |
Scope-specific handler wrappers with swagger comments |
routers/api/v1/api.go |
Registers PUT /{runner_id}/disable and /{runner_id}/enable routes |
routers/web/shared/actions/runners.go |
Implements web RunnerDisablePost/RunnerEnablePost handlers |
routers/web/web.go |
Registers POST disable/enable web routes; adds devtest runner-edit routes |
routers/web/devtest/runner_edit.go |
Devtest handler for previewing enable/disable UI states |
templates/shared/actions/runner_edit.tmpl |
Adds availability status indicator and enable/disable toggle button |
templates/devtest/runner-edit.tmpl |
Devtest page for UI verification |
templates/swagger/v1_json.tmpl |
Adds swagger definitions for all new endpoints and disabled field in ActionRunner definition; fixes "an" → "a" article in repo/user endpoint summaries |
options/locale/locale_en-US.json |
Adds locale strings for availability label and enable/disable actions |
tests/integration/api_actions_runner_test.go |
Integration tests for disable/enable API at all scopes, including idempotency and scope-enforcement |
tests/integration/actions_runner_modify_test.go |
Web integration tests for disable/enable in runner modify flow |
tests/integration/actions_job_test.go |
End-to-end test verifying disabled runner does not pick up tasks but re-enabled runner does |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
9d903da to
678ae44
Compare
|
@silverwind fixed copilots comments |
|
anyone who can review? :-) |
I will take care of that, but it may take some time since the task is relatively large. |
|
Found some issues fixing them |
d5f0054 to
5bf5c62
Compare
|
@lunny should be ready for a review now - rebased and fixed some stuff 😄 |
5bf5c62 to
a53dde2
Compare
There was a problem hiding this comment.
-
fetchTaskOncewill panic on error (tests/integration/actions_runner_test.go): Usesassert.NoErrorwhich records the failure but continues execution. IfFetchTaskreturns an error,respis nil andresp.Msg.Taskpanics. Should userequire.NoErrorto fail fast. -
Consider a single toggle endpoint: Separate
/disableand/enableendpoints result in 8 route registrations + 8 swagger handler functions for a boolean toggle. A singlePATCH .../runners/{runner_id}with{"disabled": true/false}would halve the API surface and be more conventional REST. Though I understand this may be intentional for simplicity.
- Redundant early-return in API handler:
updateRunnerDisabledinrouters/api/v1/shared/runners.gochecksrunner.IsDisabled == isDisabledbefore callingSetRunnerDisabled, butSetRunnerDisabledalready has this exact same check. The API handler check just saves one function call — not worth the duplicated logic.
|
@silverwind which of these comments do you want fixed? |
|
1 and 3 at least. And don't ask me questions like that, it's your job to judge these comments :) |
|
@silverwind is there something wrong with CI? |
dbda9f6 to
c1d40c4
Compare
|
ig I found it: #36858 |
|
It was a lie :-( whyyyyy |
|
int64-related issues may be coming from #36858. Also I think you need to run |
|
@silverwind @lunny fixed and ready for review again |
- Use *bool for EditActionRunnerOption.Disabled (standard pattern), removing custom UnmarshalJSON and modules/json import from structs - Fix enable/disable buttons to use link-action with JSONRedirect instead of formaction which does not work with JS-driven forms - Remove redundant IsDisabled check in CreateTaskForRunner (already guarded in PickTask) - Use grey label for disabled badge in runner list and edit page Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
| // the current TasksVersion (not 0), the server still re-evaluates after disable | ||
| // and does not assign a task to a disabled runner (version bump on disable). | ||
| func TestRunnerDisableEnableTasksVersionPath(t *testing.T) { | ||
| onGiteaRun(t, func(t *testing.T, _ *url.URL) { |
There was a problem hiding this comment.
I mean , is it possible to merge TestRunnerDisableEnable and TestRunnerDisableEnableTasksVersionPath, then only use one "onGiteaRun"?
The reason is that "onGiteaRun" is slow, keeping adding new "onGiteaRun" calls just slows down the testing more and more.
So if there is a chance, I would always suggest to merge test cases

This PR adds per-runner disable/enable support for Gitea Actions so a registered runner can be paused from picking up new jobs without unregistering.
Disabled runners stay registered and online but are excluded from new task assignment; running tasks are allowed to finish. Re-enabling restores pickup, and runner list/get responses now expose disabled state.
Also added an endpoint for testing http://localhost:3000/devtest/runner-edit/enable
Fixes: #36767