mirror of
https://github.com/semaphoreui/semaphore.git
synced 2025-01-20 15:29:28 +01:00
feat: add schedule functionality
This commit is contained in:
parent
b77ffbfab8
commit
6eeb6706d4
149
api/projects/schedules.go
Normal file
149
api/projects/schedules.go
Normal file
@ -0,0 +1,149 @@
|
||||
package projects
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/ansible-semaphore/semaphore/api/helpers"
|
||||
"github.com/ansible-semaphore/semaphore/db"
|
||||
"github.com/gorilla/context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// SchedulesMiddleware ensures a template exists and loads it to the context
|
||||
func SchedulesMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
project := context.Get(r, "project").(db.Project)
|
||||
scheduleID, err := helpers.GetIntParam("schedule_id", w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
schedule, err := helpers.Store(r).GetSchedule(project.ID, scheduleID)
|
||||
|
||||
if err != nil {
|
||||
helpers.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
context.Set(r, "schedule", schedule)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// GetSchedule returns single template by ID
|
||||
func GetSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
schedule := context.Get(r, "schedule").(db.Schedule)
|
||||
helpers.WriteJSON(w, http.StatusOK, schedule)
|
||||
}
|
||||
|
||||
// AddSchedule adds a template to the database
|
||||
func AddSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
project := context.Get(r, "project").(db.Project)
|
||||
|
||||
var schedule db.Schedule
|
||||
if !helpers.Bind(w, r, &schedule) {
|
||||
return
|
||||
}
|
||||
|
||||
schedule.ProjectID = project.ID
|
||||
schedule, err := helpers.Store(r).CreateSchedule(schedule)
|
||||
|
||||
if err != nil {
|
||||
helpers.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
user := context.Get(r, "user").(*db.User)
|
||||
objType := "schedule"
|
||||
desc := "Schedule ID " + strconv.Itoa(schedule.ID) + " created"
|
||||
|
||||
_, err = helpers.Store(r).CreateEvent(db.Event{
|
||||
UserID: &user.ID,
|
||||
ProjectID: &project.ID,
|
||||
ObjectType: &objType,
|
||||
ObjectID: &schedule.ID,
|
||||
Description: &desc,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
helpers.WriteJSON(w, http.StatusCreated, schedule)
|
||||
}
|
||||
|
||||
// UpdateSchedule writes a schedule to an existing key in the database
|
||||
func UpdateSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
oldSchedule := context.Get(r, "schedule").(db.Schedule)
|
||||
|
||||
var schedule db.Schedule
|
||||
if !helpers.Bind(w, r, &schedule) {
|
||||
return
|
||||
}
|
||||
|
||||
// project ID and schedule ID in the body and the path must be the same
|
||||
|
||||
if schedule.ID != oldSchedule.ID {
|
||||
helpers.WriteJSON(w, http.StatusBadRequest, map[string]string{
|
||||
"error": "schedule id in URL and in body must be the same",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if schedule.ProjectID != oldSchedule.ProjectID {
|
||||
helpers.WriteJSON(w, http.StatusBadRequest, map[string]string{
|
||||
"error": "You can not move schedule to other project",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := helpers.Store(r).UpdateSchedule(schedule)
|
||||
if err != nil {
|
||||
helpers.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
user := context.Get(r, "user").(*db.User)
|
||||
|
||||
desc := "Schedule ID " + strconv.Itoa(schedule.ID) + " updated"
|
||||
objType := "schedule"
|
||||
|
||||
_, err = helpers.Store(r).CreateEvent(db.Event{
|
||||
UserID: &user.ID,
|
||||
ProjectID: &schedule.ProjectID,
|
||||
Description: &desc,
|
||||
ObjectID: &schedule.ID,
|
||||
ObjectType: &objType,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// RemoveSchedule deletes a schedule from the database
|
||||
func RemoveSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
schedule := context.Get(r, "schedule").(db.Schedule)
|
||||
|
||||
err := helpers.Store(r).DeleteSchedule(schedule.ProjectID, schedule.ID)
|
||||
if err != nil {
|
||||
helpers.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
user := context.Get(r, "user").(*db.User)
|
||||
desc := "Schedule ID " + strconv.Itoa(schedule.ID) + " deleted"
|
||||
_, err = helpers.Store(r).CreateEvent(db.Event{
|
||||
UserID: &user.ID,
|
||||
ProjectID: &schedule.ProjectID,
|
||||
Description: &desc,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
@ -4,10 +4,9 @@ import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/ansible-semaphore/semaphore/api/helpers"
|
||||
"github.com/ansible-semaphore/semaphore/db"
|
||||
"github.com/gorilla/context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/context"
|
||||
)
|
||||
|
||||
// TemplatesMiddleware ensures a template exists and loads it to the context
|
||||
@ -42,7 +41,7 @@ func GetTemplates(w http.ResponseWriter, r *http.Request) {
|
||||
project := context.Get(r, "project").(db.Project)
|
||||
|
||||
params := db.RetrieveQueryParams{
|
||||
SortBy: r.URL.Query().Get("sort"),
|
||||
SortBy: r.URL.Query().Get("sort"),
|
||||
SortInverted: r.URL.Query().Get("order") == desc,
|
||||
}
|
||||
|
||||
@ -102,9 +101,17 @@ func UpdateTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// project ID and template ID in the body and the path must be the same
|
||||
if template.ID != oldTemplate.ID || template.ProjectID != oldTemplate.ProjectID {
|
||||
|
||||
if template.ID != oldTemplate.ID {
|
||||
helpers.WriteJSON(w, http.StatusBadRequest, map[string]string{
|
||||
"error": "You can not move ",
|
||||
"error": "template id in URL and in body must be the same",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if template.ProjectID != oldTemplate.ProjectID {
|
||||
helpers.WriteJSON(w, http.StatusBadRequest, map[string]string{
|
||||
"error": "You can not move template to other project",
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -125,7 +132,7 @@ func UpdateTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
objType := "template"
|
||||
|
||||
_, err = helpers.Store(r).CreateEvent(db.Event{
|
||||
UserID: &user.ID,
|
||||
UserID: &user.ID,
|
||||
ProjectID: &template.ProjectID,
|
||||
Description: &desc,
|
||||
ObjectID: &template.ID,
|
||||
@ -162,4 +169,4 @@ func RemoveTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
@ -189,6 +189,7 @@ func Route() *mux.Router {
|
||||
projectTmplManagement.HandleFunc("/{template_id}", projects.GetTemplate).Methods("GET")
|
||||
projectTmplManagement.HandleFunc("/{template_id}/tasks", tasks.GetAllTasks).Methods("GET")
|
||||
projectTmplManagement.HandleFunc("/{template_id}/tasks/last", tasks.GetLastTasks).Methods("GET")
|
||||
projectTmplManagement.HandleFunc("/{template_id}/schedules", projects.GetSchedule).Methods("GET")
|
||||
|
||||
projectTaskManagement := projectUserAPI.PathPrefix("/tasks").Subrouter()
|
||||
projectTaskManagement.Use(tasks.GetTaskMiddleware)
|
||||
@ -198,6 +199,13 @@ func Route() *mux.Router {
|
||||
projectTaskManagement.HandleFunc("/{task_id}", tasks.RemoveTask).Methods("DELETE")
|
||||
projectTaskManagement.HandleFunc("/{task_id}/stop", tasks.StopTask).Methods("POST")
|
||||
|
||||
|
||||
projectScheduleManagement := projectUserAPI.PathPrefix("/schedules").Subrouter()
|
||||
projectScheduleManagement.Use(projects.SchedulesMiddleware)
|
||||
projectScheduleManagement.HandleFunc("/{schedule_id}", projects.GetSchedule).Methods("GET", "HEAD")
|
||||
projectScheduleManagement.HandleFunc("/{schedule_id}", projects.UpdateSchedule).Methods("PUT")
|
||||
projectScheduleManagement.HandleFunc("/{schedule_id}", projects.RemoveSchedule).Methods("DELETE")
|
||||
|
||||
if os.Getenv("DEBUG") == "1" {
|
||||
defer debugPrintRoutes(r)
|
||||
}
|
||||
|
63
api/schedules/pool.go
Normal file
63
api/schedules/pool.go
Normal file
@ -0,0 +1,63 @@
|
||||
package schedules
|
||||
|
||||
import (
|
||||
"github.com/ansible-semaphore/semaphore/db"
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
type templateRunner struct {
|
||||
schedule db.Schedule
|
||||
}
|
||||
|
||||
func (r templateRunner) Run() {
|
||||
// TODO: add task to tasks pool
|
||||
}
|
||||
|
||||
type schedulePool struct {
|
||||
cron *cron.Cron
|
||||
jobs []cron.EntryID
|
||||
}
|
||||
|
||||
func (p *schedulePool) init() {
|
||||
p.cron = cron.New()
|
||||
}
|
||||
|
||||
func (p *schedulePool) loadData(d db.Store) {
|
||||
schedules, err := d.GetSchedules()
|
||||
|
||||
if err != nil {
|
||||
// TODO: log error
|
||||
return
|
||||
}
|
||||
|
||||
for _, schedule := range schedules {
|
||||
err := p.addSchedule(schedule)
|
||||
if err != nil {
|
||||
// TODO: log error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *schedulePool) addSchedule(schedule db.Schedule) error {
|
||||
id, err := p.cron.AddJob(schedule.CronFormat, templateRunner{
|
||||
schedule: schedule,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.jobs = append(p.jobs, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *schedulePool) run() {
|
||||
p.cron.Run()
|
||||
}
|
||||
|
||||
var pool = schedulePool{}
|
||||
|
||||
// StartRunner begins the schedule pool, used as a goroutine
|
||||
func StartRunner(d db.Store) {
|
||||
pool.init()
|
||||
pool.loadData(d)
|
||||
pool.run()
|
||||
}
|
@ -4,7 +4,11 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/ansible-semaphore/semaphore/api/helpers"
|
||||
"github.com/ansible-semaphore/semaphore/api/sockets"
|
||||
"github.com/ansible-semaphore/semaphore/db"
|
||||
"github.com/ansible-semaphore/semaphore/util"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -12,13 +16,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ansible-semaphore/semaphore/api/helpers"
|
||||
"github.com/ansible-semaphore/semaphore/db"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/ansible-semaphore/semaphore/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -32,19 +29,19 @@ const (
|
||||
)
|
||||
|
||||
type task struct {
|
||||
store db.Store
|
||||
task db.Task
|
||||
template db.Template
|
||||
inventory db.Inventory
|
||||
repository db.Repository
|
||||
environment db.Environment
|
||||
users []int
|
||||
projectID int
|
||||
hosts []string
|
||||
alertChat string
|
||||
alert bool
|
||||
prepared bool
|
||||
process *os.Process
|
||||
store db.Store
|
||||
task db.Task
|
||||
template db.Template
|
||||
inventory db.Inventory
|
||||
repository db.Repository
|
||||
environment db.Environment
|
||||
users []int
|
||||
projectID int
|
||||
hosts []string
|
||||
alertChat string
|
||||
alert bool
|
||||
prepared bool
|
||||
process *os.Process
|
||||
}
|
||||
|
||||
func (t *task) getRepoName() string {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/ansible-semaphore/semaphore/api"
|
||||
"github.com/ansible-semaphore/semaphore/api/schedules"
|
||||
"github.com/ansible-semaphore/semaphore/api/sockets"
|
||||
"github.com/ansible-semaphore/semaphore/api/tasks"
|
||||
"github.com/ansible-semaphore/semaphore/db"
|
||||
@ -74,6 +75,7 @@ func runService() {
|
||||
|
||||
go sockets.StartWS()
|
||||
go tasks.StartRunner()
|
||||
go schedules.StartRunner(store)
|
||||
|
||||
route := api.Route()
|
||||
|
||||
|
8
db/Schedule.go
Normal file
8
db/Schedule.go
Normal file
@ -0,0 +1,8 @@
|
||||
package db
|
||||
|
||||
type Schedule struct {
|
||||
ID int `db:"id" json:"id"`
|
||||
ProjectID int `db:"project_id" json:"project_id"`
|
||||
TemplateID int `db:"template_id" json:"template_id"`
|
||||
CronFormat string `db:"cron_format" json:"cron_format"`
|
||||
}
|
15
db/Store.go
15
db/Store.go
@ -43,6 +43,8 @@ func ValidateUsername(login string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Transaction interface {}
|
||||
|
||||
type Store interface {
|
||||
Connect() error
|
||||
Close() error
|
||||
@ -107,6 +109,13 @@ type Store interface {
|
||||
GetTemplate(projectID int, templateID int) (Template, error)
|
||||
DeleteTemplate(projectID int, templateID int) error
|
||||
|
||||
GetSchedules() ([]Schedule, error)
|
||||
GetTemplateSchedules(projectID int, templateID int) ([]Schedule, error)
|
||||
CreateSchedule(schedule Schedule) (Schedule, error)
|
||||
UpdateSchedule(schedule Schedule) error
|
||||
GetSchedule(projectID int, scheduleID int) (Schedule, error)
|
||||
DeleteSchedule(projectID int, scheduleID int) error
|
||||
|
||||
GetProjectUsers(projectID int, params RetrieveQueryParams) ([]User, error)
|
||||
CreateProjectUser(projectUser ProjectUser) (ProjectUser, error)
|
||||
DeleteProjectUser(projectID int, userID int) error
|
||||
@ -274,6 +283,11 @@ var TemplateProps = ObjectProperties{
|
||||
PrimaryColumnName: "id",
|
||||
}
|
||||
|
||||
var ScheduleProps = ObjectProperties{
|
||||
TableName: "project__schedule",
|
||||
PrimaryColumnName: "id",
|
||||
}
|
||||
|
||||
var ProjectUserProps = ObjectProperties{
|
||||
TableName: "project__user",
|
||||
PrimaryColumnName: "user_id",
|
||||
@ -310,5 +324,4 @@ var TaskProps = ObjectProperties{
|
||||
|
||||
var TaskOutputProps = ObjectProperties{
|
||||
TableName: "task__output",
|
||||
PrimaryColumnName: "",
|
||||
}
|
||||
|
@ -24,4 +24,4 @@ type Template struct {
|
||||
|
||||
VaultPassID *int `db:"vault_pass_id" json:"vault_pass_id"`
|
||||
VaultPass AccessKey `db:"-" json:"-"`
|
||||
}
|
||||
}
|
48
db/bolt/schedule.go
Normal file
48
db/bolt/schedule.go
Normal file
@ -0,0 +1,48 @@
|
||||
package bolt
|
||||
|
||||
import "github.com/ansible-semaphore/semaphore/db"
|
||||
|
||||
func (d *BoltDb) GetSchedules() (schedules []db.Schedule, err error) {
|
||||
var allProjects []db.Project
|
||||
|
||||
err = d.getObjects(0, db.ProjectProps, db.RetrieveQueryParams{}, nil, &allProjects)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, proj := range allProjects {
|
||||
var projSchedules []db.Schedule
|
||||
projSchedules, err = d.GetProjectSchedules(proj.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
schedules = append(schedules, projSchedules...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *BoltDb) GetProjectSchedules(projectID int) (schedules []db.Schedule, err error) {
|
||||
err = d.getObjects(projectID, db.ScheduleProps, db.RetrieveQueryParams{}, nil, &schedules)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func (d *BoltDb) GetTemplateSchedules(projectID int, templateID int) (schedule db.Schedule, err error) {
|
||||
projSchedules, err := d.GetProjectSchedules(projectID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, s := range projSchedules {
|
||||
if s.TemplateID == templateID {
|
||||
schedule = s
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = db.ErrNotFound
|
||||
return
|
||||
}
|
||||
|
@ -81,5 +81,6 @@ func init() {
|
||||
{Major: 2, Minor: 7, Patch: 9},
|
||||
{Major: 2, Minor: 7, Patch: 10},
|
||||
{Major: 2, Minor: 7, Patch: 12},
|
||||
{Major: 2, Minor: 7, Patch: 13},
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,8 @@ func (d *SqlDb) applyMigration(version *Version) error {
|
||||
}
|
||||
|
||||
q := d.prepareMigration(query)
|
||||
if _, err := tx.Exec(q); err != nil {
|
||||
_, err = tx.Exec(q)
|
||||
if err != nil {
|
||||
handleRollbackError(tx.Rollback())
|
||||
log.Warnf("\n ERR! Query: %v\n\n", q)
|
||||
return err
|
||||
|
3
db/sql/migrations/v2.7.13.sql
Normal file
3
db/sql/migrations/v2.7.13.sql
Normal file
@ -0,0 +1,3 @@
|
||||
alter table project__template_schedule rename to project__schedule;
|
||||
alter table `project__schedule` add `id` integer primary key autoincrement;
|
||||
alter table `project__schedule` add `project_id` int not null references project(`id`);
|
67
db/sql/schedule.go
Normal file
67
db/sql/schedule.go
Normal file
@ -0,0 +1,67 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/ansible-semaphore/semaphore/db"
|
||||
)
|
||||
|
||||
func (d *SqlDb) CreateSchedule(schedule db.Schedule) (newSchedule db.Schedule, err error) {
|
||||
insertID, err := d.insert(
|
||||
"id",
|
||||
"insert into project__schedule (project_id, template_id, cron_format)" +
|
||||
"values (?, ?, ?)",
|
||||
schedule.ProjectID,
|
||||
schedule.TemplateID,
|
||||
schedule.CronFormat)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newSchedule = schedule
|
||||
newSchedule.ID = insertID
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *SqlDb) UpdateSchedule(schedule db.Schedule) error {
|
||||
_, err := d.exec("update project__schedule set cron_format=? where project_id=? and id=?",
|
||||
schedule.CronFormat,
|
||||
schedule.ProjectID,
|
||||
schedule.ID)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *SqlDb) GetSchedule(projectID int, scheduleID int) (template db.Schedule, err error) {
|
||||
err = d.selectOne(
|
||||
&template,
|
||||
"select * from project__schedule where project_id=? and id=?",
|
||||
projectID,
|
||||
scheduleID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = db.ErrNotFound
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *SqlDb) DeleteSchedule(projectID int, scheduleID int) error {
|
||||
_, err := d.exec("delete project__schedule where project_id=? and id=?", projectID, scheduleID)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *SqlDb) GetSchedules() (schedules []db.Schedule, err error) {
|
||||
_, err = d.selectAll(&schedules, "select * from project__template_schedule where cron_format != ''")
|
||||
return
|
||||
}
|
||||
|
||||
func (d *SqlDb) GetTemplateSchedules(projectID int, templateID int) (schedules []db.Schedule, err error) {
|
||||
_, err = d.selectAll(&schedules,
|
||||
"select * from project__template_schedule where project_id=? and template_id=?",
|
||||
projectID,
|
||||
templateID)
|
||||
return
|
||||
}
|
@ -24,15 +24,21 @@ func (d *SqlDb) CreateTemplate(template db.Template) (newTemplate db.Template, e
|
||||
return
|
||||
}
|
||||
|
||||
err = db.FillTemplate(d, &newTemplate)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newTemplate = template
|
||||
newTemplate.ID = insertID
|
||||
err = db.FillTemplate(d, &newTemplate)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *SqlDb) UpdateTemplate(template db.Template) error {
|
||||
_, err := d.exec("update project__template set inventory_id=?, repository_id=?, environment_id=?, alias=?, " +
|
||||
"playbook=?, arguments=?, override_args=? where removed = false and id=?",
|
||||
"playbook=?, arguments=?, override_args=? where removed = false and id=? and project_id=?",
|
||||
template.InventoryID,
|
||||
template.RepositoryID,
|
||||
template.EnvironmentID,
|
||||
@ -40,8 +46,33 @@ func (d *SqlDb) UpdateTemplate(template db.Template) error {
|
||||
template.Playbook,
|
||||
template.Arguments,
|
||||
template.OverrideArguments,
|
||||
template.ID)
|
||||
|
||||
template.ID,
|
||||
template.ProjectID)
|
||||
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
//if template.CronFormat == "" {
|
||||
// _, err = d.exec(
|
||||
// "delete from project__template_schedule where project_id =? and template_id=?",
|
||||
// template.ProjectID,
|
||||
// template.ID)
|
||||
//} else {
|
||||
// _, err = d.GetTemplateSchedules(template.ProjectID, template.ID)
|
||||
// if err == nil {
|
||||
// _, err = d.exec(
|
||||
// "update project__template_schedule set cron_format=? where project_id =? and template_id=?",
|
||||
// template.CronFormat,
|
||||
// template.ProjectID,
|
||||
// template.ID)
|
||||
// } else if err == db.ErrNotFound {
|
||||
// _, err = d.exec(
|
||||
// "insert into project__template_schedule (template_id, cron_format) values (?, ?)",
|
||||
// template.ID,
|
||||
// template.CronFormat)
|
||||
// }
|
||||
//}
|
||||
return err
|
||||
}
|
||||
|
||||
@ -117,11 +148,4 @@ func (d *SqlDb) DeleteTemplate(projectID int, templateID int) error {
|
||||
_, err := d.exec("update project__template set removed=true where project_id=? and id=?", projectID, templateID)
|
||||
|
||||
return err
|
||||
|
||||
//res, err := d.exec(
|
||||
// "delete from project__template where project_id=? and id=?",
|
||||
// projectID,
|
||||
// templateID)
|
||||
|
||||
//return validateMutationResult(res, err)
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@ -40,6 +40,7 @@ require (
|
||||
github.com/onsi/ginkgo v1.12.0 // indirect
|
||||
github.com/onsi/gomega v1.9.0 // indirect
|
||||
github.com/radovskyb/watcher v1.0.7 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/russross/blackfriday v1.5.2 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2 // indirect
|
||||
github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa
|
||||
|
2
go.sum
2
go.sum
@ -379,6 +379,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
|
@ -762,11 +762,11 @@ export default {
|
||||
if (!this.isAuthenticated) {
|
||||
return;
|
||||
}
|
||||
this.user = (await axios({
|
||||
method: 'get',
|
||||
url: '/api/user',
|
||||
responseType: 'json',
|
||||
})).data;
|
||||
this.user = (await axios({
|
||||
method: 'get',
|
||||
url: '/api/user',
|
||||
responseType: 'json',
|
||||
})).data;
|
||||
},
|
||||
|
||||
getProjectColor(projectData) {
|
||||
|
@ -79,6 +79,10 @@ export default {
|
||||
throw new Error('Not implemented'); // must me implemented in template
|
||||
},
|
||||
|
||||
afterSave() {
|
||||
|
||||
},
|
||||
|
||||
getNewItem() {
|
||||
return {};
|
||||
},
|
||||
@ -142,6 +146,8 @@ export default {
|
||||
...(this.getRequestOptions()),
|
||||
})).data;
|
||||
|
||||
await this.afterSave();
|
||||
|
||||
this.$emit('save', {
|
||||
item: item || this.item,
|
||||
action: this.isNew ? 'new' : 'edit',
|
||||
|
@ -67,6 +67,13 @@
|
||||
:disabled="formSaving"
|
||||
></v-select>
|
||||
|
||||
<v-text-field
|
||||
v-model="cronFormat"
|
||||
label="Cron"
|
||||
:disabled="formSaving"
|
||||
placeholder="Example: * 1 * * * *"
|
||||
v-if="schedules == null || schedules.length === 1"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6" class="pb-0">
|
||||
@ -134,6 +141,8 @@ export default {
|
||||
inventory: null,
|
||||
repositories: null,
|
||||
environment: null,
|
||||
schedules: null,
|
||||
cronFormat: null,
|
||||
};
|
||||
},
|
||||
|
||||
@ -177,6 +186,14 @@ export default {
|
||||
url: `/api/project/${this.projectId}/environment`,
|
||||
responseType: 'json',
|
||||
})).data;
|
||||
this.schedules = (await axios({
|
||||
keys: 'get',
|
||||
url: `/api/project/${this.projectId}/templates/${this.sourceItemId}/schedules`,
|
||||
responseType: 'json',
|
||||
})).data;
|
||||
if (this.schedules.length === 1) {
|
||||
this.cronFormat = this.schedules[0].cron_format;
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
@ -189,7 +206,8 @@ export default {
|
||||
&& this.repositories != null
|
||||
&& this.inventory != null
|
||||
&& this.environment != null
|
||||
&& this.item != null;
|
||||
&& this.item != null
|
||||
&& this.schedules != null;
|
||||
},
|
||||
|
||||
loginPasswordKeys() {
|
||||
@ -208,6 +226,45 @@ export default {
|
||||
getSingleItemUrl() {
|
||||
return `/api/project/${this.projectId}/templates/${this.itemId}`;
|
||||
},
|
||||
|
||||
async afterSave(newItem) {
|
||||
if (newItem || this.schedules.length === 0) {
|
||||
if (this.cronFormat !== '') {
|
||||
// new schedule
|
||||
await axios({
|
||||
method: 'post',
|
||||
url: `/api/project/${this.projectId}/schedules`,
|
||||
responseType: 'json',
|
||||
data: {
|
||||
project_id: this.projectId,
|
||||
template_id: newItem ? newItem.id : this.itemId,
|
||||
cron_format: this.cronFormat,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if (this.schedules.length > 1) {
|
||||
// do nothing
|
||||
} else if (this.schedules === '') {
|
||||
// drop schedule
|
||||
await axios({
|
||||
method: 'delete',
|
||||
url: `/api/project/${this.projectId}/schedules/${this.schedules[0].id}`,
|
||||
responseType: 'json',
|
||||
});
|
||||
} else {
|
||||
// update schedule
|
||||
await axios({
|
||||
method: 'put',
|
||||
url: `/api/project/${this.projectId}/schedules/${this.schedules[0].id}`,
|
||||
responseType: 'json',
|
||||
data: {
|
||||
project_id: this.projectId,
|
||||
template_id: this.itemId,
|
||||
cron_format: this.cronFormat,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user