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
475 changes: 475 additions & 0 deletions actfile-schema.json

Large diffs are not rendered by default.

79 changes: 78 additions & 1 deletion cmd/cmd_validate.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package cmd

import (
"encoding/json"
"fmt"
"os"
"os/user"
"strings"

"github.com/actionforge/actrun-cli/core"
u "github.com/actionforge/actrun-cli/utils"
"github.com/santhosh-tekuri/jsonschema/v6"
"github.com/spf13/cobra"
"go.yaml.in/yaml/v4"
)

// ActfileSchema holds the embedded JSON schema bytes, set from main.
var ActfileSchema []byte

var cmdValidate = &cobra.Command{
Use: "validate [graph-file]",
Short: "Validate a graph file.",
Expand All @@ -38,6 +43,56 @@ var cmdValidate = &cobra.Command{
},
}

func validateSchema(data any) error {
if len(ActfileSchema) == 0 {
return fmt.Errorf("actfile schema not loaded")
}

var schemaObj any
if err := json.Unmarshal(ActfileSchema, &schemaObj); err != nil {
return fmt.Errorf("failed to parse schema JSON: %w", err)
}

compiler := jsonschema.NewCompiler()
if err := compiler.AddResource("actfile-schema.json", schemaObj); err != nil {
return fmt.Errorf("failed to add schema resource: %w", err)
}

schema, err := compiler.Compile("actfile-schema.json")
if err != nil {
return fmt.Errorf("failed to compile schema: %w", err)
}

return schema.Validate(convertToJSONCompatible(data))
}

// convertToJSONCompatible recursively converts YAML-unmarshalled data into
// types that the JSON schema validator accepts.
func convertToJSONCompatible(v any) any {
switch val := v.(type) {
case map[string]any:
result := make(map[string]any, len(val))
for k, v := range val {
result[k] = convertToJSONCompatible(v)
}
return result
case []any:
result := make([]any, len(val))
for i, v := range val {
result[i] = convertToJSONCompatible(v)
}
return result
case int:
return float64(val)
case int64:
return float64(val)
case float32:
return float64(val)
default:
return val
}
}

func validateGraph(filePath string) error {
fmt.Printf("Validating '%s'...\n", filePath)

Expand All @@ -54,10 +109,17 @@ func validateGraph(filePath string) error {
return err
}

hasErrors := false

if err := validateSchema(graphYaml); err != nil {
fmt.Printf("\n❌ Graph schema validation failed:\n%v\n", err)
hasErrors = true
}

_, errs := core.LoadGraph(graphYaml, nil, "", true, core.RunOpts{})

if len(errs) > 0 {
fmt.Printf("\n❌ Validation failed with %d error(s):\n", len(errs))
fmt.Printf("\n❌ Graph validation failed with %d error(s):\n", len(errs))

for i, e := range errs {
if leafErr, ok := e.(*core.LeafError); ok {
Expand All @@ -67,6 +129,10 @@ func validateGraph(filePath string) error {
fmt.Printf("\n%d. %v\n", i+1, e)
}
}
hasErrors = true
}

if hasErrors {
return fmt.Errorf("validation failed")
}

Expand All @@ -84,6 +150,17 @@ func expandPath(path string) string {
return os.ExpandEnv(path)
}

var cmdSchema = &cobra.Command{
Use: "schema",
Short: "Print the JSON schema for .act files.",
Long: `Prints the JSON schema used to validate ActionForge graph (.act) files.`,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(string(ActfileSchema))
},
}

func init() {
cmdRoot.AddCommand(cmdValidate)
cmdRoot.AddCommand(cmdSchema)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/rhysd/actionlint v1.7.10
github.com/rossmacarthur/cases v0.3.0
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
github.com/rossmacarthur/cases v0.3.0 h1:7rlsXK2qHb6mQUOX+/IGDO9YyFXqjiDiMpkHfIl54Yg=
github.com/rossmacarthur/cases v0.3.0/go.mod h1:ebnckUNBu5QAJGxFNai/H0IN133rLze6gmoxJyYvHW0=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
Expand Down
6 changes: 6 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package main

import (
_ "embed"

_ "github.com/actionforge/actrun-cli/api"
"github.com/actionforge/actrun-cli/cmd"
_ "github.com/actionforge/actrun-cli/cmd"
Expand All @@ -9,6 +11,9 @@ import (
"github.com/actionforge/actrun-cli/utils"
)

//go:embed actfile-schema.json
var actfileSchema []byte

func main() {
utils.ApplyLogLevel()

Expand All @@ -23,5 +28,6 @@ func main() {
return
}

cmd.ActfileSchema = actfileSchema
cmd.Execute()
}
1 change: 1 addition & 0 deletions tests_e2e/references/reference_app.sh_l10
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Usage:
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
schema Print the JSON schema for .act files.
validate Validate a graph file.
version Print the version number of actrun

Expand Down
2 changes: 1 addition & 1 deletion tests_e2e/references/reference_app.sh_l35
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ looking for value: 'graph_file'
no value (is optional) found for: 'graph_file'
Validating '[REDACTED]/missing-exec-connection1.act'...

Validation failed with 1 error(s):
Graph validation failed with 1 error(s):

--- Error 1 ---
error:
Expand Down
2 changes: 1 addition & 1 deletion tests_e2e/references/reference_app.sh_l36
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ looking for value: 'graph_file'
no value (is optional) found for: 'graph_file'
Validating '[REDACTED]/missing-exec-connection2.act'...

Validation failed with 2 error(s):
Graph validation failed with 2 error(s):

--- Error 1 ---
error:
Expand Down
1 change: 1 addition & 0 deletions tests_e2e/references/reference_contexts_env.sh_l26
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Usage:
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
schema Print the JSON schema for .act files.
validate Validate a graph file.
version Print the version number of actrun

Expand Down
2 changes: 1 addition & 1 deletion tests_e2e/references/reference_validate.sh_l8
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ looking for value: 'graph_file'
evaluated to: 'validate.act'
Validating 'validate.act'...

Validation failed with 4 error(s):
Graph validation failed with 4 error(s):

--- Error 1 ---
error:
Expand Down
Loading
Loading