Skip to content

Commit 1e2f351

Browse files
NorthRealmlunnywxiaoguang
authored
Add endpoint deleting workflow run (#34337)
Add endpoint deleting workflow run Resolves #26219 /claim #26219 --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
1 parent a0595ad commit 1e2f351

File tree

22 files changed

+691
-43
lines changed

22 files changed

+691
-43
lines changed

models/actions/run.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
user_model "code.gitea.io/gitea/models/user"
1717
"code.gitea.io/gitea/modules/git"
1818
"code.gitea.io/gitea/modules/json"
19+
"code.gitea.io/gitea/modules/setting"
1920
api "code.gitea.io/gitea/modules/structs"
2021
"code.gitea.io/gitea/modules/timeutil"
2122
"code.gitea.io/gitea/modules/util"
@@ -343,13 +344,13 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
343344
return committer.Commit()
344345
}
345346

346-
func GetRunByID(ctx context.Context, id int64) (*ActionRun, error) {
347+
func GetRunByRepoAndID(ctx context.Context, repoID, runID int64) (*ActionRun, error) {
347348
var run ActionRun
348-
has, err := db.GetEngine(ctx).Where("id=?", id).Get(&run)
349+
has, err := db.GetEngine(ctx).Where("id=? AND repo_id=?", runID, repoID).Get(&run)
349350
if err != nil {
350351
return nil, err
351352
} else if !has {
352-
return nil, fmt.Errorf("run with id %d: %w", id, util.ErrNotExist)
353+
return nil, fmt.Errorf("run with id %d: %w", runID, util.ErrNotExist)
353354
}
354355

355356
return &run, nil
@@ -420,17 +421,10 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error {
420421

421422
if run.Status != 0 || slices.Contains(cols, "status") {
422423
if run.RepoID == 0 {
423-
run, err = GetRunByID(ctx, run.ID)
424-
if err != nil {
425-
return err
426-
}
424+
setting.PanicInDevOrTesting("RepoID should not be 0")
427425
}
428-
if run.Repo == nil {
429-
repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
430-
if err != nil {
431-
return err
432-
}
433-
run.Repo = repo
426+
if err = run.LoadRepo(ctx); err != nil {
427+
return err
434428
}
435429
if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
436430
return err

models/actions/run_job.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (job *ActionRunJob) Duration() time.Duration {
5151

5252
func (job *ActionRunJob) LoadRun(ctx context.Context) error {
5353
if job.Run == nil {
54-
run, err := GetRunByID(ctx, job.RunID)
54+
run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID)
5555
if err != nil {
5656
return err
5757
}
@@ -142,7 +142,7 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col
142142
{
143143
// Other goroutines may aggregate the status of the run and update it too.
144144
// So we need load the run and its jobs before updating the run.
145-
run, err := GetRunByID(ctx, job.RunID)
145+
run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID)
146146
if err != nil {
147147
return 0, err
148148
}

models/actions/task_list.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ func (tasks TaskList) LoadAttributes(ctx context.Context) error {
4848
type FindTaskOptions struct {
4949
db.ListOptions
5050
RepoID int64
51+
JobID int64
5152
OwnerID int64
5253
CommitSHA string
5354
Status Status
@@ -61,6 +62,9 @@ func (opts FindTaskOptions) ToConds() builder.Cond {
6162
if opts.RepoID > 0 {
6263
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
6364
}
65+
if opts.JobID > 0 {
66+
cond = cond.And(builder.Eq{"job_id": opts.JobID})
67+
}
6468
if opts.OwnerID > 0 {
6569
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
6670
}

models/fixtures/action_artifact.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,39 @@
105105
created_unix: 1730330775
106106
updated_unix: 1730330775
107107
expired_unix: 1738106775
108+
109+
-
110+
id: 24
111+
run_id: 795
112+
runner_id: 1
113+
repo_id: 2
114+
owner_id: 2
115+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
116+
storage_path: "27/5/1730330775594233150.chunk"
117+
file_size: 1024
118+
file_compressed_size: 1024
119+
content_encoding: "application/zip"
120+
artifact_path: "artifact-795-1.zip"
121+
artifact_name: "artifact-795-1"
122+
status: 2
123+
created_unix: 1730330775
124+
updated_unix: 1730330775
125+
expired_unix: 1738106775
126+
127+
-
128+
id: 25
129+
run_id: 795
130+
runner_id: 1
131+
repo_id: 2
132+
owner_id: 2
133+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
134+
storage_path: "27/5/1730330775594233150.chunk"
135+
file_size: 1024
136+
file_compressed_size: 1024
137+
content_encoding: "application/zip"
138+
artifact_path: "artifact-795-2.zip"
139+
artifact_name: "artifact-795-2"
140+
status: 2
141+
created_unix: 1730330775
142+
updated_unix: 1730330775
143+
expired_unix: 1738106775

models/fixtures/action_run.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0"
4949
event: "push"
5050
is_fork_pull_request: 0
51-
status: 1
51+
status: 6 # running
5252
started: 1683636528
5353
stopped: 1683636626
5454
created: 1683636108
@@ -74,3 +74,23 @@
7474
updated: 1683636626
7575
need_approval: 0
7676
approved_by: 0
77+
78+
-
79+
id: 795
80+
title: "to be deleted (test)"
81+
repo_id: 2
82+
owner_id: 2
83+
workflow_id: "test.yaml"
84+
index: 191
85+
trigger_user_id: 1
86+
ref: "refs/heads/test"
87+
commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0"
88+
event: "push"
89+
is_fork_pull_request: 0
90+
status: 2
91+
started: 1683636528
92+
stopped: 1683636626
93+
created: 1683636108
94+
updated: 1683636626
95+
need_approval: 0
96+
approved_by: 0

models/fixtures/action_run_job.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,33 @@
6969
status: 5
7070
started: 1683636528
7171
stopped: 1683636626
72+
73+
-
74+
id: 198
75+
run_id: 795
76+
repo_id: 2
77+
owner_id: 2
78+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
79+
is_fork_pull_request: 0
80+
name: job_1
81+
attempt: 1
82+
job_id: job_1
83+
task_id: 53
84+
status: 1
85+
started: 1683636528
86+
stopped: 1683636626
87+
88+
-
89+
id: 199
90+
run_id: 795
91+
repo_id: 2
92+
owner_id: 2
93+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
94+
is_fork_pull_request: 0
95+
name: job_2
96+
attempt: 1
97+
job_id: job_2
98+
task_id: 54
99+
status: 2
100+
started: 1683636528
101+
stopped: 1683636626

models/fixtures/action_task.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,43 @@
117117
log_length: 707
118118
log_size: 90179
119119
log_expired: 0
120+
-
121+
id: 53
122+
job_id: 198
123+
attempt: 1
124+
runner_id: 1
125+
status: 1
126+
started: 1683636528
127+
stopped: 1683636626
128+
repo_id: 2
129+
owner_id: 2
130+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
131+
is_fork_pull_request: 0
132+
token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784223
133+
token_salt: ffffffffff
134+
token_last_eight: ffffffff
135+
log_filename: artifact-test2/2f/47.log
136+
log_in_storage: 1
137+
log_length: 0
138+
log_size: 0
139+
log_expired: 0
140+
-
141+
id: 54
142+
job_id: 199
143+
attempt: 1
144+
runner_id: 1
145+
status: 2
146+
started: 1683636528
147+
stopped: 1683636626
148+
repo_id: 2
149+
owner_id: 2
150+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
151+
is_fork_pull_request: 0
152+
token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784224
153+
token_salt: ffffffffff
154+
token_last_eight: ffffffff
155+
log_filename: artifact-test2/2f/47.log
156+
log_in_storage: 1
157+
log_length: 0
158+
log_size: 0
159+
log_expired: 0

options/locale/locale_en-US.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3811,6 +3811,9 @@ runs.no_workflows.documentation = For more information on Gitea Actions, see <a
38113811
runs.no_runs = The workflow has no runs yet.
38123812
runs.empty_commit_message = (empty commit message)
38133813
runs.expire_log_message = Logs have been purged because they were too old.
3814+
runs.delete = Delete workflow run
3815+
runs.delete.description = Are you sure you want to permanently delete this workflow run? This action cannot be undone.
3816+
runs.not_done = This workflow run is not done.
38143817

38153818
workflow.disable = Disable Workflow
38163819
workflow.disable_success = Workflow '%s' disabled successfully.

routers/api/v1/api.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,10 @@ func Routes() *web.Router {
12791279
}, reqToken(), reqAdmin())
12801280
m.Group("/actions", func() {
12811281
m.Get("/tasks", repo.ListActionTasks)
1282-
m.Get("/runs/{run}/artifacts", repo.GetArtifactsOfRun)
1282+
m.Group("/runs/{run}", func() {
1283+
m.Get("/artifacts", repo.GetArtifactsOfRun)
1284+
m.Delete("", reqToken(), reqRepoWriter(unit.TypeActions), repo.DeleteActionRun)
1285+
})
12831286
m.Get("/artifacts", repo.GetArtifacts)
12841287
m.Group("/artifacts/{artifact_id}", func() {
12851288
m.Get("", repo.GetArtifact)

routers/api/v1/repo/action.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,58 @@ func GetArtifactsOfRun(ctx *context.APIContext) {
10611061
ctx.JSON(http.StatusOK, &res)
10621062
}
10631063

1064+
// DeleteActionRun Delete a workflow run
1065+
func DeleteActionRun(ctx *context.APIContext) {
1066+
// swagger:operation DELETE /repos/{owner}/{repo}/actions/runs/{run} repository deleteActionRun
1067+
// ---
1068+
// summary: Delete a workflow run
1069+
// produces:
1070+
// - application/json
1071+
// parameters:
1072+
// - name: owner
1073+
// in: path
1074+
// description: name of the owner
1075+
// type: string
1076+
// required: true
1077+
// - name: repo
1078+
// in: path
1079+
// description: name of the repository
1080+
// type: string
1081+
// required: true
1082+
// - name: run
1083+
// in: path
1084+
// description: runid of the workflow run
1085+
// type: integer
1086+
// required: true
1087+
// responses:
1088+
// "204":
1089+
// description: "No Content"
1090+
// "400":
1091+
// "$ref": "#/responses/error"
1092+
// "404":
1093+
// "$ref": "#/responses/notFound"
1094+
1095+
runID := ctx.PathParamInt64("run")
1096+
run, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID)
1097+
if errors.Is(err, util.ErrNotExist) {
1098+
ctx.APIError(http.StatusNotFound, err)
1099+
return
1100+
} else if err != nil {
1101+
ctx.APIErrorInternal(err)
1102+
return
1103+
}
1104+
if !run.Status.IsDone() {
1105+
ctx.APIError(http.StatusBadRequest, "this workflow run is not done")
1106+
return
1107+
}
1108+
1109+
if err := actions_service.DeleteRun(ctx, run); err != nil {
1110+
ctx.APIErrorInternal(err)
1111+
return
1112+
}
1113+
ctx.Status(http.StatusNoContent)
1114+
}
1115+
10641116
// GetArtifacts Lists all artifacts for a repository.
10651117
func GetArtifacts(ctx *context.APIContext) {
10661118
// swagger:operation GET /repos/{owner}/{repo}/actions/artifacts repository getArtifacts

routers/web/repo/actions/actions.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ func prepareWorkflowList(ctx *context.Context, workflows []Workflow) {
317317
pager.AddParamFromRequest(ctx.Req)
318318
ctx.Data["Page"] = pager
319319
ctx.Data["HasWorkflowsOrRuns"] = len(workflows) > 0 || len(runs) > 0
320+
321+
ctx.Data["AllowDeleteWorkflowRuns"] = ctx.Repo.CanWrite(unit.TypeActions)
320322
}
321323

322324
// loadIsRefDeleted loads the IsRefDeleted field for each run in the list.

routers/web/repo/actions/view.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,33 @@ func Approve(ctx *context_module.Context) {
577577
ctx.JSON(http.StatusOK, struct{}{})
578578
}
579579

580+
func Delete(ctx *context_module.Context) {
581+
runIndex := getRunIndex(ctx)
582+
repoID := ctx.Repo.Repository.ID
583+
584+
run, err := actions_model.GetRunByIndex(ctx, repoID, runIndex)
585+
if err != nil {
586+
if errors.Is(err, util.ErrNotExist) {
587+
ctx.JSONErrorNotFound()
588+
return
589+
}
590+
ctx.ServerError("GetRunByIndex", err)
591+
return
592+
}
593+
594+
if !run.Status.IsDone() {
595+
ctx.JSONError(ctx.Tr("actions.runs.not_done"))
596+
return
597+
}
598+
599+
if err := actions_service.DeleteRun(ctx, run); err != nil {
600+
ctx.ServerError("DeleteRun", err)
601+
return
602+
}
603+
604+
ctx.JSONOK()
605+
}
606+
580607
// getRunJobs gets the jobs of runIndex, and returns jobs[jobIndex], jobs.
581608
// Any error will be written to the ctx.
582609
// It never returns a nil job of an empty jobs, if the jobIndex is out of range, it will be treated as 0.

routers/web/repo/branch.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ func MergeUpstream(ctx *context.Context) {
264264
_, err := repo_service.MergeUpstream(ctx, ctx.Doer, ctx.Repo.Repository, branchName)
265265
if err != nil {
266266
if errors.Is(err, util.ErrNotExist) {
267-
ctx.JSONError(ctx.Tr("error.not_found"))
267+
ctx.JSONErrorNotFound()
268268
return
269269
} else if pull_service.IsErrMergeConflicts(err) {
270270
ctx.JSONError(ctx.Tr("repo.pulls.merge_conflict"))

routers/web/web.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,7 @@ func registerWebRoutes(m *web.Router) {
14471447
})
14481448
m.Post("/cancel", reqRepoActionsWriter, actions.Cancel)
14491449
m.Post("/approve", reqRepoActionsWriter, actions.Approve)
1450+
m.Post("/delete", reqRepoActionsWriter, actions.Delete)
14501451
m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
14511452
m.Delete("/artifacts/{artifact_name}", reqRepoActionsWriter, actions.ArtifactsDeleteView)
14521453
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)

0 commit comments

Comments
 (0)