From 4ef99810a9dead1435cf44a0ecc53b65e490467f Mon Sep 17 00:00:00 2001
From: qwerty287 <80460567+qwerty287@users.noreply.github.com>
Date: Wed, 26 Oct 2022 01:23:28 +0200
Subject: [PATCH] Allow to run cron manually (#1338)
Closes #1154
---
server/api/cron.go | 32 +++++++++++++++++++
server/api/pipeline.go | 6 ++++
server/cron/cron.go | 6 ++--
server/cron/cron_test.go | 2 +-
server/router/api.go | 1 +
web/components.d.ts | 1 +
web/src/assets/locales/en.json | 1 +
web/src/components/atomic/Icon.vue | 4 ++-
web/src/components/repo/settings/CronTab.vue | 25 +++++++++++----
.../components/repo/settings/GeneralTab.vue | 10 +++---
web/src/lib/api/index.ts | 4 +++
11 files changed, 76 insertions(+), 16 deletions(-)
diff --git a/server/api/cron.go b/server/api/cron.go
index 714bda4a468..cdf42f54e1f 100644
--- a/server/api/cron.go
+++ b/server/api/cron.go
@@ -23,6 +23,7 @@ import (
"github.com/woodpecker-ci/woodpecker/server"
cronScheduler "github.com/woodpecker-ci/woodpecker/server/cron"
"github.com/woodpecker-ci/woodpecker/server/model"
+ "github.com/woodpecker-ci/woodpecker/server/pipeline"
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
"github.com/woodpecker-ci/woodpecker/server/store"
)
@@ -45,6 +46,37 @@ func GetCron(c *gin.Context) {
c.JSON(200, cron)
}
+// RunCron starts a cron job now.
+func RunCron(c *gin.Context) {
+ repo := session.Repo(c)
+ _store := store.FromContext(c)
+ id, err := strconv.ParseInt(c.Param("cron"), 10, 64)
+ if err != nil {
+ c.String(400, "Error parsing cron id. %s", err)
+ return
+ }
+
+ cron, err := _store.CronFind(repo, id)
+ if err != nil {
+ c.String(http.StatusNotFound, "Error getting cron %q. %s", id, err)
+ return
+ }
+
+ repo, newPipeline, err := cronScheduler.CreatePipeline(c, _store, server.Config.Services.Remote, cron)
+ if err != nil {
+ c.String(http.StatusInternalServerError, "Error creating pipeline for cron %q. %s", id, err)
+ return
+ }
+
+ pl, err := pipeline.Create(c, _store, repo, newPipeline)
+ if err != nil {
+ handlePipelineErr(c, err)
+ return
+ }
+
+ c.JSON(200, pl)
+}
+
// PostCron persists the cron job to the database.
func PostCron(c *gin.Context) {
repo := session.Repo(c)
diff --git a/server/api/pipeline.go b/server/api/pipeline.go
index db5259f802b..c6b7600b7ad 100644
--- a/server/api/pipeline.go
+++ b/server/api/pipeline.go
@@ -21,6 +21,7 @@ package api
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io"
"net/http"
@@ -28,6 +29,7 @@ import (
"time"
"github.com/woodpecker-ci/woodpecker/server"
+ "github.com/woodpecker-ci/woodpecker/server/store/types"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
@@ -95,6 +97,10 @@ func GetPipelines(c *gin.Context) {
pipelines, err := store.FromContext(c).GetPipelineList(repo, page)
if err != nil {
+ if errors.Is(err, types.RecordNotExist) {
+ c.AbortWithStatus(http.StatusNotFound)
+ return
+ }
c.AbortWithStatus(http.StatusInternalServerError)
return
}
diff --git a/server/cron/cron.go b/server/cron/cron.go
index c9f5dc25316..919b856f053 100644
--- a/server/cron/cron.go
+++ b/server/cron/cron.go
@@ -96,16 +96,16 @@ func runCron(store store.Store, remote remote.Remote, cron *model.Cron, now time
return nil
}
- repo, newBuild, err := createBuild(ctx, store, remote, cron)
+ repo, newPipeline, err := CreatePipeline(ctx, store, remote, cron)
if err != nil {
return err
}
- _, err = pipeline.Create(ctx, store, repo, newBuild)
+ _, err = pipeline.Create(ctx, store, repo, newPipeline)
return err
}
-func createBuild(ctx context.Context, store store.Store, remote remote.Remote, cron *model.Cron) (*model.Repo, *model.Pipeline, error) {
+func CreatePipeline(ctx context.Context, store store.Store, remote remote.Remote, cron *model.Cron) (*model.Repo, *model.Pipeline, error) {
repo, err := store.GetRepo(cron.RepoID)
if err != nil {
return nil, nil, err
diff --git a/server/cron/cron_test.go b/server/cron/cron_test.go
index 831c156ca3d..94b319d0df4 100644
--- a/server/cron/cron_test.go
+++ b/server/cron/cron_test.go
@@ -49,7 +49,7 @@ func TestCreateBuild(t *testing.T) {
store.On("GetUser", mock.Anything).Return(creator, nil)
remote.On("BranchHead", mock.Anything, creator, repo1, "default").Return("sha1", nil)
- _, pipeline, err := createBuild(ctx, store, remote, &model.Cron{
+ _, pipeline, err := CreatePipeline(ctx, store, remote, &model.Cron{
Name: "test",
})
assert.NoError(t, err)
diff --git a/server/router/api.go b/server/router/api.go
index fbb413becf5..357eb5be891 100644
--- a/server/router/api.go
+++ b/server/router/api.go
@@ -114,6 +114,7 @@ func apiRoutes(e *gin.Engine) {
repo.GET("/cron", session.MustPush, api.GetCronList)
repo.POST("/cron", session.MustPush, api.PostCron)
repo.GET("/cron/:cron", session.MustPush, api.GetCron)
+ repo.POST("/cron/:cron", session.MustPush, api.RunCron)
repo.PATCH("/cron/:cron", session.MustPush, api.PatchCron)
repo.DELETE("/cron/:cron", session.MustPush, api.DeleteCron)
diff --git a/web/components.d.ts b/web/components.d.ts
index caf10baec2e..992bc6a15e2 100644
--- a/web/components.d.ts
+++ b/web/components.d.ts
@@ -32,6 +32,7 @@ declare module '@vue/runtime-core' {
IIcBaselineFileDownload: typeof import('~icons/ic/baseline-file-download')['default']
IIcBaselineFileDownloadOff: typeof import('~icons/ic/baseline-file-download-off')['default']
IIcBaselineHealing: typeof import('~icons/ic/baseline-healing')['default']
+ IIcBaselinePlayArrow: typeof import('~icons/ic/baseline-play-arrow')['default']
IIconoirArrowLeft: typeof import('~icons/iconoir/arrow-left')['default']
IIconParkOutlineAlarmClock: typeof import('~icons/icon-park-outline/alarm-clock')['default']
IIcRoundLightMode: typeof import('~icons/ic/round-light-mode')['default']
diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json
index 0ce845afc09..b11aef09633 100644
--- a/web/src/assets/locales/en.json
+++ b/web/src/assets/locales/en.json
@@ -154,6 +154,7 @@
"deleted": "Cron deleted",
"next_exec": "Next execution",
"not_executed_yet": "Not executed yet",
+ "run": "Run now",
"branch": {
"title": "Branch",
"placeholder": "Branch (uses default branch if empty)"
diff --git a/web/src/components/atomic/Icon.vue b/web/src/components/atomic/Icon.vue
index ed5671fda6a..16f5c4d7be5 100644
--- a/web/src/components/atomic/Icon.vue
+++ b/web/src/components/atomic/Icon.vue
@@ -41,6 +41,7 @@