Skip to content

Commit 59a6eab

Browse files
michaellee1019jgeaso1266
authored andcommitted
Validate there is a build path in meta.json before running reload commands (#5502)
1 parent 1df0214 commit 59a6eab

File tree

3 files changed

+163
-1
lines changed

3 files changed

+163
-1
lines changed

cli/module_build.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,9 @@ func reloadModuleActionInner(
11551155
if manifest == nil {
11561156
return fmt.Errorf(`manifest not found at "%s". manifest required for build`, moduleFlagPath)
11571157
}
1158+
if manifest.Build == nil || manifest.Build.Build == "" {
1159+
return errors.New("your meta.json cannot have an empty build step. It is required for 'reload' and 'reload-local' commands")
1160+
}
11581161
if !cloudBuild {
11591162
err = moduleBuildLocalAction(c, manifest, environment)
11601163
buildPath = manifest.Build.Path

cli/module_build_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ func createTestManifest(t *testing.T, path string, overrides map[string]any) str
5050

5151
// Apply overrides
5252
for key, value := range overrides {
53-
defaultManifest[key] = value
53+
if value == nil {
54+
// nil means delete the key entirely
55+
delete(defaultManifest, key)
56+
} else {
57+
defaultManifest[key] = value
58+
}
5459
}
5560

5661
// Marshal to JSON

cli/module_reload_test.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,157 @@ func TestMutateModuleConfig(t *testing.T) {
337337
test.That(t, modules[0]["version"], test.ShouldEqual, expectedVersion)
338338
})
339339
}
340+
341+
func TestReloadWithMissingBuildSection(t *testing.T) {
342+
logger := logging.NewTestLogger(t)
343+
344+
t.Run("reload-local with missing build section", func(t *testing.T) {
345+
// Create manifest without build section (nil value deletes the key)
346+
manifestPath := createTestManifest(t, "", map[string]any{
347+
"build": nil,
348+
})
349+
350+
confStruct, err := structpb.NewStruct(map[string]any{
351+
"modules": []any{},
352+
})
353+
test.That(t, err, test.ShouldBeNil)
354+
355+
userInfo, err := structpb.NewStruct(map[string]any{
356+
"version": "0.90.0",
357+
"platform": "linux/amd64",
358+
})
359+
test.That(t, err, test.ShouldBeNil)
360+
361+
cCtx, vc, _, _ := setup(
362+
mockFullAppServiceClient(confStruct, userInfo, nil),
363+
nil,
364+
&inject.BuildServiceClient{},
365+
map[string]any{
366+
moduleFlagPath: manifestPath,
367+
generalFlagPartID: "part-123",
368+
moduleFlagLocal: true,
369+
generalFlagNoProgress: true,
370+
},
371+
"token",
372+
)
373+
374+
// Test reload-local (cloudBuild=false)
375+
err = reloadModuleActionInner(cCtx, vc, parseStructFromCtx[reloadModuleArgs](cCtx), logger, false)
376+
test.That(t, err, test.ShouldNotBeNil)
377+
test.That(t, err.Error(), test.ShouldContainSubstring, "cannot have an empty build step")
378+
test.That(t, err.Error(), test.ShouldContainSubstring, "required for 'reload' and 'reload-local' commands")
379+
})
380+
381+
t.Run("reload (cloud) with missing build section", func(t *testing.T) {
382+
// Create manifest without build section (nil value deletes the key)
383+
manifestPath := createTestManifest(t, "", map[string]any{
384+
"build": nil,
385+
})
386+
387+
confStruct, err := structpb.NewStruct(map[string]any{
388+
"modules": []any{},
389+
})
390+
test.That(t, err, test.ShouldBeNil)
391+
392+
userInfo, err := structpb.NewStruct(map[string]any{
393+
"version": "0.90.0",
394+
"platform": "linux/amd64",
395+
})
396+
test.That(t, err, test.ShouldBeNil)
397+
398+
cCtx, vc, _, _ := setup(
399+
mockFullAppServiceClient(confStruct, userInfo, nil),
400+
nil,
401+
&inject.BuildServiceClient{},
402+
map[string]any{
403+
moduleFlagPath: manifestPath,
404+
generalFlagPartID: "part-123",
405+
generalFlagNoProgress: true,
406+
},
407+
"token",
408+
)
409+
410+
// Test reload with cloud build (cloudBuild=true)
411+
err = reloadModuleActionInner(cCtx, vc, parseStructFromCtx[reloadModuleArgs](cCtx), logger, true)
412+
test.That(t, err, test.ShouldNotBeNil)
413+
test.That(t, err.Error(), test.ShouldContainSubstring, "cannot have an empty build step")
414+
test.That(t, err.Error(), test.ShouldContainSubstring, "required for 'reload' and 'reload-local' commands")
415+
})
416+
417+
t.Run("reload-local with empty build command", func(t *testing.T) {
418+
// Create manifest with build section but empty build command
419+
manifestPath := createTestManifest(t, "", map[string]any{
420+
"build": map[string]any{
421+
"path": "module",
422+
"arch": []any{"linux/amd64"},
423+
// "build" field is missing or empty
424+
},
425+
})
426+
427+
confStruct, err := structpb.NewStruct(map[string]any{
428+
"modules": []any{},
429+
})
430+
test.That(t, err, test.ShouldBeNil)
431+
432+
userInfo, err := structpb.NewStruct(map[string]any{
433+
"version": "0.90.0",
434+
"platform": "linux/amd64",
435+
})
436+
test.That(t, err, test.ShouldBeNil)
437+
438+
cCtx, vc, _, _ := setup(
439+
mockFullAppServiceClient(confStruct, userInfo, nil),
440+
nil,
441+
&inject.BuildServiceClient{},
442+
map[string]any{
443+
moduleFlagPath: manifestPath,
444+
generalFlagPartID: "part-123",
445+
moduleFlagLocal: true,
446+
generalFlagNoProgress: true,
447+
},
448+
"token",
449+
)
450+
451+
err = reloadModuleActionInner(cCtx, vc, parseStructFromCtx[reloadModuleArgs](cCtx), logger, false)
452+
test.That(t, err, test.ShouldNotBeNil)
453+
test.That(t, err.Error(), test.ShouldContainSubstring, "cannot have an empty build step")
454+
})
455+
456+
t.Run("reload-local with --no-build flag still requires manifest", func(t *testing.T) {
457+
// Create manifest without build section (nil value deletes the key)
458+
manifestPath := createTestManifest(t, "", map[string]any{
459+
"build": nil,
460+
})
461+
462+
confStruct, err := structpb.NewStruct(map[string]any{
463+
"modules": []any{},
464+
})
465+
test.That(t, err, test.ShouldBeNil)
466+
467+
userInfo, err := structpb.NewStruct(map[string]any{
468+
"version": "0.90.0",
469+
"platform": "linux/amd64",
470+
})
471+
test.That(t, err, test.ShouldBeNil)
472+
473+
cCtx, vc, _, _ := setup(
474+
mockFullAppServiceClient(confStruct, userInfo, nil),
475+
nil,
476+
&inject.BuildServiceClient{},
477+
map[string]any{
478+
moduleFlagPath: manifestPath,
479+
generalFlagPartID: "part-123",
480+
moduleBuildFlagNoBuild: true, // --no-build flag
481+
moduleFlagLocal: true,
482+
generalFlagNoProgress: true,
483+
},
484+
"token",
485+
)
486+
487+
// Even with --no-build flag, manifest with build section is still required
488+
// because it needs to know where to find the already-built artifact
489+
err = reloadModuleActionInner(cCtx, vc, parseStructFromCtx[reloadModuleArgs](cCtx), logger, false)
490+
test.That(t, err, test.ShouldNotBeNil)
491+
test.That(t, err.Error(), test.ShouldContainSubstring, "manifest required for reload")
492+
})
493+
}

0 commit comments

Comments
 (0)