Skip to content

Commit 7cb6b0a

Browse files
committed
chore: improve logging around lifecycle scripts (#420)
(cherry picked from commit fafad44)
1 parent 6a1da0c commit 7cb6b0a

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
@@ -170,6 +170,7 @@ func run(ctx context.Context, opts options.Options, execArgs *execArgsInfo) erro
170170
RemoteEnv: make(map[string]string),
171171
}
172172
if fileExists(opts.Filesystem, workingDir.Image()) {
173+
opts.Logger(log.LevelInfo, "Found magic image file at %s", workingDir.Image())
173174
if err = parseMagicImageFile(opts.Filesystem, workingDir.Image(), &runtimeData); err != nil {
174175
return fmt.Errorf("parse magic image file: %w", err)
175176
}
@@ -288,6 +289,7 @@ func run(ctx context.Context, opts options.Options, execArgs *execArgsInfo) erro
288289

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

339343
// If the dockerfilePath is specified and deeper than the base of WorkspaceFolder AND the BuildContextPath is
340344
// not defined, show a warning
@@ -1411,6 +1415,7 @@ func execOneLifecycleScript(
14111415
userInfo userInfo,
14121416
) error {
14131417
if s.IsEmpty() {
1418+
logf(log.LevelInfo, "=== No %s script specified", scriptName)
14141419
return nil
14151420
}
14161421
logf(log.LevelInfo, "=== Running %s as the %q user...", scriptName, userInfo.user.Username)
@@ -1429,6 +1434,7 @@ func execLifecycleScripts(
14291434
userInfo userInfo,
14301435
) error {
14311436
if options.PostStartScriptPath != "" {
1437+
options.Logger(log.LevelDebug, "Removing postStartScriptPath %s", options.PostStartScriptPath)
14321438
_ = os.Remove(options.PostStartScriptPath)
14331439
}
14341440

@@ -1437,6 +1443,8 @@ func execLifecycleScripts(
14371443
// skip remaining lifecycle commands
14381444
return nil
14391445
}
1446+
} else {
1447+
options.Logger(log.LevelDebug, "Skipping onCreateCommand for subsequent starts...")
14401448
}
14411449
if err := execOneLifecycleScript(ctx, options.Logger, scripts.UpdateContentCommand, "updateContentCommand", userInfo); err != nil {
14421450
// skip remaining lifecycle commands

integration/integration_test.go

+81-30
Original file line numberDiff line numberDiff line change
@@ -1122,37 +1122,88 @@ func TestUnsetOptionsEnv(t *testing.T) {
11221122
func TestLifecycleScripts(t *testing.T) {
11231123
t.Parallel()
11241124

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

11581209
func TestPostStartScript(t *testing.T) {

0 commit comments

Comments
 (0)