Skip to content

Commit 15b5420

Browse files
authored
chore: improve logging around lifecycle scripts (#420) (#427)
(cherry picked from commit fafad44) Co-authored-by: Mathias Fredriksson <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 0b4600f commit 15b5420

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
@@ -1402,6 +1406,7 @@ func execOneLifecycleScript(
14021406
userInfo userInfo,
14031407
) error {
14041408
if s.IsEmpty() {
1409+
logf(log.LevelInfo, "=== No %s script specified", scriptName)
14051410
return nil
14061411
}
14071412
logf(log.LevelInfo, "=== Running %s as the %q user...", scriptName, userInfo.user.Username)
@@ -1420,6 +1425,7 @@ func execLifecycleScripts(
14201425
userInfo userInfo,
14211426
) error {
14221427
if options.PostStartScriptPath != "" {
1428+
options.Logger(log.LevelDebug, "Removing postStartScriptPath %s", options.PostStartScriptPath)
14231429
_ = os.Remove(options.PostStartScriptPath)
14241430
}
14251431

@@ -1428,6 +1434,8 @@ func execLifecycleScripts(
14281434
// skip remaining lifecycle commands
14291435
return nil
14301436
}
1437+
} else {
1438+
options.Logger(log.LevelDebug, "Skipping onCreateCommand for subsequent starts...")
14311439
}
14321440
if err := execOneLifecycleScript(ctx, options.Logger, scripts.UpdateContentCommand, "updateContentCommand", userInfo); err != nil {
14331441
// skip remaining lifecycle commands

integration/integration_test.go

+81-30
Original file line numberDiff line numberDiff line change
@@ -1125,37 +1125,88 @@ func TestUnsetOptionsEnv(t *testing.T) {
11251125
func TestLifecycleScripts(t *testing.T) {
11261126
t.Parallel()
11271127

1128-
// Ensures that a Git repository with a devcontainer.json is cloned and built.
1129-
srv := gittest.CreateGitServer(t, gittest.Options{
1130-
Files: map[string]string{
1131-
".devcontainer/devcontainer.json": `{
1132-
"name": "Test",
1133-
"build": {
1134-
"dockerfile": "Dockerfile"
1135-
},
1136-
"onCreateCommand": "echo create > /tmp/out",
1137-
"updateContentCommand": ["sh", "-c", "echo update >> /tmp/out"],
1138-
"postCreateCommand": "(echo -n postCreate. ; id -un) >> /tmp/out",
1139-
"postStartCommand": {
1140-
"parallel1": "echo parallel1 > /tmp/parallel1",
1141-
"parallel2": ["sh", "-c", "echo parallel2 > /tmp/parallel2"]
1142-
}
1143-
}`,
1144-
".devcontainer/Dockerfile": "FROM " + testImageAlpine + "\nUSER nobody",
1128+
for _, tt := range []struct {
1129+
name string
1130+
files map[string]string
1131+
outputCmd string
1132+
expectOutput string
1133+
}{
1134+
{
1135+
name: "build",
1136+
files: map[string]string{
1137+
".devcontainer/devcontainer.json": `{
1138+
"name": "Test",
1139+
"build": {
1140+
"dockerfile": "Dockerfile"
1141+
},
1142+
"onCreateCommand": "echo create > /tmp/out",
1143+
"updateContentCommand": ["sh", "-c", "echo update >> /tmp/out"],
1144+
"postCreateCommand": "(echo -n postCreate. ; id -un) >> /tmp/out",
1145+
"postStartCommand": {
1146+
"parallel1": "echo parallel1 > /tmp/parallel1",
1147+
"parallel2": ["sh", "-c", "echo parallel2 > /tmp/parallel2"]
1148+
}
1149+
}`,
1150+
".devcontainer/Dockerfile": "FROM " + testImageAlpine + "\nUSER nobody",
1151+
},
1152+
outputCmd: "cat /tmp/out /tmp/parallel1 /tmp/parallel2",
1153+
expectOutput: "create\nupdate\npostCreate.nobody\nparallel1\nparallel2",
11451154
},
1146-
})
1147-
ctr, err := runEnvbuilder(t, runOpts{env: []string{
1148-
envbuilderEnv("GIT_URL", srv.URL),
1149-
}})
1150-
require.NoError(t, err)
1151-
1152-
output := execContainer(t, ctr, "cat /tmp/out /tmp/parallel1 /tmp/parallel2")
1153-
require.Equal(t,
1154-
`create
1155-
update
1156-
postCreate.nobody
1157-
parallel1
1158-
parallel2`, strings.TrimSpace(output))
1155+
{
1156+
name: "image",
1157+
files: map[string]string{
1158+
".devcontainer/devcontainer.json": fmt.Sprintf(`{
1159+
"name": "Test",
1160+
"image": %q,
1161+
"containerUser": "nobody",
1162+
"onCreateCommand": "echo create > /tmp/out",
1163+
"updateContentCommand": ["sh", "-c", "echo update >> /tmp/out"],
1164+
"postCreateCommand": "(echo -n postCreate. ; id -un) >> /tmp/out",
1165+
"postStartCommand": {
1166+
"parallel1": "echo parallel1 > /tmp/parallel1",
1167+
"parallel2": ["sh", "-c", "echo parallel2 > /tmp/parallel2"]
1168+
}
1169+
}`, testImageAlpine),
1170+
},
1171+
outputCmd: "cat /tmp/out /tmp/parallel1 /tmp/parallel2",
1172+
expectOutput: "create\nupdate\npostCreate.nobody\nparallel1\nparallel2",
1173+
},
1174+
{
1175+
name: "label",
1176+
files: map[string]string{
1177+
".devcontainer/Dockerfile": fmt.Sprintf(`FROM %s
1178+
LABEL devcontainer.metadata='[{ \
1179+
"onCreateCommand": "echo create > /tmp/out", \
1180+
"updateContentCommand": ["sh", "-c", "echo update >> /tmp/out"], \
1181+
"postCreateCommand": "(echo -n postCreate. ; id -un) >> /tmp/out", \
1182+
"postStartCommand": { \
1183+
"parallel1": "echo parallel1 > /tmp/parallel1", \
1184+
"parallel2": ["sh", "-c", "echo parallel2 > /tmp/parallel2"] \
1185+
} \
1186+
}]'
1187+
USER nobody`, testImageAlpine),
1188+
},
1189+
outputCmd: "cat /tmp/out /tmp/parallel1 /tmp/parallel2",
1190+
expectOutput: "create\nupdate\npostCreate.nobody\nparallel1\nparallel2",
1191+
},
1192+
} {
1193+
tt := tt
1194+
t.Run(tt.name, func(t *testing.T) {
1195+
srv := gittest.CreateGitServer(t, gittest.Options{
1196+
Files: tt.files,
1197+
})
1198+
env := []string{
1199+
envbuilderEnv("GIT_URL", srv.URL),
1200+
}
1201+
if _, ok := tt.files[".devcontainer/devcontainer.json"]; !ok {
1202+
env = append(env, envbuilderEnv("DOCKERFILE_PATH", ".devcontainer/Dockerfile"))
1203+
}
1204+
ctr, err := runEnvbuilder(t, runOpts{env: env})
1205+
require.NoError(t, err, "failed to run envbuilder")
1206+
output := execContainer(t, ctr, tt.outputCmd)
1207+
require.Equal(t, tt.expectOutput, strings.TrimSpace(output))
1208+
})
1209+
}
11591210
}
11601211

11611212
func TestPostStartScript(t *testing.T) {

0 commit comments

Comments
 (0)