loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Support changing labels of Actions runner without re-registration (#24806)

close #24540

related:
- Protocol: https://gitea.com/gitea/actions-proto-def/pulls/9
- Runner side: https://gitea.com/gitea/act_runner/pulls/201

changes:
- Add column of `labels` to table `action_runner`, and combine the value
of `agent_labels` and `custom_labels` column to `labels` column.
- Store `labels` when registering `act_runner`.
- Update `labels` when `act_runner` starting and calling `Declare`.
- Users cannot modify the `custom labels` in edit page any more.

other changes:
- Store `version` when registering `act_runner`.
- If runner is latest version, parse version from `Declare`. But older
version runner still parse version from request header.

authored by

sillyguodong and committed by
GitHub
8228751c 6bbccdd1

+113 -63
+1 -1
go.mod
··· 3 3 go 1.20 4 4 5 5 require ( 6 - code.gitea.io/actions-proto-go v0.2.1 6 + code.gitea.io/actions-proto-go v0.3.0 7 7 code.gitea.io/gitea-vet v0.2.2 8 8 code.gitea.io/sdk/gitea v0.15.1 9 9 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
+2 -2
go.sum
··· 40 40 cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 41 41 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 42 42 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= 43 - code.gitea.io/actions-proto-go v0.2.1 h1:ToMN/8thz2q10TuCq8dL2d8mI+/pWpJcHCvG+TELwa0= 44 - code.gitea.io/actions-proto-go v0.2.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A= 43 + code.gitea.io/actions-proto-go v0.3.0 h1:9Tvg8+TaaCXPKi6EnWl9vVgs2VZsj1Cs5afnsHa4AmM= 44 + code.gitea.io/actions-proto-go v0.3.0/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A= 45 45 code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= 46 46 code.gitea.io/gitea-vet v0.2.2 h1:TEOV/Glf38iGmKzKP0EB++Z5OSL4zGg3RrAvlwaMuvk= 47 47 code.gitea.io/gitea-vet v0.2.2/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
+2 -9
models/actions/runner.go
··· 43 43 LastOnline timeutil.TimeStamp `xorm:"index"` 44 44 LastActive timeutil.TimeStamp `xorm:"index"` 45 45 46 - // Store OS and Artch. 47 - AgentLabels []string 48 - // Store custom labes use defined. 49 - CustomLabels []string 46 + // Store labels defined in state file (default: .runner file) of `act_runner` 47 + AgentLabels []string `xorm:"TEXT"` 50 48 51 49 Created timeutil.TimeStamp `xorm:"created"` 52 50 Updated timeutil.TimeStamp `xorm:"updated"` ··· 102 100 return true 103 101 } 104 102 return false 105 - } 106 - 107 - // AllLabels returns agent and custom labels 108 - func (r *ActionRunner) AllLabels() []string { 109 - return append(r.AgentLabels, r.CustomLabels...) 110 103 } 111 104 112 105 // Editable checks if the runner is editable by the user
+2 -4
models/actions/task.go
··· 241 241 242 242 // TODO: a more efficient way to filter labels 243 243 var job *ActionRunJob 244 - labels := runner.AgentLabels 245 - labels = append(labels, runner.CustomLabels...) 246 - log.Trace("runner labels: %v", labels) 244 + log.Trace("runner labels: %v", runner.AgentLabels) 247 245 for _, v := range jobs { 248 - if isSubset(labels, v.RunsOn) { 246 + if isSubset(runner.AgentLabels, v.RunsOn) { 249 247 job = v 250 248 break 251 249 }
+6
models/migrations/migrations.go
··· 20 20 "code.gitea.io/gitea/models/migrations/v1_18" 21 21 "code.gitea.io/gitea/models/migrations/v1_19" 22 22 "code.gitea.io/gitea/models/migrations/v1_20" 23 + "code.gitea.io/gitea/models/migrations/v1_21" 23 24 "code.gitea.io/gitea/models/migrations/v1_6" 24 25 "code.gitea.io/gitea/models/migrations/v1_7" 25 26 "code.gitea.io/gitea/models/migrations/v1_8" ··· 497 498 NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue), 498 499 // v259 -> 260 499 500 NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens), 501 + 502 + // Gitea 1.21.0 ends at 260 503 + 504 + // v260 -> v261 505 + NewMigration("Add label column to action_run table, and combine labels", v1_21.DropCustomLabelsColumnToActRunner), 500 506 } 501 507 502 508 // GetCurrentDBVersion returns the current db version
+14
models/migrations/v1_21/main_test.go
··· 1 + // Copyright 2023 The Gitea Authors. All rights reserved. 2 + // SPDX-License-Identifier: MIT 3 + 4 + package v1_21 //nolint 5 + 6 + import ( 7 + "testing" 8 + 9 + "code.gitea.io/gitea/models/migrations/base" 10 + ) 11 + 12 + func TestMain(m *testing.M) { 13 + base.MainTest(m) 14 + }
+26
models/migrations/v1_21/v260.go
··· 1 + // Copyright 2023 The Gitea Authors. All rights reserved. 2 + // SPDX-License-Identifier: MIT 3 + 4 + package v1_21 //nolint 5 + 6 + import ( 7 + "code.gitea.io/gitea/models/migrations/base" 8 + 9 + "xorm.io/xorm" 10 + ) 11 + 12 + func DropCustomLabelsColumnToActRunner(x *xorm.Engine) error { 13 + sess := x.NewSession() 14 + defer sess.Close() 15 + 16 + if err := sess.Begin(); err != nil { 17 + return err 18 + } 19 + 20 + // drop "custom_labels" cols 21 + if err := base.DropTableColumns(sess, "action_runner", "custom_labels"); err != nil { 22 + return err 23 + } 24 + 25 + return sess.Commit() 26 + }
+1 -3
options/locale/locale_en-US.ini
··· 3426 3426 runners.description = Description 3427 3427 runners.labels = Labels 3428 3428 runners.last_online = Last Online Time 3429 - runners.agent_labels = Agent Labels 3430 - runners.custom_labels = Custom Labels 3431 - runners.custom_labels_helper = Custom labels are labels that are added manually by an administrator. A comma separates labels, whitespace at the start and end of each label is ignored. 3432 3429 runners.runner_title = Runner 3433 3430 runners.task_list = Recent tasks on this runner 3431 + runners.task_list.no_tasks = There is no task yet. 3434 3432 runners.task_list.run = Run 3435 3433 runners.task_list.status = Status 3436 3434 runners.task_list.repository = Repository
+10 -9
routers/api/actions/runner/interceptor.go
··· 21 21 ) 22 22 23 23 const ( 24 - uuidHeaderKey = "x-runner-uuid" 25 - tokenHeaderKey = "x-runner-token" 24 + uuidHeaderKey = "x-runner-uuid" 25 + tokenHeaderKey = "x-runner-token" 26 + // Deprecated: will be removed after Gitea 1.20 released. 26 27 versionHeaderKey = "x-runner-version" 27 - 28 - versionUnknown = "Unknown" 29 28 ) 30 29 31 30 var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unaryFunc connect.UnaryFunc) connect.UnaryFunc { ··· 36 35 } 37 36 uuid := request.Header().Get(uuidHeaderKey) 38 37 token := request.Header().Get(tokenHeaderKey) 38 + // TODO: version will be removed from request header after Gitea 1.20 released. 39 + // And Gitea will not try to read version from reuqest header 39 40 version := request.Header().Get(versionHeaderKey) 40 - if util.IsEmptyString(version) { 41 - version = versionUnknown 42 - } 43 - version, _ = util.SplitStringAtByteN(version, 64) 44 41 45 42 runner, err := actions_model.GetRunnerByUUID(ctx, uuid) 46 43 if err != nil { ··· 54 51 } 55 52 56 53 cols := []string{"last_online"} 57 - if runner.Version != version { 54 + 55 + // TODO: version will be removed from request header after Gitea 1.20 released. 56 + // And Gitea will not try to read version from reuqest header 57 + version, _ = util.SplitStringAtByteN(version, 64) 58 + if !util.IsEmptyString(version) && runner.Version != version { 58 59 runner.Version = version 59 60 cols = append(cols, "version") 60 61 }
+43 -12
routers/api/actions/runner/runner.go
··· 54 54 return nil, errors.New("runner token has already been activated") 55 55 } 56 56 57 + labels := req.Msg.Labels 58 + // TODO: agent_labels should be removed from pb after Gitea 1.20 released. 59 + // Old version runner's agent_labels slice is not empty and labels slice is empty. 60 + // And due to compatibility with older versions, it is temporarily marked as Deprecated in pb, so use `//nolint` here. 61 + if len(req.Msg.AgentLabels) > 0 && len(req.Msg.Labels) == 0 { //nolint:staticcheck 62 + labels = req.Msg.AgentLabels //nolint:staticcheck 63 + } 64 + 57 65 // create new runner 58 66 name, _ := util.SplitStringAtByteN(req.Msg.Name, 255) 59 67 runner := &actions_model.ActionRunner{ 60 - UUID: gouuid.New().String(), 61 - Name: name, 62 - OwnerID: runnerToken.OwnerID, 63 - RepoID: runnerToken.RepoID, 64 - AgentLabels: req.Msg.AgentLabels, 65 - CustomLabels: req.Msg.CustomLabels, 68 + UUID: gouuid.New().String(), 69 + Name: name, 70 + OwnerID: runnerToken.OwnerID, 71 + RepoID: runnerToken.RepoID, 72 + Version: req.Msg.Version, 73 + AgentLabels: labels, 66 74 } 67 75 if err := runner.GenerateToken(); err != nil { 68 76 return nil, errors.New("can't generate token") ··· 81 89 82 90 res := connect.NewResponse(&runnerv1.RegisterResponse{ 83 91 Runner: &runnerv1.Runner{ 84 - Id: runner.ID, 85 - Uuid: runner.UUID, 86 - Token: runner.Token, 87 - Name: runner.Name, 88 - AgentLabels: runner.AgentLabels, 89 - CustomLabels: runner.CustomLabels, 92 + Id: runner.ID, 93 + Uuid: runner.UUID, 94 + Token: runner.Token, 95 + Name: runner.Name, 96 + Version: runner.Version, 97 + Labels: runner.AgentLabels, 90 98 }, 91 99 }) 92 100 93 101 return res, nil 102 + } 103 + 104 + func (s *Service) Declare( 105 + ctx context.Context, 106 + req *connect.Request[runnerv1.DeclareRequest], 107 + ) (*connect.Response[runnerv1.DeclareResponse], error) { 108 + runner := GetRunner(ctx) 109 + runner.AgentLabels = req.Msg.Labels 110 + runner.Version = req.Msg.Version 111 + if err := actions_model.UpdateRunner(ctx, runner, "agent_labels", "version"); err != nil { 112 + return nil, status.Errorf(codes.Internal, "update runner: %v", err) 113 + } 114 + 115 + return connect.NewResponse(&runnerv1.DeclareResponse{ 116 + Runner: &runnerv1.Runner{ 117 + Id: runner.ID, 118 + Uuid: runner.UUID, 119 + Token: runner.Token, 120 + Name: runner.Name, 121 + Version: runner.Version, 122 + Labels: runner.AgentLabels, 123 + }, 124 + }), nil 94 125 } 95 126 96 127 // FetchTask assigns a task to the runner
-1
routers/web/repo/actions/actions.go
··· 84 84 allRunnerLabels := make(container.Set[string]) 85 85 for _, r := range runners { 86 86 allRunnerLabels.AddMultiple(r.AgentLabels...) 87 - allRunnerLabels.AddMultiple(r.CustomLabels...) 88 87 } 89 88 90 89 workflows = make([]Workflow, 0, len(entries))
+1 -11
routers/web/shared/actions/runners.go
··· 6 6 import ( 7 7 "errors" 8 8 "net/http" 9 - "strings" 10 9 11 10 actions_model "code.gitea.io/gitea/models/actions" 12 11 "code.gitea.io/gitea/models/db" ··· 126 125 127 126 form := web.GetForm(ctx).(*forms.EditRunnerForm) 128 127 runner.Description = form.Description 129 - runner.CustomLabels = splitLabels(form.CustomLabels) 130 128 131 - err = actions_model.UpdateRunner(ctx, runner, "description", "custom_labels") 129 + err = actions_model.UpdateRunner(ctx, runner, "description") 132 130 if err != nil { 133 131 log.Warn("RunnerDetailsEditPost.UpdateRunner failed: %v, url: %s", err, ctx.Req.URL) 134 132 ctx.Flash.Warning(ctx.Tr("actions.runners.update_runner_failed")) ··· 176 174 "redirect": successRedirectTo, 177 175 }) 178 176 } 179 - 180 - func splitLabels(s string) []string { 181 - labels := strings.Split(s, ",") 182 - for i, v := range labels { 183 - labels[i] = strings.TrimSpace(v) 184 - } 185 - return labels 186 - }
+1 -2
services/forms/runner.go
··· 14 14 15 15 // EditRunnerForm form for admin to create runner 16 16 type EditRunnerForm struct { 17 - Description string 18 - CustomLabels string // comma-separated 17 + Description string 19 18 } 20 19 21 20 // Validate validates form fields
+3 -8
templates/shared/actions/runner_edit.tmpl
··· 13 13 </div> 14 14 <div class="field gt-dib gt-mr-4"> 15 15 <label>{{.locale.Tr "actions.runners.last_online"}}</label> 16 - <span>{{if .LastOnline}}{{TimeSinceUnix .LastOnline $.locale}}{{else}}{{$.locale.Tr "never"}}{{end}}</span> 16 + <span>{{if .Runner.LastOnline}}{{TimeSinceUnix .Runner.LastOnline $.locale}}{{else}}{{$.locale.Tr "never"}}{{end}}</span> 17 17 </div> 18 18 <div class="field gt-dib gt-mr-4"> 19 - <label>{{.locale.Tr "actions.runners.agent_labels"}}</label> 19 + <label>{{.locale.Tr "actions.runners.labels"}}</label> 20 20 <span> 21 21 {{range .Runner.AgentLabels}} 22 22 <span>{{.}}</span> ··· 34 34 <div class="field"> 35 35 <label for="description">{{.locale.Tr "actions.runners.description"}}</label> 36 36 <input id="description" name="description" value="{{.Runner.Description}}"> 37 - </div> 38 - <div class="field" data-tooltip-content="Labels are comma-separated. Whitespace at the beginning, end, and around the commas are ignored."> 39 - <label for="custom_labels">{{.locale.Tr "actions.runners.custom_labels"}}</label> 40 - <input id="custom_labels" name="custom_labels" value="{{StringUtils.Join .Runner.CustomLabels `,`}}"> 41 - <p class="help">{{.locale.Tr "actions.runners.custom_labels_helper"}}</p> 42 37 </div> 43 38 44 39 <div class="ui divider"></div> ··· 81 76 {{end}} 82 77 {{if not .Tasks}} 83 78 <tr> 84 - <td colspan="5">{{.locale.Tr "runners.task_list.no_tasks"}}</td> 79 + <td colspan="5">{{.locale.Tr "actions.runners.task_list.no_tasks"}}</td> 85 80 </tr> 86 81 {{end}} 87 82 </tbody>
+1 -1
templates/shared/actions/runner_list.tmpl
··· 67 67 <td>{{if .Version}}{{.Version}}{{else}}{{$.locale.Tr "unknown"}}{{end}}</td> 68 68 <td><span data-tooltip-content="{{.BelongsToOwnerName}}">{{.BelongsToOwnerType.LocaleString $.locale}}<span></td> 69 69 <td class="runner-tags"> 70 - {{range .AllLabels}}<span class="ui label">{{.}}</span>{{end}} 70 + {{range .AgentLabels}}<span class="ui label">{{.}}</span>{{end}} 71 71 </td> 72 72 <td>{{if .LastOnline}}{{TimeSinceUnix .LastOnline $.locale}}{{else}}{{$.locale.Tr "never"}}{{end}}</td> 73 73 <td class="runner-ops">