From f0b773e0ced9110f34326398e5b6c55ad6e25201 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Thu, 29 Jun 2023 05:58:56 +0300 Subject: [PATCH] Support downloading raw task logs (#24451) Hi! This pull request adds support for downloading raw task logs for Gitea Actions, similar to Github Actions It looks like the following: ![image](https://user-images.githubusercontent.com/945339/235376746-405d5019-710b-468b-8113-9e82eab8e752.png) --- modules/actions/log.go | 4 +- options/locale/locale_en-US.ini | 1 + routers/web/repo/actions/view.go | 50 ++++++++++++++++++++++++ routers/web/web.go | 1 + templates/repo/actions/view.tmpl | 1 + web_src/js/components/RepoActionView.vue | 5 +++ web_src/js/svg.js | 2 + 7 files changed, 62 insertions(+), 2 deletions(-) diff --git a/modules/actions/log.go b/modules/actions/log.go index 36bed931fa..cdf18646aa 100644 --- a/modules/actions/log.go +++ b/modules/actions/log.go @@ -73,7 +73,7 @@ func WriteLogs(ctx context.Context, filename string, offset int64, rows []*runne } func ReadLogs(ctx context.Context, inStorage bool, filename string, offset, limit int64) ([]*runnerv1.LogRow, error) { - f, err := openLogs(ctx, inStorage, filename) + f, err := OpenLogs(ctx, inStorage, filename) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func RemoveLogs(ctx context.Context, inStorage bool, filename string) error { return nil } -func openLogs(ctx context.Context, inStorage bool, filename string) (io.ReadSeekCloser, error) { +func OpenLogs(ctx context.Context, inStorage bool, filename string) (io.ReadSeekCloser, error) { if !inStorage { name := DBFSPrefix + filename f, err := dbfs.Open(ctx, name) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 6de0258051..be90e5366c 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -129,6 +129,7 @@ concept_user_organization = Organization show_timestamps = Show timestamps show_log_seconds = Show seconds show_full_screen = Show full screen +download_logs = Download logs confirm_delete_selected = Confirm to delete all selected items? diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 7c2e9d63d6..537bc61807 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net/http" + "strings" "time" actions_model "code.gitea.io/gitea/models/actions" @@ -310,6 +311,55 @@ func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob) erro return nil } +func Logs(ctx *context_module.Context) { + runIndex := ctx.ParamsInt64("run") + jobIndex := ctx.ParamsInt64("job") + + job, _ := getRunJobs(ctx, runIndex, jobIndex) + if ctx.Written() { + return + } + if job.TaskID == 0 { + ctx.Error(http.StatusNotFound, "job is not started") + return + } + + err := job.LoadRun(ctx) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + + task, err := actions_model.GetTaskByID(ctx, job.TaskID) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + if task.LogExpired { + ctx.Error(http.StatusNotFound, "logs have been cleaned up") + return + } + + reader, err := actions.OpenLogs(ctx, task.LogInStorage, task.LogFilename) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + defer reader.Close() + + workflowName := job.Run.WorkflowID + if p := strings.Index(workflowName, "."); p > 0 { + workflowName = workflowName[0:p] + } + ctx.ServeContent(reader, &context_module.ServeHeaderOptions{ + Filename: fmt.Sprintf("%v-%v-%v.log", workflowName, job.Name, task.ID), + ContentLength: &task.LogSize, + ContentType: "text/plain", + ContentTypeCharset: "utf-8", + Disposition: "attachment", + }) +} + func Cancel(ctx *context_module.Context) { runIndex := ctx.ParamsInt64("run") diff --git a/routers/web/web.go b/routers/web/web.go index 26ad2d54c3..a5465eb041 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1207,6 +1207,7 @@ func registerRoutes(m *web.Route) { Get(actions.View). Post(web.Bind(actions.ViewRequest{}), actions.ViewPost) m.Post("/rerun", reqRepoActionsWriter, actions.RerunOne) + m.Get("/logs", actions.Logs) }) m.Post("/cancel", reqRepoActionsWriter, actions.Cancel) m.Post("/approve", reqRepoActionsWriter, actions.Approve) diff --git a/templates/repo/actions/view.tmpl b/templates/repo/actions/view.tmpl index 297232fca0..7b07aa155b 100644 --- a/templates/repo/actions/view.tmpl +++ b/templates/repo/actions/view.tmpl @@ -22,6 +22,7 @@ data-locale-show-timestamps="{{.locale.Tr "show_timestamps"}}" data-locale-show-log-seconds="{{.locale.Tr "show_log_seconds"}}" data-locale-show-full-screen="{{.locale.Tr "show_full_screen"}}" + data-locale-download-logs="{{.locale.Tr "download_logs"}}" > diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index dcbb598052..7c65d5a131 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -74,6 +74,10 @@