diff --git a/core/base.go b/core/base.go index be52fc9..410e27b 100644 --- a/core/base.go +++ b/core/base.go @@ -39,6 +39,10 @@ func getIndexPortRegex() *regexp.Regexp { return indexPortRegex } +type PortValidationOpts struct { + IsGroupNode bool +} + type CredentialType int const ( @@ -402,7 +406,7 @@ func (n *NodeTypeDefinitionFull) IsValid() error { return nil } -func PortDefValidation(portId string, portDef PortDefinition) error { +func PortDefValidation(portId string, portDef PortDefinition, opts PortValidationOpts) error { if portId == "" { return errors.New("port id is missing") } @@ -417,14 +421,14 @@ func PortDefValidation(portId string, portDef PortDefinition) error { // [0]: "exec" // [1]: "" // [2]: "" - if strings.Contains(m[2], "-") { + if strings.Contains(m[2], "-") && !opts.IsGroupNode { return CreateErr(nil, nil, "execution port '%v' must not contain hyphens", portId) } } } else if !portDef.Exec { if m != nil { return CreateErr(nil, nil, "port '%v' starts with 'exec-' but is not flagged as exec", portId) - } else if strings.Contains(portId, "-") { + } else if strings.Contains(portId, "-") && !opts.IsGroupNode { return CreateErr(nil, nil, "port '%v' must not contain hyphens", portId) } } @@ -491,7 +495,9 @@ func RegisterNodeFactory(nodeDefStr string, fn nodeFactoryFunc) error { } if nodeDef.Id != "core/test" { - err = PortDefValidation(string(inputId), inputDef.PortDefinition) + err = PortDefValidation(string(inputId), inputDef.PortDefinition, PortValidationOpts{ + IsGroupNode: strings.HasPrefix(nodeDef.Id, "core/group@"), + }) if err != nil { return CreateErr(nil, err, "input '%v' is invalid", inputId) } @@ -537,7 +543,10 @@ func RegisterNodeFactory(nodeDefStr string, fn nodeFactoryFunc) error { outputIndexes[outputDef.Index] = string(outputId) if nodeDef.Id != "core/test" { - err = PortDefValidation(string(outputId), outputDef.PortDefinition) + err = PortDefValidation(string(outputId), outputDef.PortDefinition, PortValidationOpts{ + IsGroupNode: strings.HasPrefix(nodeDef.Id, "core/group@"), + }) + if err != nil { return CreateErr(nil, err, "input '%v' is invalid", outputId) } diff --git a/core/github.go b/core/github.go index 25c48d0..fcf7710 100644 --- a/core/github.go +++ b/core/github.go @@ -7,9 +7,12 @@ import ( "maps" "os" "os/exec" + "path/filepath" + "runtime" "strings" "github.com/actionforge/actrun-cli/utils" + "github.com/go-git/go-git/v5" "github.com/google/shlex" ) @@ -249,3 +252,201 @@ func decodeJsonFromEnvValue[T any](envValue string) (map[string]T, error) { } return envMap, nil } + +func getRunnerOS() string { + switch runtime.GOOS { + case "darwin": + return "macOS" + case "linux": + return "Linux" + case "windows": + return "Windows" + default: + return runtime.GOOS + } +} + +func getRunnerArch() string { + switch runtime.GOARCH { + case "arm64", "aarch64": + return "ARM64" + case "amd64": + return "X64" + default: + return runtime.GOARCH + } +} + +// Extracts owner/repo from a git remote URL. Supports http and ssh formats. +func parseRepoFromRemoteURL(remoteURL string) (string, error) { + remoteURL = strings.TrimSpace(remoteURL) + + // handle ssh format + if strings.HasPrefix(remoteURL, "git@") { + // git@github.com:user/repo.git -> user/repo + colonIdx := strings.Index(remoteURL, ":") + if colonIdx == -1 { + return "", fmt.Errorf("invalid SSH remote URL format: %s", remoteURL) + } + path := remoteURL[colonIdx+1:] + path = strings.TrimSuffix(path, ".git") + return path, nil + } + + // handle https format + if strings.HasPrefix(remoteURL, "https://") || strings.HasPrefix(remoteURL, "http://") { + path := remoteURL + path = strings.TrimPrefix(path, "https://") + path = strings.TrimPrefix(path, "http://") + + // remove the host, eg github.com + slashIdx := strings.Index(path, "/") + if slashIdx == -1 { + return "", fmt.Errorf("invalid HTTPS remote URL format: %s", remoteURL) + } + path = path[slashIdx+1:] + path = strings.TrimSuffix(path, ".git") + return path, nil + } + + return "", fmt.Errorf("unsupported remote URL format: %s", remoteURL) +} + +func SetupGitHubActionsEnv(finalEnv map[string]string) error { + sourceWorkspace := finalEnv["GITHUB_WORKSPACE"] + if sourceWorkspace == "" { + return CreateErr(nil, nil, "GITHUB_WORKSPACE environment variable is required"). + SetHint("Set GITHUB_WORKSPACE to the path of a git repository.") + } + + eventName := finalEnv["GITHUB_EVENT_NAME"] + if eventName == "" { + return CreateErr(nil, nil, "GITHUB_EVENT_NAME environment variable is required"). + SetHint("Set GITHUB_EVENT_NAME to the event that triggered the workflow (e.g., push, pull_request).") + } + + repo, err := git.PlainOpenWithOptions(sourceWorkspace, &git.PlainOpenOptions{ + DetectDotGit: true, + }) + if err != nil { + return CreateErr(nil, err, "unable to open git repository at GITHUB_WORKSPACE"). + SetHint("Ensure GITHUB_WORKSPACE points to a valid git repository.") + } + + remote, err := repo.Remote("origin") + if err != nil { + return CreateErr(nil, err, "remote \"origin\" not found in git repository"). + SetHint("Your repository must have a GitHub remote named \"origin\".") + } + + remoteURLs := remote.Config().URLs + if len(remoteURLs) == 0 { + return CreateErr(nil, nil, "remote \"origin\" has no URLs configured"). + SetHint("Set the origin URL with: git remote set-url origin ") + } + + repoName, err := parseRepoFromRemoteURL(remoteURLs[0]) + if err != nil { + return CreateErr(nil, err, "unable to parse repository from remote URL"). + SetHint("Ensure the origin remote URL is a valid GitHub repository URL.") + } + + head, err := repo.Head() + if err != nil { + return CreateErr(nil, err, "failed to get git HEAD"). + SetHint("Ensure you have at least one commit in the repository.") + } + + // here we default to main if we are not in a branch + branch := "main" + if head.Name().IsBranch() { + branch = head.Name().Short() + } + + sha := head.Hash().String() + + // create RUNNER_WORKSPACE with an empty directory for the actual GITHUB_WORKSPACE + runnerWorkspace, err := os.MkdirTemp("", "actrun-runner-") + if err != nil { + return CreateErr(nil, err, "failed to create runner workspace directory"). + SetHint("Check that you have write permissions to the system temp directory.") + } + + // extract repo name for the workspace dir name + repoParts := strings.Split(repoName, "/") + repoBaseName := repoParts[len(repoParts)-1] + + // here create the actual GITHUB_WORKSPACE inside the runner workspace + githubWorkspace := filepath.Join(runnerWorkspace, repoBaseName) + if err := os.MkdirAll(githubWorkspace, 0755); err != nil { + return CreateErr(nil, err, "failed to create github workspace directory"). + SetHint("Check that you have write permissions to the system temp directory.") + } + + // create temp dir for runner files + tempDir, err := os.MkdirTemp("", "actrun-") + if err != nil { + return CreateErr(nil, err, "failed to create temp directory"). + SetHint("Check that you have write permissions to the system temp directory.") + } + + homeDir, err := os.UserHomeDir() + if err != nil { + return CreateErr(nil, err, "failed to get home directory"). + SetHint("Ensure the HOME environment variable is set correctly.") + } + toolCacheDir := filepath.Join(homeDir, ".actrun", "tool-cache") + + setIfNotSet := func(key, value string) { + if finalEnv[key] == "" { + finalEnv[key] = value + } + } + + setIfNotSet("CI", "true") + setIfNotSet("GITHUB_ACTIONS", "true") + setIfNotSet("GITHUB_REPOSITORY", repoName) + setIfNotSet("GITHUB_REF", "refs/heads/"+branch) + setIfNotSet("GITHUB_REF_NAME", branch) + setIfNotSet("GITHUB_SHA", sha) + setIfNotSet("RUNNER_OS", getRunnerOS()) + setIfNotSet("RUNNER_ARCH", getRunnerArch()) + setIfNotSet("RUNNER_TOOL_CACHE", toolCacheDir) + setIfNotSet("GITHUB_OUTPUT", filepath.Join(tempDir, "output")) + setIfNotSet("GITHUB_ENV", filepath.Join(tempDir, "env")) + setIfNotSet("GITHUB_PATH", filepath.Join(tempDir, "path")) + setIfNotSet("GITHUB_STATE", filepath.Join(tempDir, "state")) + setIfNotSet("GITHUB_STEP_SUMMARY", filepath.Join(tempDir, "summary")) + setIfNotSet("RUNNER_TEMP", tempDir) + + // override a few envs here no matter if they were set or not + finalEnv["GITHUB_WORKSPACE"] = githubWorkspace + finalEnv["RUNNER_WORKSPACE"] = runnerWorkspace + + err = os.MkdirAll(toolCacheDir, 0755) + if err != nil { + return CreateErr(nil, err, "failed to create tool cache directory"). + SetHint("Check that you have write permissions to %s.", toolCacheDir) + } + + fileCommandFiles := []string{ + finalEnv["GITHUB_OUTPUT"], + finalEnv["GITHUB_ENV"], + finalEnv["GITHUB_PATH"], + finalEnv["GITHUB_STATE"], + finalEnv["GITHUB_STEP_SUMMARY"], + } + + for _, filePath := range fileCommandFiles { + if filePath != "" { + f, err := os.Create(filePath) + if err != nil { + return CreateErr(nil, err, "failed to create file command file %s", filePath). + SetHint("Check that you have write permissions to the runner temp directory.") + } + f.Close() + } + } + + return nil +} diff --git a/core/graph.go b/core/graph.go index 3464baf..d6988ef 100644 --- a/core/graph.go +++ b/core/graph.go @@ -399,6 +399,38 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R printExplicit(envTracker, false) } + if isGitHubWorkflow { + err = SetupGitHubActionsEnv(finalEnv) + if err != nil { + return CreateErr(nil, err, "failed to setup GitHub Actions environment") + } + } + + // set cwd for current process. `ACT_CWD` is used for non GitHub workflows + if cwd := finalEnv["GITHUB_WORKSPACE"]; cwd != "" { + originalCwd, err := os.Getwd() + if err != nil { + return CreateErr(nil, err, "failed to get current working directory") + } + if err := os.Chdir(cwd); err != nil { + return CreateErr(nil, err, "failed to change working directory to GITHUB_WORKSPACE") + } + defer func() { + _ = os.Chdir(originalCwd) + }() + } else if cwd := finalEnv["ACT_CWD"]; cwd != "" { + originalCwd, err := os.Getwd() + if err != nil { + return CreateErr(nil, err, "failed to get current working directory") + } + if err := os.Chdir(cwd); err != nil { + return CreateErr(nil, err, "failed to change working directory to ACT_CWD") + } + defer func() { + _ = os.Chdir(originalCwd) + }() + } + // construct the `github` context var ghContext map[string]any var errGh error diff --git a/nodes/gh-action@v1.go b/nodes/gh-action@v1.go index f0bd30c..9e28044 100644 --- a/nodes/gh-action@v1.go +++ b/nodes/gh-action@v1.go @@ -19,6 +19,9 @@ import ( u "github.com/actionforge/actrun-cli/utils" "github.com/Masterminds/semver/v3" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/google/uuid" "go.yaml.in/yaml/v4" ) @@ -398,34 +401,78 @@ func init() { return nil, []error{core.CreateErr(nil, nil, "INPUT_TOKEN not set")} } - cloneUrl := fmt.Sprintf("https://%s@github.com/%s/%s", ghToken, owner, repo) + cloneUrl := fmt.Sprintf("https://github.com/%s/%s", owner, repo) if err := os.MkdirAll(filepath.Dir(repoRoot), 0755); err != nil { return nil, []error{core.CreateErr(nil, err, "unable to create action directory")} } - c := exec.Command("git", "clone", "--quiet", "--no-checkout", cloneUrl, repoRoot) - c.Stderr = os.Stderr - err = c.Run() + cloneOpts := &git.CloneOptions{ + URL: cloneUrl, + NoCheckout: true, + } + + // TODO: (Seb) Find alternative for running in + // debug mode if user has SSH keys set up instead of a token. + cloneOpts.Auth = &http.BasicAuth{ + Username: "x-access-token", + Password: ghToken, + } + + clonedRepo, err := git.PlainClone(repoRoot, false, cloneOpts) if err != nil { - return nil, []error{err} + return nil, []error{core.CreateErr(nil, err, "failed to clone repository")} + } + + // checkout the specified ref (or HEAD if empty) + worktree, err := clonedRepo.Worktree() + if err != nil { + return nil, []error{core.CreateErr(nil, err, "failed to get worktree")} + } + + checkoutOpts := &git.CheckoutOptions{} + if ref != "" { + // resolve as a revision (commit hash, tag, or branch) + hash, err := clonedRepo.ResolveRevision(plumbing.Revision(ref)) + if err != nil { + // if not a hash, try as a branch name + checkoutOpts.Branch = plumbing.NewBranchReferenceName(ref) + } else { + checkoutOpts.Hash = *hash + } } - c = exec.Command("git", "checkout", u.If(ref == "", "HEAD", ref)) - c.Stderr = os.Stderr - c.Dir = repoRoot - err = c.Run() + err = worktree.Checkout(checkoutOpts) if err != nil { - return nil, []error{err} + return nil, []error{core.CreateErr(nil, err, "failed to checkout ref '%s'", ref)} } } else { - // reset in case something or someone tampered with the cached gh actions - c := exec.Command("git", "reset", "--quiet", "--hard", u.If(ref == "", "HEAD", ref)) - c.Stderr = os.Stderr - c.Dir = repoRoot - err = c.Run() + // reset in just case something tampered with the cached gh actions + existingRepo, err := git.PlainOpen(repoRoot) + if err != nil { + return nil, []error{core.CreateErr(nil, err, "failed to open cached repository")} + } + + worktree, err := existingRepo.Worktree() + if err != nil { + return nil, []error{core.CreateErr(nil, err, "failed to get worktree")} + } + + checkoutOpts := &git.CheckoutOptions{ + Force: true, + } + if ref != "" { + hash, err := existingRepo.ResolveRevision(plumbing.Revision(ref)) + if err != nil { + checkoutOpts.Branch = plumbing.NewBranchReferenceName(ref) + } else { + checkoutOpts.Hash = *hash + } + } + + err = worktree.Checkout(checkoutOpts) if err != nil { - return nil, []error{err} + return nil, []error{core.CreateErr(nil, err, "failed to reset to ref '%s'", ref)} } } diff --git a/nodes/group@v1.go b/nodes/group@v1.go index 00d6397..be295d8 100644 --- a/nodes/group@v1.go +++ b/nodes/group@v1.go @@ -149,28 +149,36 @@ func init() { } // Check for name collisions - if graphInputs != nil && graphOutputs != nil { - for inputId := range graphInputs { - if _, ok := graphOutputs[core.OutputId(inputId)]; ok { - err := core.CreateErr(nil, nil, "group node has an input and output with the same name '%s'", inputId) - if !validate { - return nil, []error{err} - } + for inputId := range graphInputs { + if _, ok := graphOutputs[core.OutputId(inputId)]; ok { + err := core.CreateErr(nil, nil, "group node has an input and output with the same name '%s'", inputId) + if !validate { + return nil, []error{err} + } + collectedErrors = append(collectedErrors, err) + } + } + + // validate each port definition + if validate { + for inputId, inputDef := range graphInputs { + if err := core.PortDefValidation(string(inputId), inputDef.PortDefinition, core.PortValidationOpts{ + IsGroupNode: true, + }); err != nil { + err = core.CreateErr(nil, err, "input '%v' is invalid", inputId) collectedErrors = append(collectedErrors, err) } } - for outputId := range graphOutputs { - if _, ok := graphInputs[core.InputId(outputId)]; ok { - err := core.CreateErr(nil, nil, "group node has an input and output with the same name '%s'", outputId) - if !validate { - return nil, []error{err} - } + for outputId, outputDef := range graphOutputs { + if err := core.PortDefValidation(string(outputId), outputDef.PortDefinition, core.PortValidationOpts{ + IsGroupNode: true, + }); err != nil { + err = core.CreateErr(nil, err, "output '%v' is invalid", outputId) collectedErrors = append(collectedErrors, err) } } } - // Pass 'validate' to LoadGraph to collect internal graph errors ag, errs := core.LoadGraph(subGraph, group, parentId, validate) if len(errs) > 0 { if !validate { @@ -181,7 +189,7 @@ func init() { group.NodeBaseComponent.Graph = &ag - // Connect the group node with the group input node + // connect the group node with the group input node if graphInputs != nil { n, ok := ag.FindNode(ag.Entry) if !ok || n == nil { diff --git a/tests_e2e/references/reference_app.sh_l12 b/tests_e2e/references/reference_app.sh_l12 index ff2033a..e7ed64a 100644 --- a/tests_e2e/references/reference_app.sh_l12 +++ b/tests_e2e/references/reference_app.sh_l12 @@ -23,7 +23,7 @@ hint: stack trace: github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1035 + graph.go:1067 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_dir-walk.sh_l56 b/tests_e2e/references/reference_dir-walk.sh_l56 index c4eea98..d4516da 100644 --- a/tests_e2e/references/reference_dir-walk.sh_l56 +++ b/tests_e2e/references/reference_dir-walk.sh_l56 @@ -40,11 +40,11 @@ github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteImpl github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteEntry start@v1.go:45 github.com/actionforge/actrun-cli/core.RunGraph - graph.go:430 + graph.go:462 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_error_no_output.sh_l8 b/tests_e2e/references/reference_error_no_output.sh_l8 index c1ee55e..0e2d98c 100644 --- a/tests_e2e/references/reference_error_no_output.sh_l8 +++ b/tests_e2e/references/reference_error_no_output.sh_l8 @@ -51,11 +51,11 @@ github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteImpl github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteEntry start@v1.go:45 github.com/actionforge/actrun-cli/core.RunGraph - graph.go:430 + graph.go:462 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_group-error.sh_l8 b/tests_e2e/references/reference_group-error.sh_l8 index e53949a..be2b8af 100644 --- a/tests_e2e/references/reference_group-error.sh_l8 +++ b/tests_e2e/references/reference_group-error.sh_l8 @@ -250,7 +250,7 @@ github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteImpl github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteEntry start@v1.go:45 github.com/actionforge/actrun-cli/core.RunGraph - graph.go:430 + graph.go:462 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 diff --git a/tests_e2e/references/reference_group-port-collision.sh_l13 b/tests_e2e/references/reference_group-port-collision.sh_l13 index f9302c4..55aae64 100644 --- a/tests_e2e/references/reference_group-port-collision.sh_l13 +++ b/tests_e2e/references/reference_group-port-collision.sh_l13 @@ -21,21 +21,21 @@ error: stack trace: github.com/actionforge/actrun-cli/nodes.init.40.func1 - group@v1.go:155 + group@v1.go:154 github.com/actionforge/actrun-cli/core.NewNodeInstance - base.go:610 + base.go:619 github.com/actionforge/actrun-cli/core.LoadNode - graph.go:603 + graph.go:635 github.com/actionforge/actrun-cli/core.LoadNodes - graph.go:543 + graph.go:575 github.com/actionforge/actrun-cli/core.LoadGraph - graph.go:458 + graph.go:490 github.com/actionforge/actrun-cli/core.RunGraph graph.go:279 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_index.sh_l20 b/tests_e2e/references/reference_index.sh_l20 index 073edd5..85d1838 100644 --- a/tests_e2e/references/reference_index.sh_l20 +++ b/tests_e2e/references/reference_index.sh_l20 @@ -84,11 +84,11 @@ github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteImpl github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteEntry start@v1.go:45 github.com/actionforge/actrun-cli/core.RunGraph - graph.go:430 + graph.go:462 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_run-python-embedded.sh_l13 b/tests_e2e/references/reference_run-python-embedded.sh_l13 index 45f2b1e..4d62986 100644 --- a/tests_e2e/references/reference_run-python-embedded.sh_l13 +++ b/tests_e2e/references/reference_run-python-embedded.sh_l13 @@ -27,19 +27,19 @@ stack trace: github.com/actionforge/actrun-cli/nodes.init.51.func1 nrun-python-embedded@v1.go:16 github.com/actionforge/actrun-cli/core.NewNodeInstance - base.go:610 + base.go:619 github.com/actionforge/actrun-cli/core.LoadNode - graph.go:603 + graph.go:635 github.com/actionforge/actrun-cli/core.LoadNodes - graph.go:543 + graph.go:575 github.com/actionforge/actrun-cli/core.LoadGraph - graph.go:458 + graph.go:490 github.com/actionforge/actrun-cli/core.RunGraph graph.go:279 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_s3_aws_walk.sh_l22 b/tests_e2e/references/reference_s3_aws_walk.sh_l22 index 7091fdf..2b66827 100644 --- a/tests_e2e/references/reference_s3_aws_walk.sh_l22 +++ b/tests_e2e/references/reference_s3_aws_walk.sh_l22 @@ -44,11 +44,11 @@ github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteImpl github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteEntry start@v1.go:45 github.com/actionforge/actrun-cli/core.RunGraph - graph.go:430 + graph.go:462 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_s3_aws_walk.sh_l44 b/tests_e2e/references/reference_s3_aws_walk.sh_l44 index 7091fdf..2b66827 100644 --- a/tests_e2e/references/reference_s3_aws_walk.sh_l44 +++ b/tests_e2e/references/reference_s3_aws_walk.sh_l44 @@ -44,11 +44,11 @@ github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteImpl github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteEntry start@v1.go:45 github.com/actionforge/actrun-cli/core.RunGraph - graph.go:430 + graph.go:462 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_select-data.sh_l9 b/tests_e2e/references/reference_select-data.sh_l9 index 01d53d1..6526406 100644 --- a/tests_e2e/references/reference_select-data.sh_l9 +++ b/tests_e2e/references/reference_select-data.sh_l9 @@ -91,11 +91,11 @@ github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteImpl github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteEntry start@v1.go:45 github.com/actionforge/actrun-cli/core.RunGraph - graph.go:430 + graph.go:462 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_e2e/references/reference_string-transform.sh_l61 b/tests_e2e/references/reference_string-transform.sh_l61 index 87142ca..204d2eb 100644 --- a/tests_e2e/references/reference_string-transform.sh_l61 +++ b/tests_e2e/references/reference_string-transform.sh_l61 @@ -51,11 +51,11 @@ github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteImpl github.com/actionforge/actrun-cli/nodes.(*StartNode).ExecuteEntry start@v1.go:45 github.com/actionforge/actrun-cli/core.RunGraph - graph.go:430 + graph.go:462 github.com/actionforge/actrun-cli/core.RunGraphFromString - graph.go:1020 + graph.go:1052 github.com/actionforge/actrun-cli/core.RunGraphFromFile - graph.go:1038 + graph.go:1070 github.com/actionforge/actrun-cli/cmd.cmdRootRun cmd_root.go:186 github.com/spf13/cobra.(*Command).execute diff --git a/tests_unit/core_test.go b/tests_unit/core_test.go index d1cfadb..09c49f3 100644 --- a/tests_unit/core_test.go +++ b/tests_unit/core_test.go @@ -43,7 +43,9 @@ func TestPortValidation(t *testing.T) { // Run each test case for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - err := core.PortDefValidation(tc.portId, tc.portDef) + err := core.PortDefValidation(tc.portId, tc.portDef, core.PortValidationOpts{ + IsGroupNode: false, + }) if (err != nil) != tc.shouldErr { t.Errorf("unexpected error: %v, expected error: %v", err, tc.shouldErr) }