diff --git a/modules/structs/repo_actions.go b/modules/structs/repo_actions.go new file mode 100644 index 0000000000..ca894c14f9 --- /dev/null +++ b/modules/structs/repo_actions.go @@ -0,0 +1,23 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package structs + +import ( + "time" +) + +// Tag represents a repository tag +type ActionTask struct { + ID int64 `json:"id"` + JobName string `json:"job_name"` + WorkflowID string `json:"workflow_id"` + Title string `json:"title"` + Status string `json:"status"` + Commit string `json:"commit"` + Duration string `json:"duration"` + // swagger:strfmt date-time + Started time.Time `json:"started,omitempty"` + // swagger:strfmt date-time + Stopped time.Time `json:"stopped,omitempty"` +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 9613bd610d..f441db5ffd 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -994,6 +994,9 @@ func Routes() *web.Route { m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateTagOption{}), repo.CreateTag) m.Delete("/*", reqToken(), repo.DeleteTag) }, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true)) + m.Group("/actions", func() { + m.Get("/tasks", repo.ListActionTasks) + }, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true)) m.Group("/keys", func() { m.Combo("").Get(repo.ListDeployKeys). Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey) diff --git a/routers/api/v1/repo/actions.go b/routers/api/v1/repo/actions.go new file mode 100644 index 0000000000..fbf863ac5e --- /dev/null +++ b/routers/api/v1/repo/actions.go @@ -0,0 +1,69 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "net/http" + + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/context" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/convert" +) + +// ListActionTasks list all the actions of a repository +func ListActionTasks(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/actions/tasks repository ListActionTasks + // --- + // summary: List a repository's action tasks + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results, default maximum page size is 50 + // type: integer + // responses: + // "200": + // "$ref": "#/responses/TasksList" + page := ctx.FormInt("page") + limit := convert.ToCorrectPageSize(ctx.FormInt("limit")) + + opts := actions_model.FindTaskOptions{ + RepoID: ctx.Repo.Repository.ID, + ListOptions: db.ListOptions{ + Page: page, + PageSize: limit, + }, + Status: actions_model.StatusUnknown, // Unknown means all + IDOrderDesc: true, + } + tasks, err := actions_model.FindTasks(ctx, opts) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetTags", err) + return + } + + apiActionTasks := make([]*api.ActionTask, len(tasks)) + for i := range tasks { + apiActionTasks[i] = convert.ToActionTask(ctx, ctx.Repo.Repository, tasks[i]) + } + + ctx.JSON(http.StatusOK, &apiActionTasks) +} diff --git a/services/convert/convert.go b/services/convert/convert.go index a7a777e8bd..8ca215938d 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -11,6 +11,7 @@ import ( "strings" "time" + actions_model "code.gitea.io/gitea/models/actions" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" @@ -179,6 +180,24 @@ func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag { } } +// ToActionTask convert a actions_model.ActionTask to an api.ActionTask +func ToActionTask(ctx context.Context, repo *repo_model.Repository, t *actions_model.ActionTask) *api.ActionTask { + if err := t.LoadAttributes(ctx); err != nil { + log.Warn("LoadAttributes of ActionTask: %v", err) + } + return &api.ActionTask{ + ID: t.ID, + JobName: t.Job.Name, + WorkflowID: t.Job.Run.WorkflowID, + Title: t.Job.Run.Title, + Status: t.Status.String(), + Commit: t.CommitSHA, + Duration: t.Duration().String(), + Started: t.Started.AsLocalTime(), + Stopped: t.Stopped.AsLocalTime(), + } +} + // ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification func ToVerification(ctx context.Context, c *git.Commit) *api.PayloadCommitVerification { verif := asymkey_model.ParseCommitWithSignature(ctx, c) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 5e75f6f8b4..1765879c92 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -12313,6 +12313,51 @@ } } }, + "/repos/{owner}/{repo}/actions/tasks": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "List a repository's actions tasks", + "operationId": "ListActionTasks", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "page number of results to return (1-based)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size of results, default maximum page size is 50", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/TasksList" + } + } + } + }, "/repos/{owner}/{repo}/teams": { "get": { "produces": [ @@ -21414,6 +21459,51 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "Task": { + "description": "Task represents a task", + "type": "object", + "properties": { + "id": { + "type": "string", + "x-go-name": "ID" + }, + "job_name": { + "type": "string", + "x-go-name": "JobName" + }, + "workflow_id": { + "type": "string", + "x-go-name": "WorkflowID" + }, + "title": { + "type": "string", + "x-go-name": "Title" + }, + "status": { + "type": "string", + "x-go-name": "Status" + }, + "commit": { + "type": "string", + "x-go-name": "Commit" + }, + "duration": { + "type": "string", + "x-go-name": "Duration" + }, + "started": { + "type": "string", + "format": "date-time", + "x-go-name": "Started" + }, + "stopped": { + "type": "string", + "format": "date-time", + "x-go-name": "Stopped" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "ServerVersion": { "description": "ServerVersion wraps the version of the server", "type": "object", @@ -23000,6 +23090,15 @@ } } }, + "TasksList": { + "description": "TasksList", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Task" + } + } + }, "ServerVersion": { "description": "ServerVersion", "schema": {