Add runner capabilities display to web UI
Some checks are pending
Build and Release / Lint and Test (push) Waiting to run
Build and Release / Build Binaries (amd64, darwin) (push) Blocked by required conditions
Build and Release / Build Binaries (amd64, linux) (push) Blocked by required conditions
Build and Release / Build Binaries (amd64, windows) (push) Blocked by required conditions
Build and Release / Build Binaries (arm64, darwin) (push) Blocked by required conditions
Build and Release / Build Binaries (arm64, linux) (push) Blocked by required conditions

- Display capabilities on runner edit page (OS, Docker, shells, tools)
- Add locale translations for capability labels
- Parse and render CapabilitiesJSON from runner model
- Update actions-proto-go to v0.5.2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
David H. Friedel Jr. 2026-01-10 05:14:55 -05:00
parent 5d0a9f64e5
commit ef63f23694
5 changed files with 76 additions and 4 deletions

4
go.mod
View File

@ -10,7 +10,7 @@ toolchain go1.25.5
godebug x509negativeserial=1 godebug x509negativeserial=1
require ( require (
code.gitea.io/actions-proto-go v0.4.1 code.gitea.io/actions-proto-go v0.5.0
code.gitea.io/sdk/gitea v0.22.0 code.gitea.io/sdk/gitea v0.22.0
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
connectrpc.com/connect v1.18.1 connectrpc.com/connect v1.18.1
@ -313,7 +313,7 @@ replace github.com/nektos/act => gitea.com/gitea/act v0.261.7-0.20251003180512-a
replace git.sr.ht/~mariusor/go-xsd-duration => gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 replace git.sr.ht/~mariusor/go-xsd-duration => gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078
// Use GitCaddy fork with capability support // Use GitCaddy fork with capability support
replace code.gitea.io/actions-proto-go => git.marketally.com/gitcaddy/actions-proto-go v0.5.1 replace code.gitea.io/actions-proto-go => git.marketally.com/gitcaddy/actions-proto-go v0.5.2
exclude github.com/gofrs/uuid v3.2.0+incompatible exclude github.com/gofrs/uuid v3.2.0+incompatible

4
go.sum
View File

@ -29,8 +29,8 @@ dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.marketally.com/gitcaddy/actions-proto-go v0.5.0 h1:D2loMnqTXiaJL6TMfOOUJz4/3Vpv0AnMDSJVuiqMNrM= git.marketally.com/gitcaddy/actions-proto-go v0.5.2 h1:+0tDJeyduhxpYrBNScN8w5din/0zJ/KtAh/Eo6mE9QE=
git.marketally.com/gitcaddy/actions-proto-go v0.5.0/go.mod h1:li5RzZsj1sV8a0SXzXWsGNwv0dYw7Wj829AgloZqF5o= git.marketally.com/gitcaddy/actions-proto-go v0.5.2/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
gitea.com/gitea/act v0.261.7-0.20251003180512-ac6e4b751763 h1:ohdxegvslDEllZmRNDqpKun6L4Oq81jNdEDtGgHEV2c= gitea.com/gitea/act v0.261.7-0.20251003180512-ac6e4b751763 h1:ohdxegvslDEllZmRNDqpKun6L4Oq81jNdEDtGgHEV2c=
gitea.com/gitea/act v0.261.7-0.20251003180512-ac6e4b751763/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/gitea/act v0.261.7-0.20251003180512-ac6e4b751763/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4= gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4=

View File

@ -3696,6 +3696,13 @@
"actions.runners.reset_registration_token": "Reset registration token", "actions.runners.reset_registration_token": "Reset registration token",
"actions.runners.reset_registration_token_confirm": "Would you like to invalidate the current token and generate a new one?", "actions.runners.reset_registration_token_confirm": "Would you like to invalidate the current token and generate a new one?",
"actions.runners.reset_registration_token_success": "Runner registration token reset successfully", "actions.runners.reset_registration_token_success": "Runner registration token reset successfully",
"actions.runners.capabilities": "Capabilities",
"actions.runners.capabilities.os": "OS/Arch",
"actions.runners.capabilities.docker": "Docker",
"actions.runners.capabilities.shells": "Shells",
"actions.runners.capabilities.tools": "Tools",
"actions.runners.capabilities.limitations": "Limitations",
"actions.runners.capabilities.available": "Available",
"actions.runs.all_workflows": "All Workflows", "actions.runs.all_workflows": "All Workflows",
"actions.runs.commit": "Commit", "actions.runs.commit": "Commit",
"actions.runs.scheduled": "Scheduled", "actions.runs.scheduled": "Scheduled",

View File

@ -4,6 +4,7 @@
package actions package actions
import ( import (
"encoding/json"
"errors" "errors"
"net/http" "net/http"
"net/url" "net/url"
@ -12,6 +13,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
@ -199,6 +201,14 @@ func RunnersEdit(ctx *context.Context) {
ctx.Data["Runner"] = runner ctx.Data["Runner"] = runner
// Parse runner capabilities if available
if runner.CapabilitiesJSON != "" {
var caps structs.RunnerCapability
if err := json.Unmarshal([]byte(runner.CapabilitiesJSON), &caps); err == nil {
ctx.Data["RunnerCapabilities"] = &caps
}
}
opts := actions_model.FindTaskOptions{ opts := actions_model.FindTaskOptions{
ListOptions: db.ListOptions{ ListOptions: db.ListOptions{
Page: page, Page: page,

View File

@ -28,6 +28,61 @@
</div> </div>
</div> </div>
{{if .Runner.CapabilitiesJSON}}
<div class="divider"></div>
<div class="field">
<label>{{ctx.Locale.Tr "actions.runners.capabilities"}}</label>
<div class="ui segment runner-capabilities">
{{if .RunnerCapabilities}}
<div class="tw-flex tw-flex-wrap tw-gap-4">
{{if .RunnerCapabilities.OS}}
<div class="tw-inline-block tw-mr-4">
<strong>{{ctx.Locale.Tr "actions.runners.capabilities.os"}}:</strong>
<span class="ui label">{{.RunnerCapabilities.OS}}/{{.RunnerCapabilities.Arch}}</span>
</div>
{{end}}
{{if .RunnerCapabilities.Docker}}
<div class="tw-inline-block tw-mr-4">
<strong>{{ctx.Locale.Tr "actions.runners.capabilities.docker"}}:</strong>
<span class="ui green label">{{svg "octicon-check" 14}} {{ctx.Locale.Tr "actions.runners.capabilities.available"}}</span>
</div>
{{end}}
{{if .RunnerCapabilities.Shell}}
<div class="tw-inline-block tw-mr-4">
<strong>{{ctx.Locale.Tr "actions.runners.capabilities.shells"}}:</strong>
{{range .RunnerCapabilities.Shell}}
<span class="ui label">{{.}}</span>
{{end}}
</div>
{{end}}
</div>
{{if .RunnerCapabilities.Tools}}
<div class="tw-mt-2">
<strong>{{ctx.Locale.Tr "actions.runners.capabilities.tools"}}:</strong>
<div class="tw-flex tw-flex-wrap tw-gap-2 tw-mt-1">
{{range $tool, $versions := .RunnerCapabilities.Tools}}
<span class="ui label">{{$tool}} {{range $versions}}{{.}} {{end}}</span>
{{end}}
</div>
</div>
{{end}}
{{if .RunnerCapabilities.Limitations}}
<div class="tw-mt-2">
<strong>{{ctx.Locale.Tr "actions.runners.capabilities.limitations"}}:</strong>
<ul class="tw-mt-1 tw-ml-4">
{{range .RunnerCapabilities.Limitations}}
<li>{{.}}</li>
{{end}}
</ul>
</div>
{{end}}
{{else}}
<pre class="tw-text-sm"><code>{{.Runner.CapabilitiesJSON}}</code></pre>
{{end}}
</div>
</div>
{{end}}
<div class="divider"></div> <div class="divider"></div>
<div class="field"> <div class="field">