From 2ae8c7ab1cc1311a493fa4efa205412664f54f96 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 24 Aug 2020 16:48:15 +0100 Subject: [PATCH] Add cron running API (#12421) * Add cron running API Signed-off-by: Andrew Thornton * Apply suggestions from code review * placate-swagger Signed-off-by: Andrew Thornton * return not found Signed-off-by: Andrew Thornton * Apply suggestions from code review Co-authored-by: techknowlogick --- models/list_options.go | 8 +++ modules/structs/cron.go | 16 ++++++ routers/api/v1/admin/cron.go | 86 +++++++++++++++++++++++++++ routers/api/v1/api.go | 4 ++ routers/api/v1/swagger/cron.go | 16 ++++++ templates/swagger/v1_json.tmpl | 102 +++++++++++++++++++++++++++++++++ 6 files changed, 232 insertions(+) create mode 100644 modules/structs/cron.go create mode 100644 routers/api/v1/admin/cron.go create mode 100644 routers/api/v1/swagger/cron.go diff --git a/models/list_options.go b/models/list_options.go index 62c0944cc8..0912355352 100644 --- a/models/list_options.go +++ b/models/list_options.go @@ -37,6 +37,14 @@ func (opts ListOptions) setEnginePagination(e Engine) Engine { return e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) } +// GetStartEnd returns the start and end of the ListOptions +func (opts ListOptions) GetStartEnd() (start, end int) { + opts.setDefaultValues() + start = (opts.Page - 1) * opts.PageSize + end = start + opts.Page + return +} + func (opts ListOptions) setDefaultValues() { if opts.PageSize <= 0 { opts.PageSize = setting.API.DefaultPagingNum diff --git a/modules/structs/cron.go b/modules/structs/cron.go new file mode 100644 index 0000000000..f52a5ed3c9 --- /dev/null +++ b/modules/structs/cron.go @@ -0,0 +1,16 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package structs + +import "time" + +// Cron represents a Cron task +type Cron struct { + Name string `json:"name"` + Schedule string `json:"schedule"` + Next time.Time `json:"next"` + Prev time.Time `json:"prev"` + ExecTimes int64 `json:"exec_times"` +} diff --git a/routers/api/v1/admin/cron.go b/routers/api/v1/admin/cron.go new file mode 100644 index 0000000000..2531346fcb --- /dev/null +++ b/routers/api/v1/admin/cron.go @@ -0,0 +1,86 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package admin + +import ( + "net/http" + + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/cron" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/routers/api/v1/utils" +) + +// ListCronTasks api for getting cron tasks +func ListCronTasks(ctx *context.APIContext) { + // swagger:operation GET /admin/cron admin adminCronList + // --- + // summary: List cron tasks + // produces: + // - application/json + // parameters: + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results + // type: integer + // responses: + // "200": + // "$ref": "#/responses/CronList" + // "403": + // "$ref": "#/responses/forbidden" + tasks := cron.ListTasks() + listOpts := utils.GetListOptions(ctx) + start, end := listOpts.GetStartEnd() + + if len(tasks) > listOpts.PageSize { + tasks = tasks[start:end] + } + + res := make([]structs.Cron, len(tasks)) + for i, task := range tasks { + res[i] = structs.Cron{ + Name: task.Name, + Schedule: task.Spec, + Next: task.Next, + Prev: task.Prev, + ExecTimes: task.ExecTimes, + } + } + ctx.JSON(http.StatusOK, res) +} + +// PostCronTask api for getting cron tasks +func PostCronTask(ctx *context.APIContext) { + // swagger:operation POST /admin/cron/{task} admin adminCronRun + // --- + // summary: Run cron task + // produces: + // - application/json + // parameters: + // - name: task + // in: path + // description: task to run + // type: string + // required: true + // responses: + // "204": + // "$ref": "#/responses/empty" + // "404": + // "$ref": "#/responses/notFound" + task := cron.GetTask(ctx.Params(":task")) + if task == nil { + ctx.NotFound() + return + } + task.Run() + log.Trace("Cron Task %s started by admin(%s)", task.Name, ctx.User.Name) + + ctx.Status(http.StatusNoContent) +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 506e6a3ec0..ab7ef6d6f7 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -934,6 +934,10 @@ func RegisterRoutes(m *macaron.Macaron) { }) m.Group("/admin", func() { + m.Group("/cron", func() { + m.Get("", admin.ListCronTasks) + m.Post("/:task", admin.PostCronTask) + }) m.Get("/orgs", admin.GetAllOrgs) m.Group("/users", func() { m.Get("", admin.GetAllUsers) diff --git a/routers/api/v1/swagger/cron.go b/routers/api/v1/swagger/cron.go new file mode 100644 index 0000000000..85f2ed0e35 --- /dev/null +++ b/routers/api/v1/swagger/cron.go @@ -0,0 +1,16 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package swagger + +import ( + api "code.gitea.io/gitea/modules/structs" +) + +// CronList +// swagger:response CronList +type swaggerResponseCronList struct { + // in:body + Body []api.Cron `json:"body"` +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index ec4570b488..d9c8aeb87d 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -23,6 +23,69 @@ }, "basePath": "{{AppSubUrl}}/api/v1", "paths": { + "/admin/cron": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "List cron tasks", + "operationId": "adminCronList", + "parameters": [ + { + "type": "integer", + "description": "page number of results to return (1-based)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size of results", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/CronList" + }, + "403": { + "$ref": "#/responses/forbidden" + } + } + } + }, + "/admin/cron/{task}": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "Run cron task", + "operationId": "adminCronRun", + "parameters": [ + { + "type": "string", + "description": "task to run", + "name": "task", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "$ref": "#/responses/empty" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/admin/orgs": { "get": { "produces": [ @@ -11931,6 +11994,36 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "Cron": { + "description": "Cron represents a Cron task", + "type": "object", + "properties": { + "exec_times": { + "type": "integer", + "format": "int64", + "x-go-name": "ExecTimes" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "next": { + "type": "string", + "format": "date-time", + "x-go-name": "Next" + }, + "prev": { + "type": "string", + "format": "date-time", + "x-go-name": "Prev" + }, + "schedule": { + "type": "string", + "x-go-name": "Schedule" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "DeleteEmailOption": { "description": "DeleteEmailOption options when deleting email addresses", "type": "object", @@ -15027,6 +15120,15 @@ "$ref": "#/definitions/ContentsResponse" } }, + "CronList": { + "description": "CronList", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Cron" + } + } + }, "DeployKey": { "description": "DeployKey", "schema": {