Add support for marking sub workflows
This commit is contained in:
+10
-9
@@ -21,15 +21,16 @@ endpoints:
|
||||
path: "/"
|
||||
parameters:
|
||||
get:
|
||||
- { name: workflowID, type: "[]string", title: "Filter by workflow ID" }
|
||||
- { name: query, type: "string", title: "Filter workflows" }
|
||||
- { name: deleted, type: "uint", title: "Exclude (0, default), include (1) or return only (2) deleted workflows" }
|
||||
- { name: disabled, type: "uint", title: "Exclude (0, default), include (1) or return only (2) disabled workflows" }
|
||||
- { name: labels, type: "map[string]string", title: "Labels", parser: "label.ParseStrings" }
|
||||
- { name: limit, type: "uint", title: "Limit" }
|
||||
- { name: incTotal, type: "bool", title: "Include total rows counter" }
|
||||
- { name: pageCursor, type: "string", title: "Page cursor" }
|
||||
- { name: sort, type: "string", title: "Sort items" }
|
||||
- { name: workflowID, type: "[]string", title: "Filter by workflow ID" }
|
||||
- { name: query, type: "string", title: "Filter workflows" }
|
||||
- { name: deleted, type: "uint", title: "Exclude (0, default), include (1) or return only (2) deleted workflows" }
|
||||
- { name: disabled, type: "uint", title: "Exclude (0, default), include (1) or return only (2) disabled workflows" }
|
||||
- { name: subWorkflow, type: "uint", title: "Exclude (0, default), include (1) or return only (2) sub workflows" }
|
||||
- { name: labels, type: "map[string]string", title: "Labels", parser: "label.ParseStrings" }
|
||||
- { name: limit, type: "uint", title: "Limit" }
|
||||
- { name: incTotal, type: "bool", title: "Include total rows counter" }
|
||||
- { name: pageCursor, type: "string", title: "Page cursor" }
|
||||
- { name: sort, type: "string", title: "Sort items" }
|
||||
- name: create
|
||||
method: POST
|
||||
title: Create workflow
|
||||
|
||||
@@ -57,6 +57,11 @@ type (
|
||||
// Exclude (0, default), include (1) or return only (2) disabled workflows
|
||||
Disabled uint
|
||||
|
||||
// SubWorkflow GET parameter
|
||||
//
|
||||
// Exclude (0, default), include (1) or return only (2) sub workflows
|
||||
SubWorkflow uint
|
||||
|
||||
// Labels GET parameter
|
||||
//
|
||||
// Labels
|
||||
@@ -281,15 +286,16 @@ func NewWorkflowList() *WorkflowList {
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r WorkflowList) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"workflowID": r.WorkflowID,
|
||||
"query": r.Query,
|
||||
"deleted": r.Deleted,
|
||||
"disabled": r.Disabled,
|
||||
"labels": r.Labels,
|
||||
"limit": r.Limit,
|
||||
"incTotal": r.IncTotal,
|
||||
"pageCursor": r.PageCursor,
|
||||
"sort": r.Sort,
|
||||
"workflowID": r.WorkflowID,
|
||||
"query": r.Query,
|
||||
"deleted": r.Deleted,
|
||||
"disabled": r.Disabled,
|
||||
"subWorkflow": r.SubWorkflow,
|
||||
"labels": r.Labels,
|
||||
"limit": r.Limit,
|
||||
"incTotal": r.IncTotal,
|
||||
"pageCursor": r.PageCursor,
|
||||
"sort": r.Sort,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +319,11 @@ func (r WorkflowList) GetDisabled() uint {
|
||||
return r.Disabled
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r WorkflowList) GetSubWorkflow() uint {
|
||||
return r.SubWorkflow
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r WorkflowList) GetLabels() map[string]string {
|
||||
return r.Labels
|
||||
@@ -374,6 +385,12 @@ func (r *WorkflowList) Fill(req *http.Request) (err error) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if val, ok := tmp["subWorkflow"]; ok && len(val) > 0 {
|
||||
r.SubWorkflow, err = payload.ParseUint(val[0]), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if val, ok := tmp["labels[]"]; ok {
|
||||
r.Labels, err = label.ParseStrings(val)
|
||||
if err != nil {
|
||||
|
||||
@@ -83,11 +83,12 @@ func (ctrl Workflow) List(ctx context.Context, r *request.WorkflowList) (interfa
|
||||
var (
|
||||
err error
|
||||
f = types.WorkflowFilter{
|
||||
WorkflowID: payload.ParseUint64s(r.WorkflowID),
|
||||
Query: r.Query,
|
||||
Labels: r.Labels,
|
||||
Deleted: filter.State(r.Deleted),
|
||||
Disabled: filter.State(r.Disabled),
|
||||
WorkflowID: payload.ParseUint64s(r.WorkflowID),
|
||||
Query: r.Query,
|
||||
Labels: r.Labels,
|
||||
Deleted: filter.State(r.Deleted),
|
||||
Disabled: filter.State(r.Disabled),
|
||||
SubWorkflow: filter.State(r.SubWorkflow),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -712,6 +712,13 @@ func validateWorkflowTriggers(wf *types.Workflow, tt ...*types.Trigger) (wis typ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if wf.Meta != nil && wf.Meta.SubWorkflow {
|
||||
wis = wis.Append(
|
||||
errors.InvalidData("workflow marked as sub-workflow cannot have triggers"),
|
||||
map[string]int{"trigger": i},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza-server/automation/types"
|
||||
sysEvent "github.com/cortezaproject/corteza-server/system/service/event"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateWorkflowTriggersEmpty(t *testing.T) {
|
||||
var (
|
||||
req = require.New(t)
|
||||
|
||||
issues = validateWorkflowTriggers(
|
||||
&types.Workflow{},
|
||||
)
|
||||
)
|
||||
|
||||
req.Empty(issues)
|
||||
}
|
||||
func TestValidateWorkflowTriggersRunAs(t *testing.T) {
|
||||
var (
|
||||
req = require.New(t)
|
||||
soi = sysEvent.SystemOnInterval()
|
||||
|
||||
issues = validateWorkflowTriggers(
|
||||
&types.Workflow{},
|
||||
&types.Trigger{
|
||||
Enabled: true,
|
||||
ResourceType: soi.ResourceType(),
|
||||
EventType: soi.EventType(),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
req.Len(issues, 1)
|
||||
req.Contains(issues[0].String(), "requires run-as to be set")
|
||||
}
|
||||
|
||||
func TestValidateWorkflowTriggersSubWorkflow(t *testing.T) {
|
||||
var (
|
||||
req = require.New(t)
|
||||
|
||||
issues = validateWorkflowTriggers(
|
||||
&types.Workflow{Meta: &types.WorkflowMeta{SubWorkflow: true}},
|
||||
&types.Trigger{Enabled: true},
|
||||
)
|
||||
)
|
||||
|
||||
req.Len(issues, 1)
|
||||
req.Contains(issues[0].String(), "marked as sub-workflow")
|
||||
}
|
||||
@@ -53,6 +53,9 @@ type (
|
||||
Deleted filter.State `json:"deleted"`
|
||||
Disabled filter.State `json:"disabled"`
|
||||
|
||||
// include sub-workflows
|
||||
SubWorkflow filter.State `json:"subWorkflow"`
|
||||
|
||||
LabeledIDs []uint64 `json:"-"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
@@ -71,6 +74,10 @@ type (
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Visual map[string]interface{} `json:"visual"`
|
||||
|
||||
// list as one of the sub-workflows, when set to true
|
||||
// there should be no enabled triggers on this workflow
|
||||
SubWorkflow bool `json:"subWorkflow,omitempty"`
|
||||
}
|
||||
|
||||
WorkflowIssue struct {
|
||||
|
||||
@@ -2,6 +2,7 @@ package rdbms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/dal"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -304,6 +305,27 @@ func DefaultFilters() (f *extendedFilters) {
|
||||
return ee, f, err
|
||||
}
|
||||
|
||||
f.AutomationWorkflow = func(s *Store, f automationType.WorkflowFilter) (ee []goqu.Expression, _ automationType.WorkflowFilter, err error) {
|
||||
if ee, f, err = AutomationWorkflowFilter(f); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if f.SubWorkflow != filter.StateInclusive {
|
||||
vattr := &dal.Attribute{Type: &dal.TypeBoolean{}}
|
||||
litexp, _ := s.Dialect.DeepIdentJSON(goqu.C("meta"), "subWorkflow")
|
||||
litexp, _ = s.Dialect.AttributeCast(vattr, litexp)
|
||||
|
||||
switch f.SubWorkflow {
|
||||
case filter.StateExcluded:
|
||||
ee = append(ee, goqu.Or(litexp.IsFalse(), litexp.IsNull()))
|
||||
case filter.StateExclusive:
|
||||
ee = append(ee, litexp.IsTrue())
|
||||
}
|
||||
}
|
||||
|
||||
return ee, f, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -89,12 +89,17 @@ func testAutomationWorkflows(t *testing.T, s store.AutomationWorkflows) {
|
||||
makeNew("two-one"),
|
||||
makeNew("two-two"),
|
||||
makeNew("two-deleted"),
|
||||
func() *types.Workflow {
|
||||
wf := makeNew("subwf")
|
||||
wf.Meta = &types.WorkflowMeta{SubWorkflow: true}
|
||||
return wf
|
||||
}(),
|
||||
}
|
||||
|
||||
count := len(prefill)
|
||||
|
||||
prefill[4].DeletedAt = &prefill[4].CreatedAt
|
||||
valid := count - 1
|
||||
valid := count - 2
|
||||
|
||||
req.NoError(s.TruncateAutomationWorkflows(ctx))
|
||||
req.NoError(s.CreateAutomationWorkflow(ctx, prefill...))
|
||||
@@ -102,12 +107,15 @@ func testAutomationWorkflows(t *testing.T, s store.AutomationWorkflows) {
|
||||
// search for all valid
|
||||
set, f, err := s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(set, valid) // we've deleted one
|
||||
req.Len(set, valid) // all but deleted or workflows
|
||||
|
||||
// search for ALL
|
||||
set, f, err = s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{Deleted: filter.StateInclusive})
|
||||
// search for ALL, including deleted and sub-workflows
|
||||
set, f, err = s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{
|
||||
Deleted: filter.StateInclusive,
|
||||
SubWorkflow: filter.StateInclusive,
|
||||
})
|
||||
req.NoError(err)
|
||||
req.Len(set, count) // we've deleted one
|
||||
req.Len(set, count)
|
||||
|
||||
// search for deleted only
|
||||
set, f, err = s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{Deleted: filter.StateExclusive})
|
||||
@@ -119,6 +127,11 @@ func testAutomationWorkflows(t *testing.T, s store.AutomationWorkflows) {
|
||||
req.NoError(err)
|
||||
req.Len(set, 2)
|
||||
|
||||
// find just sub-workflows (one)
|
||||
set, f, err = s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{SubWorkflow: filter.StateExclusive})
|
||||
req.NoError(err)
|
||||
req.Len(set, 1)
|
||||
|
||||
_ = f // dummy
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user