Skip to content

Commit 1cbc008

Browse files
authored
Merge pull request #30 from mumoshu/pass-globals-to-imported-jobs
Pass globals to imported jobs
2 parents 97a4b02 + 17bb516 commit 1cbc008

File tree

11 files changed

+153
-8
lines changed

11 files changed

+153
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
option "project-dir" {
2+
description = "Terraform projects directory"
3+
default = "./defaultdir"
4+
type = string
5+
}
6+
7+
job "terraform plan" {
8+
parameter "project" {
9+
type = string
10+
}
11+
12+
exec {
13+
command = "bash"
14+
args = ["-c", "echo ${opt.project-dir}/${param.project}"]
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
job "nested" {
2+
import = "lib"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
option "project-dir" {
2+
description = "Terraform projects directory"
3+
default = "./defaultdir"
4+
type = string
5+
}
6+
7+
job "terraform plan" {
8+
parameter "project" {
9+
type = string
10+
}
11+
12+
exec {
13+
command = "bash"
14+
args = ["-c", "echo ${opt.project-dir}/${param.project}"]
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
option "project-dir" {
2+
# The default works from geodesic shell `projects` folder
3+
default = 1
4+
description = "Terraform projects directory"
5+
type = number
6+
}
7+
8+
job "nested" {
9+
import = "lib"
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DEFAULT
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
option "project-dir" {
2+
description = "Terraform projects directory"
3+
default = "./defaultdir"
4+
type = string
5+
}
6+
7+
job "terraform plan" {
8+
parameter "project" {
9+
type = string
10+
}
11+
12+
exec {
13+
command = "bash"
14+
args = ["-c", "echo ${opt.project-dir}/${param.project}"]
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
option "project-dir" {
2+
# The default works from geodesic shell `projects` folder
3+
default = "./overridedir"
4+
description = "Terraform projects directory"
5+
type = string
6+
}
7+
8+
job "nested" {
9+
import = "lib"
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
OVERRIDE

main.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package variant
22

3+
import "fmt"
4+
35
func RunMain(env Env, opts ...Option) error {
46
cmd, path, args := GetPathAndArgsFromEnv(env)
57

@@ -11,7 +13,7 @@ func RunMain(env Env, opts ...Option) error {
1113
}
1214
}))
1315
if err != nil {
14-
panic(err)
16+
return fmt.Errorf("loading command: %w", err)
1517
}
1618

1719
return m.Run(args, RunOptions{DisableLocking: false})

main_test.go

+23-2
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,27 @@ func TestExamples(t *testing.T) {
154154
args: []string{"variant", "test"},
155155
wd: "./examples/advanced/import-multi",
156156
},
157+
{
158+
subject: "nested-import-global-propagation",
159+
args: []string{"variant", "run", "nested", "terraform", "plan", "project"},
160+
variantName: "",
161+
wd: "./examples/advanced/nested-import-global-propagation",
162+
expectOut: "./overridedir/project\n",
163+
},
164+
{
165+
subject: "nested-import-global-propagation-default",
166+
args: []string{"variant", "run", "nested", "terraform", "plan", "project"},
167+
variantName: "",
168+
wd: "./examples/advanced/nested-import-global-propagation-default",
169+
expectOut: "./defaultdir/project\n",
170+
},
171+
{
172+
subject: "nested-import-global-propagation-incompatible-type",
173+
args: []string{"variant", "run", "nested", "terraform", "plan", "project"},
174+
variantName: "",
175+
wd: "./examples/advanced/nested-import-global-propagation-incompatible-type",
176+
expectErr: "loading command: merging globals: imported job \"\" has incompatible option \"project-dir\": needs type of cty.Number, encountered cty.String",
177+
},
157178
{
158179
subject: "options",
159180
variantName: "",
@@ -292,8 +313,8 @@ func TestExamples(t *testing.T) {
292313
if tc.expectErr != "" {
293314
if err == nil {
294315
t.Fatalf("Expected error didn't occur")
295-
} else if err.Error() != tc.expectErr {
296-
t.Fatalf("Unexpected error: want %q, got %q\n%s", tc.expectErr, err.Error(), errOut)
316+
} else if d := cmp.Diff(tc.expectErr, err.Error()); d != "" {
317+
t.Fatalf("Unexpected error:\nDIFF:\n%s\nSTDERR:\n%s", d, errOut)
297318
}
298319
} else if err != nil {
299320
t.Fatalf("%+v\n%s", err, errOut)

pkg/app/load.go

+54-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"path/filepath"
99
"strings"
1010

11+
"github.com/hashicorp/hcl/v2/ext/typeexpr"
12+
1113
"github.com/hashicorp/hcl/v2"
1214
"github.com/hashicorp/hcl/v2/gohcl"
1315
"github.com/hashicorp/hcl/v2/hclparse"
@@ -257,6 +259,8 @@ func newApp(app *App, cc *HCL2Config, importDir func(string) (*App, error)) (*Ap
257259

258260
var conf *HCL2Config
259261

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

293300
merged.Name = ""
294301

@@ -302,6 +309,9 @@ func newApp(app *App, cc *HCL2Config, importDir func(string) (*App, error)) (*Ap
302309
} else {
303310
// Import the top-level job in the library as the non-top-level job on the user side
304311
newJobName = j.Name
312+
313+
// And merge global parameters and options
314+
globals = append(globals, importedJob)
305315
}
306316

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

329+
root := jobByName[""]
330+
331+
for _, g := range globals {
332+
merged, err := mergeParamsAndOpts(g, root)
333+
if err != nil {
334+
return nil, fmt.Errorf("merging globals: %w", err)
335+
}
336+
337+
root = *merged
338+
}
339+
340+
jobByName[""] = root
341+
319342
if conf == nil {
320343
conf = cc
321344
}
322345

323346
app.Config = conf
324347

348+
app.Config.JobSpec = root
349+
325350
app.JobByName = jobByName
326351

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

338-
func mergeJobs(src JobSpec, dst JobSpec) *JobSpec {
363+
func mergeParamsAndOpts(src JobSpec, dst JobSpec) (*JobSpec, error) {
339364
paramMap := map[string]Parameter{}
340365
optMap := map[string]OptionSpec{}
341366

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

350375
for _, p := range src.Parameters {
351-
if _, exists := paramMap[p.Name]; !exists {
376+
if existing, exists := paramMap[p.Name]; !exists {
352377
paramMap[p.Name] = p
378+
} else {
379+
exTy, err := typeexpr.TypeConstraint(existing.Type)
380+
if err != nil {
381+
return nil, fmt.Errorf("parsing parameter type: %w", err)
382+
}
383+
toTy, err := typeexpr.TypeConstraint(p.Type)
384+
if err != nil {
385+
return nil, fmt.Errorf("parsing parameter type: %w", err)
386+
}
387+
if exTy != toTy {
388+
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())
389+
}
353390
}
354391
}
355392

356393
for _, o := range src.Options {
357-
if _, exists := optMap[o.Name]; !exists {
394+
if existing, exists := optMap[o.Name]; !exists {
358395
optMap[o.Name] = o
396+
} else {
397+
exTy, err := typeexpr.TypeConstraint(existing.Type)
398+
if err != nil {
399+
return nil, fmt.Errorf("parsing option type: %w", err)
400+
}
401+
toTy, err := typeexpr.TypeConstraint(o.Type)
402+
if err != nil {
403+
return nil, fmt.Errorf("parsing option type: %w", err)
404+
}
405+
if exTy != toTy {
406+
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())
407+
}
359408
}
360409
}
361410

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

378-
return &dst
427+
return &dst, nil
379428
}

0 commit comments

Comments
 (0)