Skip to content

Commit

Permalink
Merge pull request #30 from mumoshu/pass-globals-to-imported-jobs
Browse files Browse the repository at this point in the history
Pass globals to imported jobs
  • Loading branch information
mumoshu authored Sep 26, 2020
2 parents 97a4b02 + 17bb516 commit 1cbc008
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
option "project-dir" {
description = "Terraform projects directory"
default = "./defaultdir"
type = string
}

job "terraform plan" {
parameter "project" {
type = string
}

exec {
command = "bash"
args = ["-c", "echo ${opt.project-dir}/${param.project}"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
job "nested" {
import = "lib"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
option "project-dir" {
description = "Terraform projects directory"
default = "./defaultdir"
type = string
}

job "terraform plan" {
parameter "project" {
type = string
}

exec {
command = "bash"
args = ["-c", "echo ${opt.project-dir}/${param.project}"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
option "project-dir" {
# The default works from geodesic shell `projects` folder
default = 1
description = "Terraform projects directory"
type = number
}

job "nested" {
import = "lib"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DEFAULT
16 changes: 16 additions & 0 deletions examples/advanced/nested-import-global-propagation/lib/lib.variant
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
option "project-dir" {
description = "Terraform projects directory"
default = "./defaultdir"
type = string
}

job "terraform plan" {
parameter "project" {
type = string
}

exec {
command = "bash"
args = ["-c", "echo ${opt.project-dir}/${param.project}"]
}
}
10 changes: 10 additions & 0 deletions examples/advanced/nested-import-global-propagation/main.variant
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
option "project-dir" {
# The default works from geodesic shell `projects` folder
default = "./overridedir"
description = "Terraform projects directory"
type = string
}

job "nested" {
import = "lib"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OVERRIDE
4 changes: 3 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package variant

import "fmt"

func RunMain(env Env, opts ...Option) error {
cmd, path, args := GetPathAndArgsFromEnv(env)

Expand All @@ -11,7 +13,7 @@ func RunMain(env Env, opts ...Option) error {
}
}))
if err != nil {
panic(err)
return fmt.Errorf("loading command: %w", err)
}

return m.Run(args, RunOptions{DisableLocking: false})
Expand Down
25 changes: 23 additions & 2 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,27 @@ func TestExamples(t *testing.T) {
args: []string{"variant", "test"},
wd: "./examples/advanced/import-multi",
},
{
subject: "nested-import-global-propagation",
args: []string{"variant", "run", "nested", "terraform", "plan", "project"},
variantName: "",
wd: "./examples/advanced/nested-import-global-propagation",
expectOut: "./overridedir/project\n",
},
{
subject: "nested-import-global-propagation-default",
args: []string{"variant", "run", "nested", "terraform", "plan", "project"},
variantName: "",
wd: "./examples/advanced/nested-import-global-propagation-default",
expectOut: "./defaultdir/project\n",
},
{
subject: "nested-import-global-propagation-incompatible-type",
args: []string{"variant", "run", "nested", "terraform", "plan", "project"},
variantName: "",
wd: "./examples/advanced/nested-import-global-propagation-incompatible-type",
expectErr: "loading command: merging globals: imported job \"\" has incompatible option \"project-dir\": needs type of cty.Number, encountered cty.String",
},
{
subject: "options",
variantName: "",
Expand Down Expand Up @@ -292,8 +313,8 @@ func TestExamples(t *testing.T) {
if tc.expectErr != "" {
if err == nil {
t.Fatalf("Expected error didn't occur")
} else if err.Error() != tc.expectErr {
t.Fatalf("Unexpected error: want %q, got %q\n%s", tc.expectErr, err.Error(), errOut)
} else if d := cmp.Diff(tc.expectErr, err.Error()); d != "" {
t.Fatalf("Unexpected error:\nDIFF:\n%s\nSTDERR:\n%s", d, errOut)
}
} else if err != nil {
t.Fatalf("%+v\n%s", err, errOut)
Expand Down
59 changes: 54 additions & 5 deletions pkg/app/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"path/filepath"
"strings"

"github.com/hashicorp/hcl/v2/ext/typeexpr"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclparse"
Expand Down Expand Up @@ -257,6 +259,8 @@ func newApp(app *App, cc *HCL2Config, importDir func(string) (*App, error)) (*Ap

var conf *HCL2Config

var globals []JobSpec

jobByName := map[string]JobSpec{}
for _, j := range jobs {
jobByName[j.Name] = j
Expand Down Expand Up @@ -288,7 +292,10 @@ func newApp(app *App, cc *HCL2Config, importDir func(string) (*App, error)) (*Ap
//
// If the user-side has a global parameter/option that has the same name as the library-side,
// their types MUST match.
merged := mergeJobs(importedJob, j)
merged, err := mergeParamsAndOpts(importedJob, j)
if err != nil {
return nil, fmt.Errorf("merging globals: %w", err)
}

merged.Name = ""

Expand All @@ -302,6 +309,9 @@ func newApp(app *App, cc *HCL2Config, importDir func(string) (*App, error)) (*Ap
} else {
// Import the top-level job in the library as the non-top-level job on the user side
newJobName = j.Name

// And merge global parameters and options
globals = append(globals, importedJob)
}

importedJob.Name = newJobName
Expand All @@ -316,12 +326,27 @@ func newApp(app *App, cc *HCL2Config, importDir func(string) (*App, error)) (*Ap
}
}

root := jobByName[""]

for _, g := range globals {
merged, err := mergeParamsAndOpts(g, root)
if err != nil {
return nil, fmt.Errorf("merging globals: %w", err)
}

root = *merged
}

jobByName[""] = root

if conf == nil {
conf = cc
}

app.Config = conf

app.Config.JobSpec = root

app.JobByName = jobByName

var newJobs []JobSpec
Expand All @@ -335,7 +360,7 @@ func newApp(app *App, cc *HCL2Config, importDir func(string) (*App, error)) (*Ap
return app, nil
}

func mergeJobs(src JobSpec, dst JobSpec) *JobSpec {
func mergeParamsAndOpts(src JobSpec, dst JobSpec) (*JobSpec, error) {
paramMap := map[string]Parameter{}
optMap := map[string]OptionSpec{}

Expand All @@ -348,14 +373,38 @@ func mergeJobs(src JobSpec, dst JobSpec) *JobSpec {
}

for _, p := range src.Parameters {
if _, exists := paramMap[p.Name]; !exists {
if existing, exists := paramMap[p.Name]; !exists {
paramMap[p.Name] = p
} else {
exTy, err := typeexpr.TypeConstraint(existing.Type)
if err != nil {
return nil, fmt.Errorf("parsing parameter type: %w", err)
}
toTy, err := typeexpr.TypeConstraint(p.Type)
if err != nil {
return nil, fmt.Errorf("parsing parameter type: %w", err)
}
if exTy != toTy {
return nil, fmt.Errorf("imported job %q has incompatible parameter %q: needs type of %v, encountered %v", src.Name, p.Name, exTy.GoString(), toTy.GoString())
}
}
}

for _, o := range src.Options {
if _, exists := optMap[o.Name]; !exists {
if existing, exists := optMap[o.Name]; !exists {
optMap[o.Name] = o
} else {
exTy, err := typeexpr.TypeConstraint(existing.Type)
if err != nil {
return nil, fmt.Errorf("parsing option type: %w", err)
}
toTy, err := typeexpr.TypeConstraint(o.Type)
if err != nil {
return nil, fmt.Errorf("parsing option type: %w", err)
}
if exTy != toTy {
return nil, fmt.Errorf("imported job %q has incompatible option %q: needs type of %v, encountered %v", src.Name, o.Name, exTy.GoString(), toTy.GoString())
}
}
}

Expand All @@ -375,5 +424,5 @@ func mergeJobs(src JobSpec, dst JobSpec) *JobSpec {
dst.Parameters = params
dst.Options = opts

return &dst
return &dst, nil
}

0 comments on commit 1cbc008

Please sign in to comment.