From 83f1bbabdfdbeb51e18013ec064a2d254710db37 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Thu, 1 May 2025 16:15:38 +0800 Subject: [PATCH 01/35] Backend --- models/actions/task_list.go | 4 ++ routers/web/repo/actions/view.go | 91 ++++++++++++++++++++++++++++++++ routers/web/web.go | 1 + 3 files changed, 96 insertions(+) diff --git a/models/actions/task_list.go b/models/actions/task_list.go index df4b43c5ef300..0c80397899482 100644 --- a/models/actions/task_list.go +++ b/models/actions/task_list.go @@ -48,6 +48,7 @@ func (tasks TaskList) LoadAttributes(ctx context.Context) error { type FindTaskOptions struct { db.ListOptions RepoID int64 + JobID int64 OwnerID int64 CommitSHA string Status Status @@ -61,6 +62,9 @@ func (opts FindTaskOptions) ToConds() builder.Cond { if opts.RepoID > 0 { cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) } + if opts.JobID > 0 { + cond = cond.And(builder.Eq{"job_id": opts.JobID}) + } if opts.OwnerID > 0 { cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) } diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 2ec638926340a..2984158de7ad0 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -581,6 +581,97 @@ func Approve(ctx *context_module.Context) { ctx.JSON(http.StatusOK, struct{}{}) } +// TODO: When deleting a run, it should at lease delete artifacts, tasks logs, database record. +func Delete(ctx *context_module.Context) { + runIndex := getRunIndex(ctx) + + job0, jobs := getRunJobs(ctx, runIndex, -1) + if ctx.Written() { + return + } + + run := job0.Run + if !run.Status.IsDone() { + // TODO: Locale? + ctx.JSONError("run not done yet") + return + } + + repoID := ctx.Repo.Repository.ID + + tasks := []*actions_model.ActionTask{} + + for _, job := range jobs { + tasks0, err := db.Find[actions_model.ActionTask](ctx, actions_model.FindTaskOptions{ + RepoID: repoID, + JobID: job.ID, + }) + if err != nil { + ctx.HTTPError(http.StatusInternalServerError, err.Error()) + return + } + tasks = append(tasks, tasks0...) + } + + artifacts, err := db.Find[actions_model.ActionArtifact](ctx, actions_model.FindArtifactsOptions{ + RepoID: repoID, + RunID: run.ID, + }) + if err != nil { + ctx.HTTPError(http.StatusInternalServerError, err.Error()) + return + } + + recordsToDelete := []any{} + + for _, task := range tasks { + recordsToDelete = append(recordsToDelete, &actions_model.ActionTask{ + RepoID: repoID, + ID: task.ID, + }) + recordsToDelete = append(recordsToDelete, &actions_model.ActionTaskStep{ + RepoID: repoID, + TaskID: task.ID, + }) + } + recordsToDelete = append(recordsToDelete, &actions_model.ActionRunJob{ + RepoID: repoID, + RunID: run.ID, + }) + recordsToDelete = append(recordsToDelete, &actions_model.ActionRun{ + RepoID: repoID, + ID: run.ID, + }) + recordsToDelete = append(recordsToDelete, &actions_model.ActionArtifact{ + RepoID: repoID, + RunID: run.ID, + }) + + if err := db.WithTx(ctx, func(ctx context.Context) error { + return db.DeleteBeans(ctx, recordsToDelete...) + }); err != nil { + ctx.HTTPError(http.StatusInternalServerError, err.Error()) + return + } + + // Delete files on storage + for _, task := range tasks { + err := actions.RemoveLogs(ctx, task.LogInStorage, task.LogFilename) + if err != nil { + log.Error("remove log file %q: %v", task.LogFilename, err) + } + } + for _, art := range artifacts { + if err := storage.ActionsArtifacts.Delete(art.StoragePath); err != nil { + log.Error("remove artifact file %q: %v", art.StoragePath, err) + } + } + + // TODO: Delete commit status? Looks like it has no direct reference to a run/task/job. Not quite feasible without modifying db models (Dangerous). + + ctx.JSON(http.StatusOK, struct{}{}) +} + // getRunJobs gets the jobs of runIndex, and returns jobs[jobIndex], jobs. // Any error will be written to the ctx. // It never returns a nil job of an empty jobs, if the jobIndex is out of range, it will be treated as 0. diff --git a/routers/web/web.go b/routers/web/web.go index bd850baec0f46..8f53af56c5713 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1447,6 +1447,7 @@ func registerWebRoutes(m *web.Router) { }) m.Post("/cancel", reqRepoActionsWriter, actions.Cancel) m.Post("/approve", reqRepoActionsWriter, actions.Approve) + m.Delete("/delete", reqRepoActionsWriter, actions.Delete) m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView) m.Delete("/artifacts/{artifact_name}", reqRepoActionsWriter, actions.ArtifactsDeleteView) m.Post("/rerun", reqRepoActionsWriter, actions.Rerun) From a633f446109cbdf56663f127af7e17f742431282 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Thu, 1 May 2025 19:09:52 +0800 Subject: [PATCH 02/35] Refactor --- models/actions/run.go | 71 ++++++++++++++++++++++++++++++++ routers/web/repo/actions/view.go | 68 +----------------------------- 2 files changed, 72 insertions(+), 67 deletions(-) diff --git a/models/actions/run.go b/models/actions/run.go index 5f077940c5612..bca6a7218598a 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -4,6 +4,10 @@ package actions import ( + actions_module "code.gitea.io/gitea/modules/actions" + container_module "code.gitea.io/gitea/modules/container" + log_module "code.gitea.io/gitea/modules/log" + storage_module "code.gitea.io/gitea/modules/storage" "context" "errors" "fmt" @@ -439,4 +443,71 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error { return nil } +// TODO: When deleting a run, it should at lease delete artifacts, tasks logs, database record. +func DeleteRun(ctx context.Context, repoID int64, run *ActionRun, jobs []*ActionRunJob) error { + jobIDs := container_module.FilterSlice(jobs, func(j *ActionRunJob) (int64, bool) { + return j.ID, j.ID != 0 + }) + + tasks := make(TaskList, 0) + if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).In("job_id", jobIDs).Find(&tasks); err != nil { + return err + } + + artifacts, err := db.Find[ActionArtifact](ctx, FindArtifactsOptions{ + RepoID: repoID, + RunID: run.ID, + }) + if err != nil { + return err + } + + var recordsToDelete []any + + for _, task := range tasks { + recordsToDelete = append(recordsToDelete, &ActionTask{ + RepoID: repoID, + ID: task.ID, + }) + recordsToDelete = append(recordsToDelete, &ActionTaskStep{ + RepoID: repoID, + TaskID: task.ID, + }) + } + recordsToDelete = append(recordsToDelete, &ActionRunJob{ + RepoID: repoID, + RunID: run.ID, + }) + recordsToDelete = append(recordsToDelete, &ActionRun{ + RepoID: repoID, + ID: run.ID, + }) + recordsToDelete = append(recordsToDelete, &ActionArtifact{ + RepoID: repoID, + RunID: run.ID, + }) + + if err := db.WithTx(ctx, func(ctx context.Context) error { + return db.DeleteBeans(ctx, recordsToDelete...) + }); err != nil { + return err + } + + // Delete files on storage + for _, tas := range tasks { + err := actions_module.RemoveLogs(ctx, tas.LogInStorage, tas.LogFilename) + if err != nil { + log_module.Error("remove log file %q: %v", tas.LogFilename, err) + } + } + for _, art := range artifacts { + if err := storage_module.ActionsArtifacts.Delete(art.StoragePath); err != nil { + log_module.Error("remove artifact file %q: %v", art.StoragePath, err) + } + } + + // TODO: Delete commit status? Looks like it has no direct reference to a run/task/job. Not quite feasible without modifying db models (Dangerous). + return nil +} + type ActionRunIndex db.ResourceIndex diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 2984158de7ad0..13349f3f37841 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -581,7 +581,6 @@ func Approve(ctx *context_module.Context) { ctx.JSON(http.StatusOK, struct{}{}) } -// TODO: When deleting a run, it should at lease delete artifacts, tasks logs, database record. func Delete(ctx *context_module.Context) { runIndex := getRunIndex(ctx) @@ -599,76 +598,11 @@ func Delete(ctx *context_module.Context) { repoID := ctx.Repo.Repository.ID - tasks := []*actions_model.ActionTask{} - - for _, job := range jobs { - tasks0, err := db.Find[actions_model.ActionTask](ctx, actions_model.FindTaskOptions{ - RepoID: repoID, - JobID: job.ID, - }) - if err != nil { - ctx.HTTPError(http.StatusInternalServerError, err.Error()) - return - } - tasks = append(tasks, tasks0...) - } - - artifacts, err := db.Find[actions_model.ActionArtifact](ctx, actions_model.FindArtifactsOptions{ - RepoID: repoID, - RunID: run.ID, - }) - if err != nil { + if err := actions_model.DeleteRun(ctx, repoID, run, jobs); err != nil { ctx.HTTPError(http.StatusInternalServerError, err.Error()) return } - recordsToDelete := []any{} - - for _, task := range tasks { - recordsToDelete = append(recordsToDelete, &actions_model.ActionTask{ - RepoID: repoID, - ID: task.ID, - }) - recordsToDelete = append(recordsToDelete, &actions_model.ActionTaskStep{ - RepoID: repoID, - TaskID: task.ID, - }) - } - recordsToDelete = append(recordsToDelete, &actions_model.ActionRunJob{ - RepoID: repoID, - RunID: run.ID, - }) - recordsToDelete = append(recordsToDelete, &actions_model.ActionRun{ - RepoID: repoID, - ID: run.ID, - }) - recordsToDelete = append(recordsToDelete, &actions_model.ActionArtifact{ - RepoID: repoID, - RunID: run.ID, - }) - - if err := db.WithTx(ctx, func(ctx context.Context) error { - return db.DeleteBeans(ctx, recordsToDelete...) - }); err != nil { - ctx.HTTPError(http.StatusInternalServerError, err.Error()) - return - } - - // Delete files on storage - for _, task := range tasks { - err := actions.RemoveLogs(ctx, task.LogInStorage, task.LogFilename) - if err != nil { - log.Error("remove log file %q: %v", task.LogFilename, err) - } - } - for _, art := range artifacts { - if err := storage.ActionsArtifacts.Delete(art.StoragePath); err != nil { - log.Error("remove artifact file %q: %v", art.StoragePath, err) - } - } - - // TODO: Delete commit status? Looks like it has no direct reference to a run/task/job. Not quite feasible without modifying db models (Dangerous). - ctx.JSON(http.StatusOK, struct{}{}) } From 29a0fe5878a7e6be4031b7ecf9a2969d495c4dc2 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Thu, 1 May 2025 20:00:18 +0800 Subject: [PATCH 03/35] run.go jobIds len check --- models/actions/run.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/models/actions/run.go b/models/actions/run.go index bca6a7218598a..3155585154c2e 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -445,13 +445,16 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error { // TODO: When deleting a run, it should at lease delete artifacts, tasks logs, database record. func DeleteRun(ctx context.Context, repoID int64, run *ActionRun, jobs []*ActionRunJob) error { + tasks := make(TaskList, 0) + jobIDs := container_module.FilterSlice(jobs, func(j *ActionRunJob) (int64, bool) { return j.ID, j.ID != 0 }) - tasks := make(TaskList, 0) - if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).In("job_id", jobIDs).Find(&tasks); err != nil { - return err + if len(jobIDs) > 0 { + if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).In("job_id", jobIDs).Find(&tasks); err != nil { + return err + } } artifacts, err := db.Find[ActionArtifact](ctx, FindArtifactsOptions{ From b92b3c5b08c12437dc2f039070dfebff6bb3c928 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Thu, 1 May 2025 20:05:39 +0800 Subject: [PATCH 04/35] API endpoint --- routers/api/v1/api.go | 5 ++- routers/api/v1/repo/action.go | 67 +++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index b98863b418dc4..f57e27ada1282 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1279,7 +1279,10 @@ func Routes() *web.Router { }, reqToken(), reqAdmin()) m.Group("/actions", func() { m.Get("/tasks", repo.ListActionTasks) - m.Get("/runs/{run}/artifacts", repo.GetArtifactsOfRun) + m.Group("/runs/{run}", func() { + m.Get("/artifacts", repo.GetArtifactsOfRun) + m.Delete("", reqRepoWriter(unit.TypeActions), repo.DeleteActionRun) + }) m.Get("/artifacts", repo.GetArtifacts) m.Group("/artifacts/{artifact_id}", func() { m.Get("", repo.GetArtifact) diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 6aef529f98d5a..97bbdd1961169 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -1061,6 +1061,73 @@ func GetArtifactsOfRun(ctx *context.APIContext) { ctx.JSON(http.StatusOK, &res) } +// DeleteActionRun Delete a workflow run +func DeleteActionRun(ctx *context.APIContext) { + // swagger:operation DELETE /repos/{owner}/{repo}/actions/runs/{run} repository deleteActionRun + // --- + // summary: Delete a workflow run + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: name of the owner + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repository + // type: string + // required: true + // - name: run + // in: path + // description: runid of the workflow run + // type: integer + // required: true + // responses: + // "204": + // description: "No Content" + // "400": + // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/notFound" + + repoID := ctx.Repo.Repository.ID + runIndex := ctx.PathParamInt64("run") + + run, err := actions_model.GetRunByIndex(ctx, repoID, runIndex) + if err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.APIError(http.StatusNotFound, err.Error()) + return + } + ctx.APIErrorInternal(err) + return + } + if !run.Status.IsDone() { + ctx.APIError(http.StatusBadRequest, "Run not done yet") + return + } + + jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID) + if err != nil { + ctx.APIErrorInternal(err) + return + } + + // TODO: ? + if len(jobs) == 0 { + ctx.Status(http.StatusNoContent) + return + } + + if err := actions_model.DeleteRun(ctx, repoID, run, jobs); err != nil { + ctx.APIErrorInternal(err) + return + } + ctx.Status(http.StatusNoContent) +} + // GetArtifacts Lists all artifacts for a repository. func GetArtifacts(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/actions/artifacts repository getArtifacts From cb05cf772ce84b294b96dc70d678f82bfa2e5278 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Thu, 1 May 2025 20:13:22 +0800 Subject: [PATCH 05/35] FIX --- models/actions/run.go | 74 ----------------------------- modules/actions/run.go | 80 ++++++++++++++++++++++++++++++++ routers/api/v1/repo/action.go | 2 +- routers/web/repo/actions/view.go | 2 +- 4 files changed, 82 insertions(+), 76 deletions(-) create mode 100644 modules/actions/run.go diff --git a/models/actions/run.go b/models/actions/run.go index 3155585154c2e..5f077940c5612 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -4,10 +4,6 @@ package actions import ( - actions_module "code.gitea.io/gitea/modules/actions" - container_module "code.gitea.io/gitea/modules/container" - log_module "code.gitea.io/gitea/modules/log" - storage_module "code.gitea.io/gitea/modules/storage" "context" "errors" "fmt" @@ -443,74 +439,4 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error { return nil } -// TODO: When deleting a run, it should at lease delete artifacts, tasks logs, database record. -func DeleteRun(ctx context.Context, repoID int64, run *ActionRun, jobs []*ActionRunJob) error { - tasks := make(TaskList, 0) - - jobIDs := container_module.FilterSlice(jobs, func(j *ActionRunJob) (int64, bool) { - return j.ID, j.ID != 0 - }) - - if len(jobIDs) > 0 { - if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).In("job_id", jobIDs).Find(&tasks); err != nil { - return err - } - } - - artifacts, err := db.Find[ActionArtifact](ctx, FindArtifactsOptions{ - RepoID: repoID, - RunID: run.ID, - }) - if err != nil { - return err - } - - var recordsToDelete []any - - for _, task := range tasks { - recordsToDelete = append(recordsToDelete, &ActionTask{ - RepoID: repoID, - ID: task.ID, - }) - recordsToDelete = append(recordsToDelete, &ActionTaskStep{ - RepoID: repoID, - TaskID: task.ID, - }) - } - recordsToDelete = append(recordsToDelete, &ActionRunJob{ - RepoID: repoID, - RunID: run.ID, - }) - recordsToDelete = append(recordsToDelete, &ActionRun{ - RepoID: repoID, - ID: run.ID, - }) - recordsToDelete = append(recordsToDelete, &ActionArtifact{ - RepoID: repoID, - RunID: run.ID, - }) - - if err := db.WithTx(ctx, func(ctx context.Context) error { - return db.DeleteBeans(ctx, recordsToDelete...) - }); err != nil { - return err - } - - // Delete files on storage - for _, tas := range tasks { - err := actions_module.RemoveLogs(ctx, tas.LogInStorage, tas.LogFilename) - if err != nil { - log_module.Error("remove log file %q: %v", tas.LogFilename, err) - } - } - for _, art := range artifacts { - if err := storage_module.ActionsArtifacts.Delete(art.StoragePath); err != nil { - log_module.Error("remove artifact file %q: %v", art.StoragePath, err) - } - } - - // TODO: Delete commit status? Looks like it has no direct reference to a run/task/job. Not quite feasible without modifying db models (Dangerous). - return nil -} - type ActionRunIndex db.ResourceIndex diff --git a/modules/actions/run.go b/modules/actions/run.go new file mode 100644 index 0000000000000..76dbd17d1bb97 --- /dev/null +++ b/modules/actions/run.go @@ -0,0 +1,80 @@ +package actions + +import ( + "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/storage" + "context" +) + +// TODO: When deleting a run, it should at lease delete artifacts, tasks logs, database record. +func DeleteRun(ctx context.Context, repoID int64, run *actions.ActionRun, jobs []*actions.ActionRunJob) error { + tasks := make(actions.TaskList, 0) + + jobIDs := container.FilterSlice(jobs, func(j *actions.ActionRunJob) (int64, bool) { + return j.ID, j.ID != 0 + }) + + if len(jobIDs) > 0 { + if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).In("job_id", jobIDs).Find(&tasks); err != nil { + return err + } + } + + artifacts, err := db.Find[actions.ActionArtifact](ctx, actions.FindArtifactsOptions{ + RepoID: repoID, + RunID: run.ID, + }) + if err != nil { + return err + } + + var recordsToDelete []any + + for _, task := range tasks { + recordsToDelete = append(recordsToDelete, &actions.ActionTask{ + RepoID: repoID, + ID: task.ID, + }) + recordsToDelete = append(recordsToDelete, &actions.ActionTaskStep{ + RepoID: repoID, + TaskID: task.ID, + }) + } + recordsToDelete = append(recordsToDelete, &actions.ActionRunJob{ + RepoID: repoID, + RunID: run.ID, + }) + recordsToDelete = append(recordsToDelete, &actions.ActionRun{ + RepoID: repoID, + ID: run.ID, + }) + recordsToDelete = append(recordsToDelete, &actions.ActionArtifact{ + RepoID: repoID, + RunID: run.ID, + }) + + if err := db.WithTx(ctx, func(ctx context.Context) error { + return db.DeleteBeans(ctx, recordsToDelete...) + }); err != nil { + return err + } + + // Delete files on storage + for _, tas := range tasks { + err := RemoveLogs(ctx, tas.LogInStorage, tas.LogFilename) + if err != nil { + log.Error("remove log file %q: %v", tas.LogFilename, err) + } + } + for _, art := range artifacts { + if err := storage.ActionsArtifacts.Delete(art.StoragePath); err != nil { + log.Error("remove artifact file %q: %v", art.StoragePath, err) + } + } + + // TODO: Delete commit status? Looks like it has no direct reference to a run/task/job. Not quite feasible without modifying db models (Dangerous). + return nil +} diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 97bbdd1961169..db987958bd319 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -1121,7 +1121,7 @@ func DeleteActionRun(ctx *context.APIContext) { return } - if err := actions_model.DeleteRun(ctx, repoID, run, jobs); err != nil { + if err := actions.DeleteRun(ctx, repoID, run, jobs); err != nil { ctx.APIErrorInternal(err) return } diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 13349f3f37841..cace4b1f4878d 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -598,7 +598,7 @@ func Delete(ctx *context_module.Context) { repoID := ctx.Repo.Repository.ID - if err := actions_model.DeleteRun(ctx, repoID, run, jobs); err != nil { + if err := actions.DeleteRun(ctx, repoID, run, jobs); err != nil { ctx.HTTPError(http.StatusInternalServerError, err.Error()) return } From 0dc984ae7abc997ac3bd443124bd021854d0ebfc Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Thu, 1 May 2025 23:08:06 +0800 Subject: [PATCH 06/35] Swagger --- templates/swagger/v1_json.tmpl | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 8758b5c0a1505..459a23eae5954 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4758,6 +4758,52 @@ } } }, + "/repos/{owner}/{repo}/actions/runs/{run}": { + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Delete a workflow run", + "operationId": "deleteActionRun", + "parameters": [ + { + "type": "string", + "description": "name of the owner", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repository", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "runid of the workflow run", + "name": "run", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "$ref": "#/responses/error" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/actions/runs/{run}/artifacts": { "get": { "produces": [ From 61328b85c66c4eb07a42abc1147f8faff028b769 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Thu, 1 May 2025 23:40:18 +0800 Subject: [PATCH 07/35] LINT FIX --- modules/actions/run.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/actions/run.go b/modules/actions/run.go index 76dbd17d1bb97..1203d3e0cff38 100644 --- a/modules/actions/run.go +++ b/modules/actions/run.go @@ -1,12 +1,16 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + package actions import ( + "context" + "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/storage" - "context" ) // TODO: When deleting a run, it should at lease delete artifacts, tasks logs, database record. From c76fb69ad18b1bd4a92b651a06c6466ea34afbc2 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 15:08:46 +0800 Subject: [PATCH 08/35] Fix --- routers/api/v1/repo/action.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index db987958bd319..bdd011c2bd9f8 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -1093,9 +1093,9 @@ func DeleteActionRun(ctx *context.APIContext) { // "$ref": "#/responses/notFound" repoID := ctx.Repo.Repository.ID - runIndex := ctx.PathParamInt64("run") + runID := ctx.PathParamInt64("run") - run, err := actions_model.GetRunByIndex(ctx, repoID, runIndex) + run, err := actions_model.GetRunByID(ctx, runID) if err != nil { if errors.Is(err, util.ErrNotExist) { ctx.APIError(http.StatusNotFound, err.Error()) From 05aa0e462c124ab0ff09fd17f3b72302c718bb85 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 15:08:53 +0800 Subject: [PATCH 09/35] MOCK --- models/fixtures/action_artifact.yml | 72 ++++++++++++++++++++++++++ models/fixtures/action_run.yml | 40 +++++++++++++++ models/fixtures/action_run_job.yml | 60 ++++++++++++++++++++++ models/fixtures/action_task.yml | 80 +++++++++++++++++++++++++++++ 4 files changed, 252 insertions(+) diff --git a/models/fixtures/action_artifact.yml b/models/fixtures/action_artifact.yml index 1b00daf19817f..a7542adbf2610 100644 --- a/models/fixtures/action_artifact.yml +++ b/models/fixtures/action_artifact.yml @@ -105,3 +105,75 @@ created_unix: 1730330775 updated_unix: 1730330775 expired_unix: 1738106775 + +- + id: 24 + run_id: 795 + runner_id: 1 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + storage_path: "27/5/1730330775594233150.chunk" + file_size: 1024 + file_compressed_size: 1024 + content_encoding: "application/zip" + artifact_path: "artifact-795-1.zip" + artifact_name: "artifact-795-1" + status: 2 + created_unix: 1730330775 + updated_unix: 1730330775 + expired_unix: 1738106775 + +- + id: 25 + run_id: 795 + runner_id: 1 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + storage_path: "27/5/1730330775594233150.chunk" + file_size: 1024 + file_compressed_size: 1024 + content_encoding: "application/zip" + artifact_path: "artifact-795-2.zip" + artifact_name: "artifact-795-2" + status: 2 + created_unix: 1730330775 + updated_unix: 1730330775 + expired_unix: 1738106775 + +- + id: 26 + run_id: 796 + runner_id: 1 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + storage_path: "27/5/1730330775594233150.chunk" + file_size: 1024 + file_compressed_size: 1024 + content_encoding: "application/zip" + artifact_path: "artifact-796-1.zip" + artifact_name: "artifact-796-1" + status: 2 + created_unix: 1730330775 + updated_unix: 1730330775 + expired_unix: 1738106775 + +- + id: 27 + run_id: 796 + runner_id: 1 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + storage_path: "27/5/1730330775594233150.chunk" + file_size: 1024 + file_compressed_size: 1024 + content_encoding: "application/zip" + artifact_path: "artifact-796-2.zip" + artifact_name: "artifact-796-2" + status: 2 + created_unix: 1730330775 + updated_unix: 1730330775 + expired_unix: 1738106775 diff --git a/models/fixtures/action_run.yml b/models/fixtures/action_run.yml index 1db849352f280..9950198dc36b0 100644 --- a/models/fixtures/action_run.yml +++ b/models/fixtures/action_run.yml @@ -74,3 +74,43 @@ updated: 1683636626 need_approval: 0 approved_by: 0 + +- + id: 795 + title: "to be deleted (test)" + repo_id: 2 + owner_id: 2 + workflow_id: "test.yaml" + index: 191 + trigger_user_id: 1 + ref: "refs/heads/test" + commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" + event: "push" + is_fork_pull_request: 0 + status: 2 + started: 1683636528 + stopped: 1683636626 + created: 1683636108 + updated: 1683636626 + need_approval: 0 + approved_by: 0 + +- + id: 796 + title: "to be deleted (test)" + repo_id: 2 + owner_id: 2 + workflow_id: "test.yaml" + index: 192 + trigger_user_id: 1 + ref: "refs/heads/test" + commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" + event: "push" + is_fork_pull_request: 0 + status: 3 + started: 1683636528 + stopped: 1683636626 + created: 1683636108 + updated: 1683636626 + need_approval: 0 + approved_by: 0 diff --git a/models/fixtures/action_run_job.yml b/models/fixtures/action_run_job.yml index 8837e6ec2d80d..8f3e4fdfc0a99 100644 --- a/models/fixtures/action_run_job.yml +++ b/models/fixtures/action_run_job.yml @@ -69,3 +69,63 @@ status: 5 started: 1683636528 stopped: 1683636626 + +- + id: 198 + run_id: 795 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + name: job_1 + attempt: 1 + job_id: job_1 + task_id: 53 + status: 1 + started: 1683636528 + stopped: 1683636626 + +- + id: 199 + run_id: 795 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + name: job_2 + attempt: 1 + job_id: job_2 + task_id: 54 + status: 2 + started: 1683636528 + stopped: 1683636626 + +- + id: 200 + run_id: 796 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + name: job_1 + attempt: 1 + job_id: job_1 + task_id: 55 + status: 3 + started: 1683636528 + stopped: 1683636626 + +- + id: 201 + run_id: 796 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + name: job_2 + attempt: 1 + job_id: job_2 + task_id: 56 + status: 3 + started: 1683636528 + stopped: 1683636626 diff --git a/models/fixtures/action_task.yml b/models/fixtures/action_task.yml index 506a47d8a04dd..c3cc2d995ff8a 100644 --- a/models/fixtures/action_task.yml +++ b/models/fixtures/action_task.yml @@ -117,3 +117,83 @@ log_length: 707 log_size: 90179 log_expired: 0 +- + id: 53 + job_id: 198 + attempt: 1 + runner_id: 1 + status: 1 + started: 1683636528 + stopped: 1683636626 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784223 + token_salt: ffffffffff + token_last_eight: ffffffff + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 +- + id: 54 + job_id: 199 + attempt: 1 + runner_id: 1 + status: 2 + started: 1683636528 + stopped: 1683636626 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784224 + token_salt: ffffffffff + token_last_eight: ffffffff + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 +- + id: 55 + job_id: 200 + attempt: 1 + runner_id: 1 + status: 3 + started: 1683636528 + stopped: 1683636626 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784225 + token_salt: ffffffffff + token_last_eight: ffffffff + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 +- + id: 56 + job_id: 201 + attempt: 1 + runner_id: 1 + status: 3 + started: 1683636528 + stopped: 1683636626 + repo_id: 2 + owner_id: 2 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784226 + token_salt: ffffffffff + token_last_eight: ffffffff + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 From 5f6238ba426ac3e726e75f2ee6e081963e63f65c Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 15:39:19 +0800 Subject: [PATCH 10/35] Test --- .../api_actions_delete_run_test.go | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 tests/integration/api_actions_delete_run_test.go diff --git a/tests/integration/api_actions_delete_run_test.go b/tests/integration/api_actions_delete_run_test.go new file mode 100644 index 0000000000000..42689c18ba4f5 --- /dev/null +++ b/tests/integration/api_actions_delete_run_test.go @@ -0,0 +1,71 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/http" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/json" + api "code.gitea.io/gitea/modules/structs" + + "github.com/stretchr/testify/assert" +) + +func TestAPIActionsDeleteRun(t *testing.T) { + defer prepareTestEnvActionsArtifacts(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + testListArtifacts(t, repo, token, 2) + testListTasks(t, repo, token, true) + + req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/actions/runs/795", repo.FullName())). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusNoContent) + + testListArtifacts(t, repo, token, 0) + testListTasks(t, repo, token, false) +} + +func testListArtifacts(t *testing.T, repo *repo_model.Repository, token string, artifacts int) { + req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/runs/795/artifacts", repo.FullName())). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var listResp api.ActionArtifactsResponse + err := json.Unmarshal(resp.Body.Bytes(), &listResp) + assert.NoError(t, err) + assert.Len(t, listResp.Entries, artifacts) +} + +func testListTasks(t *testing.T, repo *repo_model.Repository, token string, expected bool) { + req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/tasks", repo.FullName())). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var listResp api.ActionTaskResponse + err := json.Unmarshal(resp.Body.Bytes(), &listResp) + assert.NoError(t, err) + findTask1 := false + findTask2 := false + for _, entry := range listResp.Entries { + if entry.ID == 53 { + findTask1 = true + continue + } + if entry.ID == 54 { + findTask2 = true + continue + } + } + assert.Equal(t, expected, findTask1) + assert.Equal(t, expected, findTask2) +} From e5a8968b7e69093678bf6f198a51d368817f40b0 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 16:42:23 +0800 Subject: [PATCH 11/35] Mock --- models/fixtures/action_task.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/models/fixtures/action_task.yml b/models/fixtures/action_task.yml index c3cc2d995ff8a..a3fa39bddc377 100644 --- a/models/fixtures/action_task.yml +++ b/models/fixtures/action_task.yml @@ -134,8 +134,8 @@ token_last_eight: ffffffff log_filename: artifact-test2/2f/47.log log_in_storage: 1 - log_length: 707 - log_size: 90179 + log_length: 0 + log_size: 0 log_expired: 0 - id: 54 @@ -154,8 +154,8 @@ token_last_eight: ffffffff log_filename: artifact-test2/2f/47.log log_in_storage: 1 - log_length: 707 - log_size: 90179 + log_length: 0 + log_size: 0 log_expired: 0 - id: 55 @@ -174,8 +174,8 @@ token_last_eight: ffffffff log_filename: artifact-test2/2f/47.log log_in_storage: 1 - log_length: 707 - log_size: 90179 + log_length: 0 + log_size: 0 log_expired: 0 - id: 56 @@ -194,6 +194,6 @@ token_last_eight: ffffffff log_filename: artifact-test2/2f/47.log log_in_storage: 1 - log_length: 707 - log_size: 90179 + log_length: 0 + log_size: 0 log_expired: 0 From 7e6e6ae7cfb9ae8357611a8387060034c34c3768 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 16:42:27 +0800 Subject: [PATCH 12/35] Test --- .../api_actions_delete_run_test.go | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/integration/api_actions_delete_run_test.go b/tests/integration/api_actions_delete_run_test.go index 42689c18ba4f5..6dde4d715e7fc 100644 --- a/tests/integration/api_actions_delete_run_test.go +++ b/tests/integration/api_actions_delete_run_test.go @@ -26,18 +26,22 @@ func TestAPIActionsDeleteRun(t *testing.T) { session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - testListArtifacts(t, repo, token, 2) - testListTasks(t, repo, token, true) + testAPIActionsDeleteRunListArtifacts(t, repo, token, 2) + testAPIActionsDeleteRunListTasks(t, repo, token, true) + testAPIActionsDeleteRun(t, repo, token, http.StatusNoContent) + testAPIActionsDeleteRunListArtifacts(t, repo, token, 0) + testAPIActionsDeleteRunListTasks(t, repo, token, false) + testAPIActionsDeleteRun(t, repo, token, http.StatusNotFound) +} + +func testAPIActionsDeleteRun(t *testing.T, repo *repo_model.Repository, token string, expected int) { req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/actions/runs/795", repo.FullName())). AddTokenAuth(token) - MakeRequest(t, req, http.StatusNoContent) - - testListArtifacts(t, repo, token, 0) - testListTasks(t, repo, token, false) + MakeRequest(t, req, expected) } -func testListArtifacts(t *testing.T, repo *repo_model.Repository, token string, artifacts int) { +func testAPIActionsDeleteRunListArtifacts(t *testing.T, repo *repo_model.Repository, token string, artifacts int) { req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/runs/795/artifacts", repo.FullName())). AddTokenAuth(token) resp := MakeRequest(t, req, http.StatusOK) @@ -47,7 +51,7 @@ func testListArtifacts(t *testing.T, repo *repo_model.Repository, token string, assert.Len(t, listResp.Entries, artifacts) } -func testListTasks(t *testing.T, repo *repo_model.Repository, token string, expected bool) { +func testAPIActionsDeleteRunListTasks(t *testing.T, repo *repo_model.Repository, token string, expected bool) { req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/tasks", repo.FullName())). AddTokenAuth(token) resp := MakeRequest(t, req, http.StatusOK) From 8922924061c37787719f4da4387e75d4a66079e2 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 17:01:51 +0800 Subject: [PATCH 13/35] Test --- models/fixtures/action_run.yml | 2 +- tests/integration/api_actions_delete_run_test.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/models/fixtures/action_run.yml b/models/fixtures/action_run.yml index 9950198dc36b0..0451533912727 100644 --- a/models/fixtures/action_run.yml +++ b/models/fixtures/action_run.yml @@ -48,7 +48,7 @@ commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" event: "push" is_fork_pull_request: 0 - status: 1 + status: 6 # running started: 1683636528 stopped: 1683636626 created: 1683636108 diff --git a/tests/integration/api_actions_delete_run_test.go b/tests/integration/api_actions_delete_run_test.go index 6dde4d715e7fc..b6c2ad5ef3666 100644 --- a/tests/integration/api_actions_delete_run_test.go +++ b/tests/integration/api_actions_delete_run_test.go @@ -35,6 +35,19 @@ func TestAPIActionsDeleteRun(t *testing.T) { testAPIActionsDeleteRun(t, repo, token, http.StatusNotFound) } +func TestAPIActionsDeleteRunRunning(t *testing.T) { + defer prepareTestEnvActionsArtifacts(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/actions/runs/793", repo.FullName())). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusBadRequest) +} + func testAPIActionsDeleteRun(t *testing.T, repo *repo_model.Repository, token string, expected int) { req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/actions/runs/795", repo.FullName())). AddTokenAuth(token) From 9435c3a3c079b9c04b75a81e37e4a1e37d585972 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 21:22:59 +0800 Subject: [PATCH 14/35] MOCK --- models/fixtures/action_artifact.yml | 36 -------------------------- models/fixtures/action_run.yml | 20 --------------- models/fixtures/action_run_job.yml | 30 ---------------------- models/fixtures/action_task.yml | 40 ----------------------------- 4 files changed, 126 deletions(-) diff --git a/models/fixtures/action_artifact.yml b/models/fixtures/action_artifact.yml index a7542adbf2610..ee8ef0d5cec48 100644 --- a/models/fixtures/action_artifact.yml +++ b/models/fixtures/action_artifact.yml @@ -141,39 +141,3 @@ created_unix: 1730330775 updated_unix: 1730330775 expired_unix: 1738106775 - -- - id: 26 - run_id: 796 - runner_id: 1 - repo_id: 2 - owner_id: 2 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - storage_path: "27/5/1730330775594233150.chunk" - file_size: 1024 - file_compressed_size: 1024 - content_encoding: "application/zip" - artifact_path: "artifact-796-1.zip" - artifact_name: "artifact-796-1" - status: 2 - created_unix: 1730330775 - updated_unix: 1730330775 - expired_unix: 1738106775 - -- - id: 27 - run_id: 796 - runner_id: 1 - repo_id: 2 - owner_id: 2 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - storage_path: "27/5/1730330775594233150.chunk" - file_size: 1024 - file_compressed_size: 1024 - content_encoding: "application/zip" - artifact_path: "artifact-796-2.zip" - artifact_name: "artifact-796-2" - status: 2 - created_unix: 1730330775 - updated_unix: 1730330775 - expired_unix: 1738106775 diff --git a/models/fixtures/action_run.yml b/models/fixtures/action_run.yml index 0451533912727..ae7dc481ec84a 100644 --- a/models/fixtures/action_run.yml +++ b/models/fixtures/action_run.yml @@ -94,23 +94,3 @@ updated: 1683636626 need_approval: 0 approved_by: 0 - -- - id: 796 - title: "to be deleted (test)" - repo_id: 2 - owner_id: 2 - workflow_id: "test.yaml" - index: 192 - trigger_user_id: 1 - ref: "refs/heads/test" - commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" - event: "push" - is_fork_pull_request: 0 - status: 3 - started: 1683636528 - stopped: 1683636626 - created: 1683636108 - updated: 1683636626 - need_approval: 0 - approved_by: 0 diff --git a/models/fixtures/action_run_job.yml b/models/fixtures/action_run_job.yml index 8f3e4fdfc0a99..72f862722448c 100644 --- a/models/fixtures/action_run_job.yml +++ b/models/fixtures/action_run_job.yml @@ -99,33 +99,3 @@ status: 2 started: 1683636528 stopped: 1683636626 - -- - id: 200 - run_id: 796 - repo_id: 2 - owner_id: 2 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - name: job_1 - attempt: 1 - job_id: job_1 - task_id: 55 - status: 3 - started: 1683636528 - stopped: 1683636626 - -- - id: 201 - run_id: 796 - repo_id: 2 - owner_id: 2 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - name: job_2 - attempt: 1 - job_id: job_2 - task_id: 56 - status: 3 - started: 1683636528 - stopped: 1683636626 diff --git a/models/fixtures/action_task.yml b/models/fixtures/action_task.yml index a3fa39bddc377..76fdac343bd10 100644 --- a/models/fixtures/action_task.yml +++ b/models/fixtures/action_task.yml @@ -157,43 +157,3 @@ log_length: 0 log_size: 0 log_expired: 0 -- - id: 55 - job_id: 200 - attempt: 1 - runner_id: 1 - status: 3 - started: 1683636528 - stopped: 1683636626 - repo_id: 2 - owner_id: 2 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784225 - token_salt: ffffffffff - token_last_eight: ffffffff - log_filename: artifact-test2/2f/47.log - log_in_storage: 1 - log_length: 0 - log_size: 0 - log_expired: 0 -- - id: 56 - job_id: 201 - attempt: 1 - runner_id: 1 - status: 3 - started: 1683636528 - stopped: 1683636626 - repo_id: 2 - owner_id: 2 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784226 - token_salt: ffffffffff - token_last_eight: ffffffff - log_filename: artifact-test2/2f/47.log - log_in_storage: 1 - log_length: 0 - log_size: 0 - log_expired: 0 From 1b759fbdd4ba06d167c329cdfa19b26162fce57b Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 21:23:02 +0800 Subject: [PATCH 15/35] Test --- tests/integration/actions_delete_run_test.go | 179 +++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 tests/integration/actions_delete_run_test.go diff --git a/tests/integration/actions_delete_run_test.go b/tests/integration/actions_delete_run_test.go new file mode 100644 index 0000000000000..77932e80fc0a1 --- /dev/null +++ b/tests/integration/actions_delete_run_test.go @@ -0,0 +1,179 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + runnerv1 "code.gitea.io/actions-proto-go/runner/v1" + actions_model "code.gitea.io/gitea/models/actions" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/routers/web/repo/actions" + "fmt" + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/timestamppb" + "net/http" + "net/url" + "testing" + "time" +) + +func TestActionsDeleteRun(t *testing.T) { + now := time.Now() + testCase := struct { + treePath string + fileContent string + outcomes map[string]*mockTaskOutcome + expectedStatuses map[string]string + }{ + treePath: ".gitea/workflows/test1.yml", + fileContent: `name: test1 +on: + push: + paths: + - .gitea/workflows/test1.yml +jobs: + job1: + runs-on: ubuntu-latest + steps: + - run: echo job1 + job2: + runs-on: ubuntu-latest + steps: + - run: echo job2 + job3: + runs-on: ubuntu-latest + steps: + - run: echo job3 +`, + outcomes: map[string]*mockTaskOutcome{ + "job1": { + result: runnerv1.Result_RESULT_SUCCESS, + logRows: []*runnerv1.LogRow{ + { + Time: timestamppb.New(now.Add(4 * time.Second)), + Content: " \U0001F433 docker create image", + }, + { + Time: timestamppb.New(now.Add(5 * time.Second)), + Content: "job1", + }, + { + Time: timestamppb.New(now.Add(6 * time.Second)), + Content: "\U0001F3C1 Job succeeded", + }, + }, + }, + "job2": { + result: runnerv1.Result_RESULT_SUCCESS, + logRows: []*runnerv1.LogRow{ + { + Time: timestamppb.New(now.Add(4 * time.Second)), + Content: " \U0001F433 docker create image", + }, + { + Time: timestamppb.New(now.Add(5 * time.Second)), + Content: "job2", + }, + { + Time: timestamppb.New(now.Add(6 * time.Second)), + Content: "\U0001F3C1 Job succeeded", + }, + }, + }, + "job3": { + result: runnerv1.Result_RESULT_SUCCESS, + logRows: []*runnerv1.LogRow{ + { + Time: timestamppb.New(now.Add(4 * time.Second)), + Content: " \U0001F433 docker create image", + }, + { + Time: timestamppb.New(now.Add(5 * time.Second)), + Content: "job3", + }, + { + Time: timestamppb.New(now.Add(6 * time.Second)), + Content: "\U0001F3C1 Job succeeded", + }, + }, + }, + }, + expectedStatuses: map[string]string{ + "job1": actions_model.StatusSuccess.String(), + "job2": actions_model.StatusSuccess.String(), + "job3": actions_model.StatusSuccess.String(), + }, + } + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + + apiRepo := createActionsTestRepo(t, token, "actions-delete-run-test", false) + runner := newMockRunner() + runner.registerAsRepoRunner(t, user2.Name, apiRepo.Name, "mock-runner", []string{"ubuntu-latest"}, false) + + opts := getWorkflowCreateFileOptions(user2, apiRepo.DefaultBranch, "create "+testCase.treePath, testCase.fileContent) + createWorkflowFile(t, token, user2.Name, apiRepo.Name, testCase.treePath, opts) + + runIndex := "" + for i := 0; i < len(testCase.outcomes); i++ { + task := runner.fetchTask(t) + jobName := getTaskJobNameByTaskID(t, token, user2.Name, apiRepo.Name, task.Id) + outcome := testCase.outcomes[jobName] + assert.NotNil(t, outcome) + runner.execTask(t, task, outcome) + runIndex = task.Context.GetFields()["run_number"].GetStringValue() + assert.Equal(t, "1", runIndex) + } + + for i := 0; i < len(testCase.outcomes); i++ { + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d", user2.Name, apiRepo.Name, runIndex, i), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + resp := session.MakeRequest(t, req, http.StatusOK) + var listResp actions.ViewResponse + err := json.Unmarshal(resp.Body.Bytes(), &listResp) + assert.NoError(t, err) + assert.Len(t, listResp.State.Run.Jobs, 3) + + req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d/logs", user2.Name, apiRepo.Name, runIndex, i)). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) + } + + req := NewRequestWithValues(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s", user2.Name, apiRepo.Name, runIndex), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusOK) + + req = NewRequestWithValues(t, "DELETE", fmt.Sprintf("/%s/%s/actions/runs/%s/delete", user2.Name, apiRepo.Name, runIndex), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusOK) + + req = NewRequestWithValues(t, "DELETE", fmt.Sprintf("/%s/%s/actions/runs/%s/delete", user2.Name, apiRepo.Name, runIndex), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusNotFound) + + req = NewRequestWithValues(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s", user2.Name, apiRepo.Name, runIndex), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusNotFound) + + for i := 0; i < len(testCase.outcomes); i++ { + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d", user2.Name, apiRepo.Name, runIndex, i), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusNotFound) + + req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d/logs", user2.Name, apiRepo.Name, runIndex, i)). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusNotFound) + } + }) +} From cf5bcfb235c4eb2656848bbf6f3308035d1af716 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Fri, 2 May 2025 21:26:04 +0800 Subject: [PATCH 16/35] LINT FIX --- tests/integration/actions_delete_run_test.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/integration/actions_delete_run_test.go b/tests/integration/actions_delete_run_test.go index 77932e80fc0a1..3e3e5161ec48b 100644 --- a/tests/integration/actions_delete_run_test.go +++ b/tests/integration/actions_delete_run_test.go @@ -4,20 +4,22 @@ package integration import ( - runnerv1 "code.gitea.io/actions-proto-go/runner/v1" + "fmt" + "net/http" + "net/url" + "testing" + "time" + actions_model "code.gitea.io/gitea/models/actions" auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/routers/web/repo/actions" - "fmt" + + runnerv1 "code.gitea.io/actions-proto-go/runner/v1" "github.com/stretchr/testify/assert" "google.golang.org/protobuf/types/known/timestamppb" - "net/http" - "net/url" - "testing" - "time" ) func TestActionsDeleteRun(t *testing.T) { From 1b5be8105c6ab13b5cc4ed02b4dcff6191978903 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Sat, 3 May 2025 18:06:18 +0800 Subject: [PATCH 17/35] UPDATE --- routers/web/web.go | 2 +- tests/integration/actions_delete_run_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/routers/web/web.go b/routers/web/web.go index 8f53af56c5713..866401252d9f3 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1447,7 +1447,7 @@ func registerWebRoutes(m *web.Router) { }) m.Post("/cancel", reqRepoActionsWriter, actions.Cancel) m.Post("/approve", reqRepoActionsWriter, actions.Approve) - m.Delete("/delete", reqRepoActionsWriter, actions.Delete) + m.Post("/delete", reqRepoActionsWriter, actions.Delete) m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView) m.Delete("/artifacts/{artifact_name}", reqRepoActionsWriter, actions.ArtifactsDeleteView) m.Post("/rerun", reqRepoActionsWriter, actions.Rerun) diff --git a/tests/integration/actions_delete_run_test.go b/tests/integration/actions_delete_run_test.go index 3e3e5161ec48b..22f9a1f7409da 100644 --- a/tests/integration/actions_delete_run_test.go +++ b/tests/integration/actions_delete_run_test.go @@ -152,12 +152,12 @@ jobs: }) session.MakeRequest(t, req, http.StatusOK) - req = NewRequestWithValues(t, "DELETE", fmt.Sprintf("/%s/%s/actions/runs/%s/delete", user2.Name, apiRepo.Name, runIndex), map[string]string{ + req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%s/delete", user2.Name, apiRepo.Name, runIndex), map[string]string{ "_csrf": GetUserCSRFToken(t, session), }) session.MakeRequest(t, req, http.StatusOK) - req = NewRequestWithValues(t, "DELETE", fmt.Sprintf("/%s/%s/actions/runs/%s/delete", user2.Name, apiRepo.Name, runIndex), map[string]string{ + req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%s/delete", user2.Name, apiRepo.Name, runIndex), map[string]string{ "_csrf": GetUserCSRFToken(t, session), }) session.MakeRequest(t, req, http.StatusNotFound) From 63d2cda1c42abefdeef52481394c8e4db2d9ea25 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Sat, 3 May 2025 18:35:19 +0800 Subject: [PATCH 18/35] Button --- options/locale/locale_en-US.ini | 2 ++ templates/repo/actions/runs_list.tmpl | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a8fabc9ca1014..de960f46edf31 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3806,6 +3806,8 @@ runs.no_workflows.documentation = For more information on Gitea Actions, see This action cannot be undone. workflow.disable = Disable Workflow workflow.disable_success = Workflow '%s' disabled successfully. diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index fa1adb3e3ba2e..be3b15285eed9 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -36,6 +36,13 @@
{{svg "octicon-calendar" 16}}{{DateUtils.TimeSince .Updated}}
{{svg "octicon-stopwatch" 16}}{{.Duration}}
+ {{end}} From 08f71c31d6737868dd17a921620b205dbb2500ee Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Sat, 3 May 2025 19:14:00 +0800 Subject: [PATCH 19/35] Button --- templates/repo/actions/runs_list.tmpl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index be3b15285eed9..44ea2af682d86 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -36,13 +36,16 @@
{{svg "octicon-calendar" 16}}{{DateUtils.TimeSince .Updated}}
{{svg "octicon-stopwatch" 16}}{{.Duration}}
- + + {{if .Link}} + + {{end}} {{end}} From 933ffee12288b150753176625a43c176eb26e330 Mon Sep 17 00:00:00 2001 From: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Date: Sat, 3 May 2025 19:20:17 +0800 Subject: [PATCH 20/35] Button --- templates/repo/actions/runs_list.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index 44ea2af682d86..7a71a5d245268 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -37,7 +37,7 @@
{{svg "octicon-stopwatch" 16}}{{.Duration}}
- {{if .Link}} + {{if and (.Link) (or (eq .Status.String "success") (eq .Status.String "skipped") (eq .Status.String "cancelled"))}}