Skip to content

Commit

Permalink
Implement pipeline scheduling via cron syntax (#139)
Browse files Browse the repository at this point in the history
* First UI layout for new option

* Added validity check for new cron entries

* Added new robfig/cron dependency

* Implemented periodic scheduling

* Added a few tests

* Fixed test

* Added test for ticker
  • Loading branch information
michelvocks committed Dec 28, 2018
1 parent 9bcc31d commit a74748f
Show file tree
Hide file tree
Showing 18 changed files with 1,451 additions and 150 deletions.
142 changes: 22 additions & 120 deletions Gopkg.lock

Large diffs are not rendered by default.

107 changes: 98 additions & 9 deletions frontend/client/views/pipeline/create.vue
Expand Up @@ -30,7 +30,7 @@
<span class="icon">
<i class="fa fa-certificate"></i>
</span>
<span>Add credentials</span>
<span>Add Credentials</span>
</a>
<a class="button is-primary" v-on:click="showGitHubWebHookModal">
<span class="icon">
Expand All @@ -39,7 +39,26 @@
<span>Add GitHub WebHook</span>
</a>
</p>
<hr class="dotted-line">
</div>
</article>

<article class="tile is-child notification content-article">
<div class="content">
<p class="control">
<label class="label">Define custom pipeline options here.</label>
<a class="button is-primary" v-on:click="showPeriodicalPipelineScheduleModal">
<span class="icon">
<i class="fa fa-calendar"></i>
</span>
<span>Add Pipeline Trigger</span>
</a>
</p>
<span style="color: red" v-if="periodicSchedulesErr">Periodic schedules invalid: {{ periodicSchedulesErrMsg }}</span>
</div>
</article>

<article class="tile is-child notification content-article">
<div class="content">
<label class="label">Type the name of your pipeline here.</label>
<p class="control has-icons-left" v-bind:class="{ 'has-icons-right': pipelineNameSuccess }">
<input class="input is-medium input-bar" v-model="pipelinename" v-on:input="checkPipelineNameAvailableDebounce" type="text" placeholder="Pipeline name ...">
Expand All @@ -51,13 +70,6 @@
</span>
</p>
<span style="color: red" v-if="pipelineErrorMsg">Pipeline Name incorrect: {{ pipelineErrorMsg }}</span>
<hr class="dotted-line">
<a class="button is-green-button" v-on:click="startCreatePipeline" v-bind:class="{ 'is-disabled': !gitSuccess || !pipelineNameSuccess }">
<span class="icon">
<i class="fa fa-plus"></i>
</span>
<span>Create Pipeline</span>
</a>
</div>
</article>
</div>
Expand Down Expand Up @@ -88,6 +100,17 @@
</div>
</div>

<div class="tile is-parent">
<article class="is-child notification content-article">
<a class="button is-green-button" style="margin-left: 13px;" v-on:click="startCreatePipeline" v-bind:class="{ 'is-disabled': !gitSuccess || !pipelineNameSuccess || periodicSchedulesErr }">
<span class="icon">
<i class="fa fa-plus"></i>
</span>
<span>Create Pipeline</span>
</a>
</article>
</div>

<div class="tile is-parent is-10">
<article class="tile is-child notification content-article box">
<vue-good-table
Expand Down Expand Up @@ -214,6 +237,36 @@
</div>
</modal>

<!-- periodical pipeline schedule modal -->
<modal :visible="periodicalPipelineScheduleModal" class="modal-z-index" @close="close">
<div class="box credentials-modal">
<div class="block credentials-modal-content">
<collapse accordion is-fullwidth>
<collapse-item title="Start pipeline periodically:" selected>
<div class="credentials-modal-content">
<p class="control">
<textarea class="textarea input-bar" v-model="periodicSchedules"></textarea>
</p>
</div>
<label class="label" style="test-align: left;">
Use the standard cron syntax. For example to start the pipeline every half hour:
<br />0 30 * * * *<br />
Please see <a href="https://godoc.org/github.com/robfig/cron" target="_blank">here</a> for more information.
</label>
</collapse-item>
</collapse>
<div class="modal-footer">
<div style="float: left;">
<button class="button is-primary" v-on:click="addPeriodicalSchedules">Confirm</button>
</div>
<div style="float: right;">
<button class="button is-danger" v-on:click="cancel">Cancel</button>
</div>
</div>
</div>
</div>
</modal>

<!-- status output modal -->
<modal :visible="statusOutputModal" class="modal-z-index" @close="closeStatusModal">
<div class="box statusModal">
Expand Down Expand Up @@ -268,11 +321,15 @@ export default {
gitSuccess: false,
gitCredentialsModal: false,
gitWebHookModal: false,
periodicalPipelineScheduleModal: false,
gitBranches: [],
giturl: '',
pipelinename: '',
pipelineNameSuccess: false,
pipelineErrorMsg: '',
periodicSchedules: '',
periodicSchedulesErrMsg: '',
periodicSchedulesErr: false,
createPipeline: {
id: '',
output: '',
Expand All @@ -282,6 +339,7 @@ export default {
pipeline: {
name: '',
type: 'golang',
perodicschedules: [],
repo: {
url: '',
user: '',
Expand Down Expand Up @@ -491,6 +549,7 @@ export default {
this.checkGitRepo()
this.gitCredentialsModal = false
this.gitWebHookModal = false
this.periodicalPipelineScheduleModal = false
this.$emit('close')
},
Expand All @@ -501,6 +560,7 @@ export default {
this.createPipeline.pipeline.repo.privatekey.key = ''
this.createPipeline.pipeline.repo.privatekey.username = ''
this.createPipeline.pipeline.repo.privatekey.password = ''
this.periodicSchedules = ''
this.close()
},
Expand All @@ -513,6 +573,35 @@ export default {
this.gitWebHookModal = true
},
showPeriodicalPipelineScheduleModal () {
this.periodicalPipelineScheduleModal = true
},
addPeriodicalSchedules () {
// Reset previous errors if there were some.
this.periodicSchedulesErr = false
// Split string by line breaks.
this.createPipeline.pipeline.periodicschedules = this.periodicSchedules.split('\n')
// Check if periodic schedule entries are valid.
this.$http
.post('/api/v1/pipeline/periodicschedules', this.createPipeline.pipeline.periodicschedules)
.then(response => {
openNotification({
title: 'Periodic schedules valid',
message: `All defined periodic schedules are valid!`,
type: 'success'
})
})
.catch((error) => {
this.periodicSchedulesErr = true
this.periodicSchedulesErrMsg = error.response.data
})
this.close()
},
showStatusOutputModal (msg) {
if (!msg) {
msg = 'No output found.'
Expand Down
28 changes: 25 additions & 3 deletions frontend/client/views/settings/index.vue
Expand Up @@ -217,10 +217,22 @@
</p>
</div>
</collapse-item>
<collapse-item title="Change Periodic Schedule">
<div class="pipeline-modal-content">
<p class="control">
<textarea class="textarea input-bar" v-model="pipelinePeriodicSchedules"></textarea>
</p>
<label class="label" style="test-align: left;">
Use the standard cron syntax. For example to start the pipeline every half hour:
<br />0 30 * * * *<br />
Please see <a href="https://godoc.org/github.com/robfig/cron" target="_blank">here</a> for more information.
</label>
</div>
</collapse-item>
</collapse>
<div class="modal-footer">
<div style="float: left;">
<button class="button is-primary" v-on:click="changePipelineName">Change Name</button>
<button class="button is-primary" v-on:click="changePipeline">Accept changes</button>
</div>
<div style="float: right;">
<button class="button is-danger" v-on:click="close">Cancel</button>
Expand Down Expand Up @@ -333,7 +345,8 @@ export default {
showDeleteUserModal: false,
showAddUserModal: false,
showEditPipelineModal: false,
showDeletePipelineModal: false
showDeletePipelineModal: false,
pipelinePeriodicSchedules: ''
}
},
Expand Down Expand Up @@ -394,6 +407,11 @@ export default {
},
editPipelineModal (pipeline) {
// Check if periodic schedules is given.
if (pipeline.periodicschedules) {
this.pipelinePeriodicSchedules = pipeline.periodicschedules.join('\n')
}
this.selectPipeline = pipeline
this.showEditPipelineModal = true
},
Expand All @@ -411,6 +429,7 @@ export default {
this.showEditPipelineModal = false
this.showDeletePipelineModal = false
this.selectPipeline = {}
this.pipelinePeriodicSchedules = ''
this.$emit('close')
},
Expand Down Expand Up @@ -518,7 +537,10 @@ export default {
this.$router.push('/pipeline/create')
},
changePipelineName () {
changePipeline () {
// Convert periodic schedules into list.
this.selectPipeline.periodicschedules = this.pipelinePeriodicSchedules.split('\n')
this.$http
.put('/api/v1/pipeline/' + this.selectPipeline.id, this.selectPipeline)
.then(response => {
Expand Down
25 changes: 14 additions & 11 deletions gaia.go
Expand Up @@ -5,6 +5,7 @@ import (
"time"

hclog "github.com/hashicorp/go-hclog"
"github.com/robfig/cron"
)

// PipelineType represents supported plugin types
Expand Down Expand Up @@ -110,16 +111,18 @@ type User struct {

// Pipeline represents a single pipeline
type Pipeline struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Repo GitRepo `json:"repo,omitempty"`
Type PipelineType `json:"type,omitempty"`
ExecPath string `json:"execpath,omitempty"`
SHA256Sum []byte `json:"sha256sum,omitempty"`
Jobs []Job `json:"jobs,omitempty"`
Created time.Time `json:"created,omitempty"`
UUID string `json:"uuid,omitempty"`
IsNotValid bool `json:"notvalid,omitempty"`
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Repo GitRepo `json:"repo,omitempty"`
Type PipelineType `json:"type,omitempty"`
ExecPath string `json:"execpath,omitempty"`
SHA256Sum []byte `json:"sha256sum,omitempty"`
Jobs []Job `json:"jobs,omitempty"`
Created time.Time `json:"created,omitempty"`
UUID string `json:"uuid,omitempty"`
IsNotValid bool `json:"notvalid,omitempty"`
PeriodicSchedules []string `json:"periodicschedules,omitempty"`
CronInst *cron.Cron `json:"-"`
}

// GitRepo represents a single git repository
Expand All @@ -130,7 +133,7 @@ type GitRepo struct {
PrivateKey PrivateKey `json:"privatekey,omitempty"`
SelectedBranch string `json:"selectedbranch,omitempty"`
Branches []string `json:"branches,omitempty"`
LocalDest string
LocalDest string `json:"-"`
}

// Job represents a single job of a pipeline
Expand Down
1 change: 1 addition & 0 deletions handlers/handler.go
Expand Up @@ -66,6 +66,7 @@ func InitHandlers(e *echo.Echo) error {
e.POST(p+"pipeline/:pipelineid/start", PipelineStart)
e.GET(p+"pipeline/latest", PipelineGetAllWithLatestRun)
e.POST(p+"pipeline/githook", GitWebHook)
e.POST(p+"pipeline/periodicschedules", PipelineCheckPeriodicSchedules)

// PipelineRun
e.POST(p+"pipelinerun/:pipelineid/:runid/stop", PipelineStop)
Expand Down

0 comments on commit a74748f

Please sign in to comment.