Skip to content

Commit fafad44

Browse files
authored
chore: improve logging around lifecycle scripts (#420)
1 parent b1dc272 commit fafad44

File tree

2 files changed

+89
-30
lines changed

2 files changed

+89
-30
lines changed

envbuilder.go

+8
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ func run(ctx context.Context, opts options.Options, execArgs *execArgsInfo) erro
169169
RemoteEnv: make(map[string]string),
170170
}
171171
if fileExists(opts.Filesystem, workingDir.Image()) {
172+
opts.Logger(log.LevelInfo, "Found magic image file at %s", workingDir.Image())
172173
if err = parseMagicImageFile(opts.Filesystem, workingDir.Image(), &runtimeData); err != nil {
173174
return fmt.Errorf("parse magic image file: %w", err)
174175
}
@@ -287,6 +288,7 @@ func run(ctx context.Context, opts options.Options, execArgs *execArgsInfo) erro
287288

288289
var buildParams *devcontainer.Compiled
289290
if opts.DockerfilePath == "" {
291+
opts.Logger(log.LevelInfo, "No Dockerfile specified, looking for a devcontainer.json...")
290292
// Only look for a devcontainer if a Dockerfile wasn't specified.
291293
// devcontainer is a standard, so it's reasonable to be the default.
292294
var devcontainerDir string
@@ -296,6 +298,7 @@ func run(ctx context.Context, opts options.Options, execArgs *execArgsInfo) erro
296298
opts.Logger(log.LevelError, "Failed to locate devcontainer.json: %s", err.Error())
297299
opts.Logger(log.LevelError, "Falling back to the default image...")
298300
} else {
301+
opts.Logger(log.LevelInfo, "Building in Devcontainer mode using %s", strings.TrimPrefix(runtimeData.DevcontainerPath, buildTimeWorkspaceFolder))
299302
// We know a devcontainer exists.
300303
// Let's parse it and use it!
301304
file, err := opts.Filesystem.Open(runtimeData.DevcontainerPath)
@@ -334,6 +337,7 @@ func run(ctx context.Context, opts options.Options, execArgs *execArgsInfo) erro
334337
} else {
335338
// If a Dockerfile was specified, we use that.
336339
dockerfilePath := filepath.Join(buildTimeWorkspaceFolder, opts.DockerfilePath)
340+
opts.Logger(log.LevelInfo, "Building in Dockerfile-only mode using %s", opts.DockerfilePath)
337341

338342
// If the dockerfilePath is specified and deeper than the base of WorkspaceFolder AND the BuildContextPath is
339343
// not defined, show a warning
@@ -1406,6 +1410,7 @@ func execOneLifecycleScript(
14061410
userInfo userInfo,
14071411
) error {
14081412
if s.IsEmpty() {
1413+
logf(log.LevelInfo, "=== No %s script specified", scriptName)
14091414
return nil
14101415
}
14111416
logf(log.LevelInfo, "=== Running %s as the %q user...", scriptName, userInfo.user.Username)
@@ -1424,6 +1429,7 @@ func execLifecycleScripts(
14241429
userInfo userInfo,
14251430
) error {
14261431
if options.PostStartScriptPath != "" {
1432+
options.Logger(log.LevelDebug, "Removing postStartScriptPath %s", options.PostStartScriptPath)
14271433
_ = os.Remove(options.PostStartScriptPath)
14281434
}
14291435

@@ -1432,6 +1438,8 @@ func execLifecycleScripts(
14321438
// skip remaining lifecycle commands
14331439
return nil
14341440
}
1441+
} else {
1442+
options.Logger(log.LevelDebug, "Skipping onCreateCommand for subsequent starts...")
14351443
}
14361444
if err := execOneLifecycleScript(ctx, options.Logger, scripts.UpdateContentCommand, "updateContentCommand", userInfo); err != nil {
14371445
// skip remaining lifecycle commands

integration/integration_test.go

+81-30
Original file line numberDiff line numberDiff line change
@@ -1188,37 +1188,88 @@ func TestBuildSecrets(t *testing.T) {
11881188
func TestLifecycleScripts(t *testing.T) {
11891189
t.Parallel()
11901190

1191-
// Ensures that a Git repository with a devcontainer.json is cloned and built.
1192-
srv := gittest.CreateGitServer(t, gittest.Options{
1193-
Files: map[string]string{
1194-
".devcontainer/devcontainer.json": `{
1195-
"name": "Test",
1196-
"build": {
1197-
"dockerfile": "Dockerfile"
1198-
},
1199-
"onCreateCommand": "echo create > /tmp/out",
1200-
"updateContentCommand": ["sh", "-c", "echo update >> /tmp/out"],
1201-
"postCreateCommand": "(echo -n postCreate. ; id -un) >> /tmp/out",
1202-
"postStartCommand": {
1203-
"parallel1": "echo parallel1 > /tmp/parallel1",
1204-
"parallel2": ["sh", "-c", "echo parallel2 > /tmp/parallel2"]
1205-
}
1206-
}`,
1207-
".devcontainer/Dockerfile": "FROM " + testImageAlpine + "\nUSER nobody",
1191+
for _, tt := range []struct {
1192+
name string
1193+
files map[string]string
1194+
outputCmd string
1195+
expectOutput string
1196+
}{
1197+
{
1198+
name: "build",
1199+
files: map[string]string{
1200+
".devcontainer/devcontainer.json": `{
1201+
"name": "Test",
1202+
"build": {
1203+
"dockerfile": "Dockerfile"
1204+
},
1205+
"onCreateCommand": "echo create > /tmp/out",
1206+
"updateContentCommand": ["sh", "-c", "echo update >> /tmp/out"],
1207+
"postCreateCommand": "(echo -n postCreate. ; id -un) >> /tmp/out",
1208+
"postStartCommand": {
1209+
"parallel1": "echo parallel1 > /tmp/parallel1",
1210+
"parallel2": ["sh", "-c", "echo parallel2 > /tmp/parallel2"]
1211+
}
1212+
}`,
1213+
".devcontainer/Dockerfile": "FROM " + testImageAlpine + "\nUSER nobody",
1214+
},
1215+
outputCmd: "cat /tmp/out /tmp/parallel1 /tmp/parallel2",
1216+
expectOutput: "create\nupdate\npostCreate.nobody\nparallel1\nparallel2",
12081217
},
1209-
})
1210-
ctr, err := runEnvbuilder(t, runOpts{env: []string{
1211-
envbuilderEnv("GIT_URL", srv.URL),
1212-
}})
1213-
require.NoError(t, err)
1214-
1215-
output := execContainer(t, ctr, "cat /tmp/out /tmp/parallel1 /tmp/parallel2")
1216-
require.Equal(t,
1217-
`create
1218-
update
1219-
postCreate.nobody
1220-
parallel1
1221-
parallel2`, strings.TrimSpace(output))
1218+
{
1219+
name: "image",
1220+
files: map[string]string{
1221+
".devcontainer/devcontainer.json": fmt.Sprintf(`{
1222+
"name": "Test",
1223+
"image": %q,
1224+
"containerUser": "nobody",
1225+
"onCreateCommand": "echo create > /tmp/out",
1226+
"updateContentCommand": ["sh", "-c", "echo update >> /tmp/out"],
1227+
"postCreateCommand": "(echo -n postCreate. ; id -un) >> /tmp/out",
1228+
"postStartCommand": {
1229+
"parallel1": "echo parallel1 > /tmp/parallel1",
1230+
"parallel2": ["sh", "-c", "echo parallel2 > /tmp/parallel2"]
1231+
}
1232+
}`, testImageAlpine),
1233+
},
1234+
outputCmd: "cat /tmp/out /tmp/parallel1 /tmp/parallel2",
1235+
expectOutput: "create\nupdate\npostCreate.nobody\nparallel1\nparallel2",
1236+
},
1237+
{
1238+
name: "label",
1239+
files: map[string]string{
1240+
".devcontainer/Dockerfile": fmt.Sprintf(`FROM %s
1241+
LABEL devcontainer.metadata='[{ \
1242+
"onCreateCommand": "echo create > /tmp/out", \
1243+
"updateContentCommand": ["sh", "-c", "echo update >> /tmp/out"], \
1244+
"postCreateCommand": "(echo -n postCreate. ; id -un) >> /tmp/out", \
1245+
"postStartCommand": { \
1246+
"parallel1": "echo parallel1 > /tmp/parallel1", \
1247+
"parallel2": ["sh", "-c", "echo parallel2 > /tmp/parallel2"] \
1248+
} \
1249+
}]'
1250+
USER nobody`, testImageAlpine),
1251+
},
1252+
outputCmd: "cat /tmp/out /tmp/parallel1 /tmp/parallel2",
1253+
expectOutput: "create\nupdate\npostCreate.nobody\nparallel1\nparallel2",
1254+
},
1255+
} {
1256+
tt := tt
1257+
t.Run(tt.name, func(t *testing.T) {
1258+
srv := gittest.CreateGitServer(t, gittest.Options{
1259+
Files: tt.files,
1260+
})
1261+
env := []string{
1262+
envbuilderEnv("GIT_URL", srv.URL),
1263+
}
1264+
if _, ok := tt.files[".devcontainer/devcontainer.json"]; !ok {
1265+
env = append(env, envbuilderEnv("DOCKERFILE_PATH", ".devcontainer/Dockerfile"))
1266+
}
1267+
ctr, err := runEnvbuilder(t, runOpts{env: env})
1268+
require.NoError(t, err, "failed to run envbuilder")
1269+
output := execContainer(t, ctr, tt.outputCmd)
1270+
require.Equal(t, tt.expectOutput, strings.TrimSpace(output))
1271+
})
1272+
}
12221273
}
12231274

12241275
func TestPostStartScript(t *testing.T) {

0 commit comments

Comments
 (0)