Skip to content

Commit 1987206

Browse files
a1012112796silverwindwolfogre
authored
add disable workflow feature (#26413)
As title, that's simmilar with github. ![image](https://github.com/go-gitea/gitea/assets/25342410/9e8b2444-63e0-4e87-80da-730c1e4d09d6) ![image](https://github.com/go-gitea/gitea/assets/25342410/6c3a3345-3ba7-48c9-9acd-3e621632491b) --------- Signed-off-by: a1012112796 <[email protected]> Co-authored-by: silverwind <[email protected]> Co-authored-by: Jason Song <[email protected]>
1 parent 253737e commit 1987206

File tree

10 files changed

+180
-2
lines changed

10 files changed

+180
-2
lines changed

models/repo/repo.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,13 @@ func (repo *Repository) MustGetUnit(ctx context.Context, tp unit.Type) *RepoUnit
391391
Type: tp,
392392
Config: new(IssuesConfig),
393393
}
394+
} else if tp == unit.TypeActions {
395+
return &RepoUnit{
396+
Type: tp,
397+
Config: new(ActionsConfig),
398+
}
394399
}
400+
395401
return &RepoUnit{
396402
Type: tp,
397403
Config: new(UnitConfig),

models/repo/repo_unit.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package repo
66
import (
77
"context"
88
"fmt"
9+
"strings"
910

1011
"code.gitea.io/gitea/models/db"
1112
"code.gitea.io/gitea/models/unit"
@@ -162,6 +163,42 @@ func (cfg *PullRequestsConfig) GetDefaultMergeStyle() MergeStyle {
162163
return MergeStyleMerge
163164
}
164165

166+
type ActionsConfig struct {
167+
DisabledWorkflows []string
168+
}
169+
170+
func (cfg *ActionsConfig) EnableWorkflow(file string) {
171+
cfg.DisabledWorkflows = util.SliceRemoveAll(cfg.DisabledWorkflows, file)
172+
}
173+
174+
func (cfg *ActionsConfig) ToString() string {
175+
return strings.Join(cfg.DisabledWorkflows, ",")
176+
}
177+
178+
func (cfg *ActionsConfig) IsWorkflowDisabled(file string) bool {
179+
return util.SliceContains(cfg.DisabledWorkflows, file)
180+
}
181+
182+
func (cfg *ActionsConfig) DisableWorkflow(file string) {
183+
for _, workflow := range cfg.DisabledWorkflows {
184+
if file == workflow {
185+
return
186+
}
187+
}
188+
189+
cfg.DisabledWorkflows = append(cfg.DisabledWorkflows, file)
190+
}
191+
192+
// FromDB fills up a ActionsConfig from serialized format.
193+
func (cfg *ActionsConfig) FromDB(bs []byte) error {
194+
return json.UnmarshalHandleDoubleEncode(bs, &cfg)
195+
}
196+
197+
// ToDB exports a ActionsConfig to a serialized format.
198+
func (cfg *ActionsConfig) ToDB() ([]byte, error) {
199+
return json.Marshal(cfg)
200+
}
201+
165202
// BeforeSet is invoked from XORM before setting the value of a field of this object.
166203
func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) {
167204
switch colName {
@@ -175,7 +212,9 @@ func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) {
175212
r.Config = new(PullRequestsConfig)
176213
case unit.TypeIssues:
177214
r.Config = new(IssuesConfig)
178-
case unit.TypeCode, unit.TypeReleases, unit.TypeWiki, unit.TypeProjects, unit.TypePackages, unit.TypeActions:
215+
case unit.TypeActions:
216+
r.Config = new(ActionsConfig)
217+
case unit.TypeCode, unit.TypeReleases, unit.TypeWiki, unit.TypeProjects, unit.TypePackages:
179218
fallthrough
180219
default:
181220
r.Config = new(UnitConfig)
@@ -218,6 +257,11 @@ func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig {
218257
return r.Config.(*ExternalTrackerConfig)
219258
}
220259

260+
// ActionsConfig returns config for unit.ActionsConfig
261+
func (r *RepoUnit) ActionsConfig() *ActionsConfig {
262+
return r.Config.(*ActionsConfig)
263+
}
264+
221265
func getUnitsByRepoID(ctx context.Context, repoID int64) (units []*RepoUnit, err error) {
222266
var tmpUnits []*RepoUnit
223267
if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Find(&tmpUnits); err != nil {

models/repo/repo_unit_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package repo
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestActionsConfig(t *testing.T) {
13+
cfg := &ActionsConfig{}
14+
cfg.DisableWorkflow("test1.yaml")
15+
assert.EqualValues(t, []string{"test1.yaml"}, cfg.DisabledWorkflows)
16+
17+
cfg.DisableWorkflow("test1.yaml")
18+
assert.EqualValues(t, []string{"test1.yaml"}, cfg.DisabledWorkflows)
19+
20+
cfg.EnableWorkflow("test1.yaml")
21+
assert.EqualValues(t, []string{}, cfg.DisabledWorkflows)
22+
23+
cfg.EnableWorkflow("test1.yaml")
24+
assert.EqualValues(t, []string{}, cfg.DisabledWorkflows)
25+
26+
cfg.DisableWorkflow("test1.yaml")
27+
cfg.DisableWorkflow("test2.yaml")
28+
cfg.DisableWorkflow("test3.yaml")
29+
assert.EqualValues(t, "test1.yaml,test2.yaml,test3.yaml", cfg.ToString())
30+
}

options/locale/locale_en-US.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3491,6 +3491,11 @@ runs.status_no_select = All status
34913491
runs.no_results = No results matched.
34923492
runs.no_runs = The workflow has no runs yet.
34933493
3494+
workflow.disable = Disable Workflow
3495+
workflow.disable_success = Workflow '%s' disabled successfully.
3496+
workflow.enable = Enable Workflow
3497+
workflow.enable_success = Workflow '%s' enabled successfully.
3498+
34943499
need_approval_desc = Need approval to run workflows for fork pull request.
34953500
34963501
variables = Variables

routers/web/repo/actions/actions.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,15 @@ func List(ctx *context.Context) {
137137
actorID := ctx.FormInt64("actor")
138138
status := ctx.FormInt("status")
139139
ctx.Data["CurWorkflow"] = workflow
140+
141+
actionsConfig := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions).ActionsConfig()
142+
ctx.Data["ActionsConfig"] = actionsConfig
143+
144+
if len(workflow) > 0 && ctx.Repo.IsAdmin() {
145+
ctx.Data["AllowDisableOrEnableWorkflow"] = true
146+
ctx.Data["CurWorkflowDisabled"] = actionsConfig.IsWorkflowDisabled(workflow)
147+
}
148+
140149
// if status or actor query param is not given to frontend href, (href="/<repoLink>/actions")
141150
// they will be 0 by default, which indicates get all status or actors
142151
ctx.Data["CurActor"] = actorID

routers/web/repo/actions/view.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
actions_model "code.gitea.io/gitea/models/actions"
1919
"code.gitea.io/gitea/models/db"
20+
repo_model "code.gitea.io/gitea/models/repo"
2021
"code.gitea.io/gitea/models/unit"
2122
"code.gitea.io/gitea/modules/actions"
2223
"code.gitea.io/gitea/modules/base"
@@ -572,3 +573,43 @@ func ArtifactsDownloadView(ctx *context_module.Context) {
572573
}
573574
}
574575
}
576+
577+
func DisableWorkflowFile(ctx *context_module.Context) {
578+
disableOrEnableWorkflowFile(ctx, false)
579+
}
580+
581+
func EnableWorkflowFile(ctx *context_module.Context) {
582+
disableOrEnableWorkflowFile(ctx, true)
583+
}
584+
585+
func disableOrEnableWorkflowFile(ctx *context_module.Context, isEnable bool) {
586+
workflow := ctx.FormString("workflow")
587+
if len(workflow) == 0 {
588+
ctx.ServerError("workflow", nil)
589+
return
590+
}
591+
592+
cfgUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions)
593+
cfg := cfgUnit.ActionsConfig()
594+
595+
if isEnable {
596+
cfg.EnableWorkflow(workflow)
597+
} else {
598+
cfg.DisableWorkflow(workflow)
599+
}
600+
601+
if err := repo_model.UpdateRepoUnit(cfgUnit); err != nil {
602+
ctx.ServerError("UpdateRepoUnit", err)
603+
return
604+
}
605+
606+
if isEnable {
607+
ctx.Flash.Success(ctx.Tr("actions.workflow.enable_success", workflow))
608+
} else {
609+
ctx.Flash.Success(ctx.Tr("actions.workflow.disable_success", workflow))
610+
}
611+
612+
redirectURL := fmt.Sprintf("%s/actions?workflow=%s&actor=%s&status=%s", ctx.Repo.RepoLink, url.QueryEscape(workflow),
613+
url.QueryEscape(ctx.FormString("actor")), url.QueryEscape(ctx.FormString("status")))
614+
ctx.JSONRedirect(redirectURL)
615+
}

routers/web/web.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,8 @@ func registerRoutes(m *web.Route) {
12001200

12011201
m.Group("/actions", func() {
12021202
m.Get("", actions.List)
1203+
m.Post("/disable", reqRepoAdmin, actions.DisableWorkflowFile)
1204+
m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile)
12031205

12041206
m.Group("/runs/{run}", func() {
12051207
m.Combo("").

services/actions/notifier_helper.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,14 @@ func notify(ctx context.Context, input *notifyInput) error {
150150
if len(workflows) == 0 {
151151
log.Trace("repo %s with commit %s couldn't find workflows", input.Repo.RepoPath(), commit.ID)
152152
} else {
153+
actionsConfig := input.Repo.MustGetUnit(ctx, unit_model.TypeActions).ActionsConfig()
154+
153155
for _, wf := range workflows {
156+
if actionsConfig.IsWorkflowDisabled(wf.EntryName) {
157+
log.Trace("repo %s has disable workflows %s", input.Repo.RepoPath(), wf.EntryName)
158+
continue
159+
}
160+
154161
if wf.TriggerEvent != actions_module.GithubEventPullRequestTarget {
155162
detectedWorkflows = append(detectedWorkflows, wf)
156163
}

templates/repo/actions/list.tmpl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
<div class="page-content repository actions">
33
{{template "repo/header" .}}
44
<div class="ui container">
5+
{{template "base/alert" .}}
6+
57
<div class="ui stackable grid">
68
<div class="four wide column">
79
<div class="ui fluid vertical menu">
@@ -13,12 +15,16 @@
1315
{{svg "octicon-alert" 16 "text red"}}
1416
</span>
1517
{{end}}
18+
19+
{{if $.ActionsConfig.IsWorkflowDisabled .Entry.Name}}
20+
<div class="ui red label">{{$.locale.Tr "disabled"}}</div>
21+
{{end}}
1622
</a>
1723
{{end}}
1824
</div>
1925
</div>
2026
<div class="twelve wide column content">
21-
<div class="ui secondary filter stackable menu gt-je">
27+
<div class="ui secondary filter menu gt-je gt-df gt-ac">
2228
<!-- Actor -->
2329
<div class="ui{{if not .Actors}} disabled{{end}} dropdown jump item">
2430
<span class="text">{{.locale.Tr "actions.runs.actor"}}</span>
@@ -57,6 +63,17 @@
5763
{{end}}
5864
</div>
5965
</div>
66+
67+
{{if .AllowDisableOrEnableWorkflow}}
68+
<button class="ui jump dropdown btn interact-bg gt-p-3">
69+
{{svg "octicon-kebab-horizontal"}}
70+
<div class="menu">
71+
<a class="item link-action" data-url="{{$.Link}}/{{if .CurWorkflowDisabled}}enable{{else}}disable{{end}}?workflow={{$.CurWorkflow}}&actor={{.CurActor}}&status={{$.CurStatus}}">
72+
{{if .CurWorkflowDisabled}}{{.locale.Tr "actions.workflow.enable"}}{{else}}{{.locale.Tr "actions.workflow.disable"}}{{end}}
73+
</a>
74+
</div>
75+
</button>
76+
{{end}}
6077
</div>
6178
{{template "repo/actions/runs_list" .}}
6279
</div>

web_src/css/base.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,18 @@ a.label,
653653
color: var(--color-text);
654654
}
655655

656+
/* replace item margin on secondary menu items with gap and remove both the
657+
negative margins on the menu as well as margin on the items */
658+
.ui.secondary.menu {
659+
margin-left: 0;
660+
margin-right: 0;
661+
gap: .35714286em;
662+
}
663+
.ui.secondary.menu .item {
664+
margin-left: 0;
665+
margin-right: 0;
666+
}
667+
656668
.ui.secondary.menu .dropdown.item:hover,
657669
.ui.secondary.menu a.item:hover {
658670
color: var(--color-text);
@@ -670,6 +682,11 @@ a.label,
670682
padding-right: 0.85714286em;
671683
}
672684

685+
/* remove the menu clearfix so that it won't add undesired gaps when using "gap" */
686+
.ui.menu::after {
687+
content: normal;
688+
}
689+
673690
.ui.menu .dropdown.item .menu {
674691
background: var(--color-body);
675692
}

0 commit comments

Comments
 (0)