Skip to content

Commit b5101f9

Browse files
committed
fix: apply value as version option in devcontainer
1 parent 82204fd commit b5101f9

File tree

2 files changed

+21
-22
lines changed

2 files changed

+21
-22
lines changed

devcontainer/devcontainer.go

+9-13
Original file line numberDiff line numberDiff line change
@@ -191,41 +191,37 @@ func (s *Spec) compileFeatures(fs billy.Filesystem, scratchDir, remoteUser, dock
191191
if err != nil {
192192
return "", fmt.Errorf("parse feature ref %s: %w", featureRefRaw, err)
193193
}
194-
featureImage := featureRefParsed.Repository.Name()
195-
featureTag := featureRefParsed.TagStr()
196194

197195
featureOpts := map[string]any{}
198196
switch t := s.Features[featureRefRaw].(type) {
199197
case string:
200-
featureTag = t
198+
// As a shorthand, the value of the `features`` property can be provided as a
199+
// single string. This string is mapped to an option called version.
200+
// https://containers.dev/implementors/features/#devcontainer-json-properties
201+
featureOpts["version"] = t
201202
case map[string]any:
202203
featureOpts = t
203204
}
204205

205-
featureRef := featureImage
206-
if featureTag != "" {
207-
featureRef += ":" + featureTag
208-
}
209-
210206
// It's important for caching that this directory is static.
211207
// If it changes on each run then the container will not be cached.
212208
//
213209
// devcontainers/cli has a very complex method of computing the feature
214210
// name from the feature reference. We're just going to hash it for simplicity.
215-
featureSha := md5.Sum([]byte(featureRef))
216-
featureName := filepath.Base(featureImage)
211+
featureSha := md5.Sum([]byte(featureRefRaw))
212+
featureName := filepath.Base(featureRefParsed.Repository.Name())
217213
featureDir := filepath.Join(featuresDir, fmt.Sprintf("%s-%x", featureName, featureSha[:4]))
218214
err = fs.MkdirAll(featureDir, 0644)
219215
if err != nil {
220216
return "", err
221217
}
222-
spec, err := features.Extract(fs, featureDir, featureRef)
218+
spec, err := features.Extract(fs, featureDir, featureRefRaw)
223219
if err != nil {
224-
return "", fmt.Errorf("extract feature %s: %w", featureRef, err)
220+
return "", fmt.Errorf("extract feature %s: %w", featureRefRaw, err)
225221
}
226222
directive, err := spec.Compile(featureOpts)
227223
if err != nil {
228-
return "", fmt.Errorf("compile feature %s: %w", featureRef, err)
224+
return "", fmt.Errorf("compile feature %s: %w", featureRefRaw, err)
229225
}
230226
featureDirectives = append(featureDirectives, directive)
231227
}

devcontainer/devcontainer_test.go

+12-9
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func TestParse(t *testing.T) {
4141
func TestCompileWithFeatures(t *testing.T) {
4242
t.Parallel()
4343
registry := registrytest.New(t)
44-
featureOne := registrytest.WriteContainer(t, registry, "coder/test:tomato", features.TarLayerMediaType, map[string]any{
44+
featureOne := registrytest.WriteContainer(t, registry, "coder/one:tomato", features.TarLayerMediaType, map[string]any{
4545
"install.sh": "hey",
4646
"devcontainer-feature.json": features.Spec{
4747
ID: "rust",
@@ -53,7 +53,7 @@ func TestCompileWithFeatures(t *testing.T) {
5353
},
5454
},
5555
})
56-
featureTwo := registrytest.WriteContainer(t, registry, "coder/test:potato", features.TarLayerMediaType, map[string]any{
56+
featureTwo := registrytest.WriteContainer(t, registry, "coder/two:potato", features.TarLayerMediaType, map[string]any{
5757
"install.sh": "hey",
5858
"devcontainer-feature.json": features.Spec{
5959
ID: "go",
@@ -63,10 +63,13 @@ func TestCompileWithFeatures(t *testing.T) {
6363
ContainerEnv: map[string]string{
6464
"POTATO": "example",
6565
},
66+
Options: map[string]features.Option{
67+
"version": {
68+
Type: "string",
69+
},
70+
},
6671
},
6772
})
68-
// Update the tag to ensure it comes from the feature value!
69-
featureTwoFake := strings.Join(append(strings.Split(featureTwo, ":")[:2], "faketag"), ":")
7073

7174
raw := `{
7275
"build": {
@@ -77,7 +80,7 @@ func TestCompileWithFeatures(t *testing.T) {
7780
"image": "codercom/code-server:latest",
7881
"features": {
7982
"` + featureOne + `": {},
80-
"` + featureTwoFake + `": "potato"
83+
"` + featureTwo + `": "potato"
8184
}
8285
}`
8386
dc, err := devcontainer.Parse([]byte(raw))
@@ -95,12 +98,12 @@ func TestCompileWithFeatures(t *testing.T) {
9598
require.Equal(t, `FROM codercom/code-server:latest
9699
97100
USER root
98-
# Go potato - Example description!
99-
ENV POTATO=example
100-
RUN .envbuilder/features/test-`+featureTwoSha+`/install.sh
101101
# Rust tomato - Example description!
102102
ENV TOMATO=example
103-
RUN .envbuilder/features/test-`+featureOneSha+`/install.sh
103+
RUN .envbuilder/features/one-`+featureOneSha+`/install.sh
104+
# Go potato - Example description!
105+
ENV POTATO=example
106+
RUN VERSION=potato .envbuilder/features/two-`+featureTwoSha+`/install.sh
104107
USER 1000`, params.DockerfileContent)
105108
}
106109

0 commit comments

Comments
 (0)