From 6b50d206d29386bdb79a585b93751890fd5abd97 Mon Sep 17 00:00:00 2001 From: decleaver <85503726+decleaver@users.noreply.github.com> Date: Fri, 12 Jul 2024 10:44:34 -0600 Subject: [PATCH] fix: task schema generation using maru and removing runner tests (#778) --- hack/generate-schema.sh | 20 +- src/cmd/internal.go | 13 +- src/types/tasks.go | 49 ----- tasks.schema.json | 394 +++++++++++++++++----------------------- 4 files changed, 184 insertions(+), 292 deletions(-) delete mode 100644 src/types/tasks.go diff --git a/hack/generate-schema.sh b/hack/generate-schema.sh index e1d1f856..9daacb8c 100755 --- a/hack/generate-schema.sh +++ b/hack/generate-schema.sh @@ -11,15 +11,23 @@ mv temp_uds.schema.json uds.schema.json go run main.go internal config-tasks-schema > tasks.schema.json # Adds pattern properties to all definitions to allow for yaml extensions -jq '.definitions |= map_values(. + {"patternProperties": {"^x-": {}}})' tasks.schema.json > temp_tasks.schema.json -mv temp_tasks.schema.json tasks.schema.json +jq ' + def addPatternProperties: + . + + if has("properties") then + {"patternProperties": {"^x-": {}}} + else + {} + end; + + walk(if type == "object" then addPatternProperties else . end) +' tasks.schema.json > temp_tasks.schema.json -# Modifies pattern properties to allow input parameters -jq '.definitions.Task.properties.inputs.patternProperties = {"^[_a-zA-Z][a-zA-Z0-9_-]*$": {"$schema": "http://json-schema.org/draft-04/schema#","$ref": "#/definitions/InputParameter"}}' tasks.schema.json > temp_tasks.schema.json -mv temp_tasks.schema.json tasks.schema.json -jq '.definitions.Action.properties.with.patternProperties = {"^[_a-zA-Z][a-zA-Z0-9_-]*$": {"additionalProperties": true}}' tasks.schema.json > temp_tasks.schema.json mv temp_tasks.schema.json tasks.schema.json +awk '{gsub(/\[github\.com\/defenseunicorns\/maru-runner\/src\/pkg\/variables\.ExtraVariableInfo\]/, ""); print}' tasks.schema.json > temp_tasks.schema.json + +mv temp_tasks.schema.json tasks.schema.json # Create the json schema for zarf.yaml go run main.go zarf internal gen-config-schema > zarf.schema.json diff --git a/src/cmd/internal.go b/src/cmd/internal.go index 2cef6e19..a29084f1 100644 --- a/src/cmd/internal.go +++ b/src/cmd/internal.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/alecthomas/jsonschema" + runnerCLI "github.com/defenseunicorns/maru-runner/src/cmd" "github.com/defenseunicorns/uds-cli/src/config/lang" "github.com/defenseunicorns/uds-cli/src/types" "github.com/defenseunicorns/zarf/src/pkg/message" @@ -45,15 +46,9 @@ var configTasksSchemaCmd = &cobra.Command{ Use: "config-tasks-schema", Aliases: []string{"c"}, Short: lang.CmdInternalConfigSchemaShort, - RunE: func(_ *cobra.Command, _ []string) error { - schema := jsonschema.Reflect(&types.TasksFile{}) - output, err := json.MarshalIndent(schema, "", " ") - if err != nil { - return fmt.Errorf(lang.CmdInternalConfigSchemaErr) - } - fmt.Print(string(output) + "\n") - - return nil + Run: func(cmd *cobra.Command, input []string) { + runnerCLI.RootCmd().SetArgs([]string{"internal", "config-tasks-schema"}) + runnerCLI.Execute() }, } diff --git a/src/types/tasks.go b/src/types/tasks.go deleted file mode 100644 index 1a3f0fe9..00000000 --- a/src/types/tasks.go +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023-Present The UDS Authors - -// Package types contains all the types used by UDS. -package types - -import ( - zarfVariables "github.com/defenseunicorns/zarf/src/pkg/variables" - zarfTypes "github.com/defenseunicorns/zarf/src/types" -) - -// TasksFile represents the contents of a tasks file -type TasksFile struct { - Includes []map[string]string `json:"includes,omitempty" jsonschema:"description=List of local task files to include"` - Variables []zarfVariables.InteractiveVariable `json:"variables,omitempty" jsonschema:"description=Definitions and default values for variables used in run.yaml"` - Tasks []Task `json:"tasks" jsonschema:"description=The list of tasks that can be run"` -} - -// Task represents a single task -type Task struct { - Name string `json:"name" jsonschema:"description=Name of the task"` - Description string `json:"description,omitempty" jsonschema:"description=Description of the task"` - Files []zarfTypes.ZarfFile `json:"files,omitempty" jsonschema:"description=Files or folders to download or copy"` - Actions []Action `json:"actions,omitempty" jsonschema:"description=Actions to take when running the task"` - Inputs map[string]InputParameter `json:"inputs,omitempty" jsonschema:"description=Input parameters for the task"` - EnvPath string `json:"envPath,omitempty" jsonschema:"description=Path to file containing environment variables"` -} - -// InputParameter represents a single input parameter for a task, to be used w/ `with` -type InputParameter struct { - Description string `json:"description" jsonschema:"description=Description of the parameter,required"` - DeprecatedMessage string `json:"deprecatedMessage,omitempty" jsonschema:"description=Message to display when the parameter is deprecated"` - Required bool `json:"required,omitempty" jsonschema:"description=Whether the parameter is required,default=true"` - Default string `json:"default,omitempty" jsonschema:"description=Default value for the parameter"` -} - -// TODO make schema complain if an action has more than one of cmd, task or wait - -// Action is a Zarf action inside a Task -type Action struct { - *zarfTypes.ZarfComponentAction `yaml:",inline"` - TaskReference string `json:"task,omitempty" jsonschema:"description=The task to run, mutually exclusive with cmd and wait"` - With map[string]string `json:"with,omitempty" jsonschema:"description=Input parameters to pass to the task,type=object"` -} - -// TaskReference references the name of a task -type TaskReference struct { - Name string `json:"name" jsonschema:"description=Name of the task to run"` -} diff --git a/tasks.schema.json b/tasks.schema.json index 31f71d90..0eedb910 100644 --- a/tasks.schema.json +++ b/tasks.schema.json @@ -1,9 +1,29 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/TasksFile", - "definitions": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/defenseunicorns/maru-runner/src/types/tasks-file", + "$ref": "#/$defs/TasksFile", + "$defs": { "Action": { "properties": { + "description": { + "type": "string", + "description": "Description of the action to be displayed during package execution instead of the command" + }, + "cmd": { + "type": "string", + "description": "The command to run. Must specify either cmd or wait for the action to do anything." + }, + "wait": { + "$ref": "#/$defs/ActionWait", + "description": "Wait for a condition to be met before continuing. Must specify either cmd or wait for the action." + }, + "env": { + "items": { + "type": "string" + }, + "type": "array", + "description": "Additional environment variables to set for the command" + }, "mute": { "type": "boolean", "description": "Hide the output of the command during package deployment (default false)" @@ -20,52 +40,24 @@ "type": "string", "description": "The working directory to run the command in (default is CWD)" }, - "env": { - "items": { - "type": "string" - }, - "type": "array", - "description": "Additional environment variables to set for the command" - }, - "cmd": { - "type": "string", - "description": "The command to run. Must specify either cmd or wait for the action to do anything." - }, "shell": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/Shell", + "$ref": "#/$defs/ShellPreference", "description": "(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems" }, - "setVariable": { - "pattern": "^[A-Z0-9_]+$", - "type": "string", - "description": "[Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to update with the output of the command. This variable will be available to all remaining actions and components in the package. This will be removed in Zarf v1.0.0" - }, "setVariables": { "items": { - "$ref": "#/definitions/Variable" + "$ref": "#/$defs/Variable" }, "type": "array", "description": "(onDeploy/cmd only) An array of variables to update with the output of the command. These variables will be available to all remaining actions and components in the package." }, - "description": { - "type": "string", - "description": "Description of the action to be displayed during package execution instead of the command" - }, - "wait": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/ZarfComponentActionWait", - "description": "Wait for a condition to be met before continuing. Must specify either cmd or wait for the action. See the 'zarf tools wait-for' command for more info." - }, "task": { "type": "string", "description": "The task to run" }, "with": { - "patternProperties": { - "^[_a-zA-Z][a-zA-Z0-9_-]*$": { - "additionalProperties": true - } + "additionalProperties": { + "type": "string" }, "type": "object", "description": "Input parameters to pass to the task" @@ -77,10 +69,111 @@ "^x-": {} } }, - "InputParameter": { + "ActionWait": { + "properties": { + "cluster": { + "$ref": "#/$defs/ActionWaitCluster", + "description": "Wait for a condition to be met in the cluster before continuing. Only one of cluster or network can be specified." + }, + "network": { + "$ref": "#/$defs/ActionWaitNetwork", + "description": "Wait for a condition to be met on the network before continuing. Only one of cluster or network can be specified." + } + }, + "additionalProperties": false, + "type": "object", + "patternProperties": { + "^x-": {} + } + }, + "ActionWaitCluster": { + "properties": { + "kind": { + "type": "string", + "description": "The kind of resource to wait for", + "examples": [ + "Pod", + "Deployment)" + ] + }, + "name": { + "type": "string", + "description": "The name of the resource or selector to wait for", + "examples": [ + "podinfo", + "app=podinfo" + ] + }, + "namespace": { + "type": "string", + "description": "The namespace of the resource to wait for" + }, + "condition": { + "type": "string", + "description": "The condition or jsonpath state to wait for; defaults to exist", + "examples": [ + "Ready", + "Available" + ] + } + }, + "additionalProperties": false, + "type": "object", "required": [ - "description" + "kind", + "name" ], + "patternProperties": { + "^x-": {} + } + }, + "ActionWaitNetwork": { + "properties": { + "protocol": { + "type": "string", + "enum": [ + "tcp", + "http", + "https" + ], + "description": "The protocol to wait for" + }, + "address": { + "type": "string", + "description": "The address to wait for", + "examples": [ + "localhost:8080", + "1.1.1.1" + ] + }, + "code": { + "type": "integer", + "description": "The HTTP status code to wait for if using http or https", + "examples": [ + 200, + 404 + ] + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "protocol", + "address" + ], + "patternProperties": { + "^x-": {} + } + }, + "ExtraVariableInfo": { + "properties": {}, + "additionalProperties": false, + "type": "object", + "patternProperties": { + "^x-": {} + } + }, + "InputParameter": { "properties": { "description": { "type": "string", @@ -92,7 +185,8 @@ }, "required": { "type": "boolean", - "description": "Whether the parameter is required" + "description": "Whether the parameter is required", + "default": true }, "default": { "type": "string", @@ -101,18 +195,26 @@ }, "additionalProperties": false, "type": "object", + "required": [ + "description" + ], "patternProperties": { "^x-": {} } }, "InteractiveVariable": { - "required": [ - "Variable" - ], "properties": { - "Variable": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/Variable" + "name": { + "type": "string", + "pattern": "^[A-Z0-9_]+$", + "description": "The name to be used for the variable" + }, + "pattern": { + "type": "string", + "description": "An optional regex pattern that a variable value must match before a package deployment can continue." + }, + "Extra": { + "$ref": "#/$defs/ExtraVariableInfo" }, "description": { "type": "string", @@ -129,11 +231,14 @@ }, "additionalProperties": false, "type": "object", + "required": [ + "name" + ], "patternProperties": { "^x-": {} } }, - "Shell": { + "ShellPreference": { "properties": { "windows": { "type": "string", @@ -177,9 +282,6 @@ } }, "Task": { - "required": [ - "name" - ], "properties": { "name": { "type": "string", @@ -189,28 +291,16 @@ "type": "string", "description": "Description of the task" }, - "files": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/ZarfFile" - }, - "type": "array", - "description": "Files or folders to download or copy" - }, "actions": { "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/Action" + "$ref": "#/$defs/Action" }, "type": "array", "description": "Actions to take when running the task" }, "inputs": { - "patternProperties": { - "^[_a-zA-Z][a-zA-Z0-9_-]*$": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/InputParameter" - } + "additionalProperties": { + "$ref": "#/$defs/InputParameter" }, "type": "object", "description": "Input parameters for the task" @@ -222,21 +312,19 @@ }, "additionalProperties": false, "type": "object", + "required": [ + "name" + ], "patternProperties": { "^x-": {} } }, "TasksFile": { - "required": [ - "tasks" - ], "properties": { "includes": { "items": { - "patternProperties": { - ".*": { - "type": "string" - } + "additionalProperties": { + "type": "string" }, "type": "object" }, @@ -245,16 +333,14 @@ }, "variables": { "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/InteractiveVariable" + "$ref": "#/$defs/InteractiveVariable" }, "type": "array", "description": "Definitions and default values for variables used in run.yaml" }, "tasks": { "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/Task" + "$ref": "#/$defs/Task" }, "type": "array", "description": "The list of tasks that can be run" @@ -262,181 +348,33 @@ }, "additionalProperties": false, "type": "object", + "required": [ + "tasks" + ], "patternProperties": { "^x-": {} } }, "Variable": { - "required": [ - "name" - ], "properties": { "name": { - "pattern": "^[A-Z0-9_]+$", "type": "string", + "pattern": "^[A-Z0-9_]+$", "description": "The name to be used for the variable" }, - "sensitive": { - "type": "boolean", - "description": "Whether to mark this variable as sensitive to not print it in the log" - }, - "autoIndent": { - "type": "boolean", - "description": "Whether to automatically indent the variable's value (if multiline) when templating. Based on the number of chars before the start of ###ZARF_VAR_." - }, "pattern": { "type": "string", "description": "An optional regex pattern that a variable value must match before a package deployment can continue." }, - "type": { - "enum": [ - "raw", - "file" - ], - "type": "string", - "description": "Changes the handling of a variable to load contents differently (i.e. from a file rather than as a raw variable - templated files should be kept below 1 MiB)" - } - }, - "additionalProperties": false, - "type": "object", - "patternProperties": { - "^x-": {} - } - }, - "ZarfComponentActionWait": { - "properties": { - "cluster": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/ZarfComponentActionWaitCluster", - "description": "Wait for a condition to be met in the cluster before continuing. Only one of cluster or network can be specified." - }, - "network": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/ZarfComponentActionWaitNetwork", - "description": "Wait for a condition to be met on the network before continuing. Only one of cluster or network can be specified." + "Extra": { + "$ref": "#/$defs/ExtraVariableInfo" } }, "additionalProperties": false, "type": "object", - "patternProperties": { - "^x-": {} - } - }, - "ZarfComponentActionWaitCluster": { "required": [ - "kind", "name" ], - "properties": { - "kind": { - "type": "string", - "description": "The kind of resource to wait for", - "examples": [ - "Pod", - "Deployment)" - ] - }, - "name": { - "type": "string", - "description": "The name of the resource or selector to wait for", - "examples": [ - "podinfo", - "app=podinfo" - ] - }, - "namespace": { - "type": "string", - "description": "The namespace of the resource to wait for" - }, - "condition": { - "type": "string", - "description": "The condition or jsonpath state to wait for; defaults to exist", - "examples": [ - "Ready", - "Available" - ] - } - }, - "additionalProperties": false, - "type": "object", - "patternProperties": { - "^x-": {} - } - }, - "ZarfComponentActionWaitNetwork": { - "required": [ - "protocol", - "address" - ], - "properties": { - "protocol": { - "enum": [ - "tcp", - "http", - "https" - ], - "type": "string", - "description": "The protocol to wait for" - }, - "address": { - "type": "string", - "description": "The address to wait for", - "examples": [ - "localhost:8080", - "1.1.1.1" - ] - }, - "code": { - "type": "integer", - "description": "The HTTP status code to wait for if using http or https", - "examples": [ - 200, - 404 - ] - } - }, - "additionalProperties": false, - "type": "object", - "patternProperties": { - "^x-": {} - } - }, - "ZarfFile": { - "required": [ - "source", - "target" - ], - "properties": { - "source": { - "type": "string", - "description": "Local folder or file path or remote URL to pull into the package" - }, - "shasum": { - "type": "string", - "description": "(files only) Optional SHA256 checksum of the file" - }, - "target": { - "type": "string", - "description": "The absolute or relative path where the file or folder should be copied to during package deploy" - }, - "executable": { - "type": "boolean", - "description": "(files only) Determines if the file should be made executable during package deploy" - }, - "symlinks": { - "items": { - "type": "string" - }, - "type": "array", - "description": "List of symlinks to create during package deploy" - }, - "extractPath": { - "type": "string", - "description": "Local folder or file to be extracted from a 'source' archive" - } - }, - "additionalProperties": false, - "type": "object", "patternProperties": { "^x-": {} }