Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const (
propRetryPolicy = "retryPolicy"
propTaskQueue = "taskQueue"
propType = "type"
propScheduleWorkflowName = "scheduleWorkflowName"
propScheduleWorkflowType = "scheduleWorkflowType"
propScheduleID = "scheduleId"
propScheduleInput = "scheduleInput"
propSeconds = "seconds"
Expand Down
11 changes: 6 additions & 5 deletions definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,11 +413,12 @@ var documentMetadataDefinition = &jsonschema.Schema{
Title: "ContinueAsNewMaxHistoryLength",
Description: "Allows you to test the Continue-As-New functionality by specifying the max history length before triggering.",
},
propScheduleWorkflowName: {
Type: typeString,
Title: "ScheduleWorkflowName",
Description: "Set the workflow name to trigger - this will either be the document.workflowType or the Do task",
MinLength: utils.Ptr(1),
propScheduleWorkflowType: {
Type: typeString,
Title: "ScheduleWorkflowType",
Description: "The workflow type the schedule starts: the document.workflowType or a top-level Do task. " +
"Defaults to document.workflowType; required when every top-level task is a Do task.",
MinLength: utils.Ptr(1),
},
propScheduleID: {
Type: typeString,
Expand Down
18 changes: 12 additions & 6 deletions metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func TestDocumentMetadataDefinitionShape(t *testing.T) {

for _, key := range []string{
propCanMaxHistory,
propScheduleWorkflowName,
propScheduleWorkflowType,
propScheduleID,
propScheduleInput,
} {
Expand All @@ -167,7 +167,8 @@ func TestDocumentMetadataDefinitionShape(t *testing.T) {
}

assert.Equal(t, typeInteger, def.Properties[propCanMaxHistory].Type)
assert.Equal(t, typeString, def.Properties[propScheduleWorkflowName].Type)
assert.Equal(t, typeString, def.Properties[propScheduleWorkflowType].Type)
assert.False(t, def.Properties[propScheduleWorkflowType].Deprecated)
assert.Equal(t, typeString, def.Properties[propScheduleID].Type)
assert.Equal(t, typeArray, def.Properties[propScheduleInput].Type)
}
Expand Down Expand Up @@ -224,8 +225,8 @@ func TestDocumentMetadata_Validation(t *testing.T) {
}{
// ---- valid cases ----
{
name: "scheduleWorkflowName string is accepted",
meta: map[string]any{"scheduleWorkflowName": "my-workflow"},
name: "scheduleWorkflowType string is accepted",
meta: map[string]any{propScheduleWorkflowType: testWorkflowType},
},
{
name: "scheduleId string is accepted",
Expand Down Expand Up @@ -262,8 +263,13 @@ func TestDocumentMetadata_Validation(t *testing.T) {

// ---- invalid cases ----
{
name: "scheduleWorkflowName as integer is rejected",
meta: map[string]any{"scheduleWorkflowName": 42},
name: "scheduleWorkflowType as integer is rejected",
meta: map[string]any{propScheduleWorkflowType: 42},
expectError: true,
},
{
name: "empty scheduleWorkflowType is rejected",
meta: map[string]any{propScheduleWorkflowType: ""},
expectError: true,
},
{
Expand Down
16 changes: 0 additions & 16 deletions schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,6 @@ func BuildSchema(version, format string) (*jsonschema.Schema, error) {
Required: []string{propDo, propDocument},
Properties: schemaProperties,
Defs: buildDefinitions(),
If: &jsonschema.Schema{
Required: []string{"schedule"},
},
Then: &jsonschema.Schema{
Required: []string{propDocument},
Properties: map[string]*jsonschema.Schema{
propDocument: {
Required: []string{propMetadata},
Properties: map[string]*jsonschema.Schema{
propMetadata: {
Required: []string{propScheduleWorkflowName},
},
},
},
},
},
}

// Validate the generated schema
Expand Down
32 changes: 4 additions & 28 deletions schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -517,10 +517,10 @@
"title": "ScheduleInput",
"description": "Set the input."
},
"scheduleWorkflowName": {
"scheduleWorkflowType": {
"type": "string",
"title": "ScheduleWorkflowName",
"description": "Set the workflow name to trigger - this will either be the document.workflowType or the Do task",
"title": "ScheduleWorkflowType",
"description": "The workflow type the schedule starts: the document.workflowType or a top-level Do task. Defaults to document.workflowType; required when every top-level task is a Do task.",
"minLength": 1
}
},
Expand Down Expand Up @@ -1834,29 +1834,5 @@
"required": [
"do",
"document"
],
"if": {
"required": [
"schedule"
]
},
"then": {
"properties": {
"document": {
"properties": {
"metadata": {
"required": [
"scheduleWorkflowName"
]
}
},
"required": [
"metadata"
]
}
},
"required": [
"document"
]
}
]
}
23 changes: 5 additions & 18 deletions schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,12 @@ $defs:
description: Set the input.
title: ScheduleInput
type: array
scheduleWorkflowName:
description: Set the workflow name to trigger - this will either be the document.workflowType
or the Do task
scheduleWorkflowType:
description: 'The workflow type the schedule starts: the document.workflowType
or a top-level Do task. Defaults to document.workflowType; required when
every top-level task is a Do task.'
minLength: 1
title: ScheduleWorkflowName
title: ScheduleWorkflowType
type: string
title: DocumentMetadata
type: object
Expand Down Expand Up @@ -1245,9 +1246,6 @@ $defs:
$id: https://zigflow.dev/schema.yaml
$schema: https://json-schema.org/draft/2020-12/schema
description: JSON Schema for a Zigflow workflow definition.
if:
required:
- schedule
properties:
do:
$ref: '#/$defs/taskList'
Expand Down Expand Up @@ -1339,16 +1337,5 @@ properties:
required:
- do
- document
then:
properties:
document:
properties:
metadata:
required:
- scheduleWorkflowName
required:
- metadata
required:
- document
title: Zigflow
type: object
58 changes: 24 additions & 34 deletions schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import (
"github.com/stretchr/testify/require"
)

const testCronExpr = "0 0 * * *"
const (
testCronExpr = "0 0 * * *"
testWorkflowType = "my-workflow"
)

// minimalWorkflow returns a minimal structurally valid workflow document.
// It is used as a baseline for validation tests so that each test only
Expand Down Expand Up @@ -97,41 +100,28 @@ func TestSchema_DocumentFields(t *testing.T) {
})
}

// TestSchema_ScheduleRequiresScheduleWorkflowName verifies the conditional
// if/then rule: when top-level schedule is present, document.metadata must
// exist and contain scheduleWorkflowName.
func TestSchema_ScheduleRequiresScheduleWorkflowName(t *testing.T) {
// TestSchema_ScheduleNeedsNoWorkflowKey verifies that a schedule validates
// without a workflow key: the runtime defaults it to document.workflowType, and
// only it can tell when that does not apply (every top-level task a Do task).
func TestSchema_ScheduleNeedsNoWorkflowKey(t *testing.T) {
resolved := resolvedTestSchema(t)

t.Run("schedule present without document.metadata is rejected", func(t *testing.T) {
doc := minimalWorkflow()
doc["schedule"] = map[string]any{propCron: testCronExpr}

err := resolved.Validate(doc)
assert.Error(t, err, "schedule without document.metadata must fail validation")
})

t.Run("schedule present with document.metadata but missing scheduleWorkflowName is rejected", func(t *testing.T) {
doc := minimalWorkflow()
doc["schedule"] = map[string]any{propCron: testCronExpr}
doc["document"].(map[string]any)["metadata"] = map[string]any{
propScheduleID: "my-schedule",
}

err := resolved.Validate(doc)
assert.Error(t, err, "schedule with document.metadata but no scheduleWorkflowName must fail validation")
})

t.Run("schedule present with valid document.metadata.scheduleWorkflowName is accepted", func(t *testing.T) {
doc := minimalWorkflow()
doc["schedule"] = map[string]any{propCron: testCronExpr}
doc["document"].(map[string]any)["metadata"] = map[string]any{
propScheduleWorkflowName: "my-workflow",
}

err := resolved.Validate(doc)
assert.NoError(t, err, "schedule with valid scheduleWorkflowName must pass validation")
})
for name, meta := range map[string]map[string]any{
"no document.metadata": nil,
"metadata without a key": {propScheduleID: "my-schedule"},
"the workflow type key": {propScheduleWorkflowType: testWorkflowType},
"the old key, now unlisted": {"scheduleWorkflowName": testWorkflowType},
} {
t.Run(name, func(t *testing.T) {
doc := minimalWorkflow()
doc["schedule"] = map[string]any{propCron: testCronExpr}
if meta != nil {
doc["document"].(map[string]any)["metadata"] = meta
}

assert.NoError(t, resolved.Validate(doc), "a schedule must validate with %s", name)
})
}
}

// TestSchema_RejectsUnknownTopLevelProperties verifies that the root schema
Expand Down
Loading