Skip to content

Commit 5bcf53a

Browse files
authored
Fix: Handle missing features (#1040)
1 parent 6d12ad9 commit 5bcf53a

File tree

5 files changed

+19
-4
lines changed

5 files changed

+19
-4
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
Notable changes.
44

5+
## June 2025
6+
7+
### [0.78.0]
8+
- Fix: Handle missing features (https://github.com/devcontainers/cli/pull/1040)
9+
510
## May 2025
611

712
### [0.77.0]

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@devcontainers/cli",
33
"description": "Dev Containers CLI",
4-
"version": "0.77.0",
4+
"version": "0.78.0",
55
"bin": {
66
"devcontainer": "devcontainer.js"
77
},

src/spec-configuration/containerFeaturesConfiguration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ export async function loadVersionInfo(params: ContainerFeatureInternalParams, co
527527
const featureRef = getRef(nullLog, userFeatureId); // Filters out Feature identifiers that cannot be versioned (e.g. local paths, deprecated, etc..)
528528
if (featureRef) {
529529
const versions = (await getVersionsStrictSorted(params, featureRef))
530-
?.reverse();
530+
?.reverse() || [];
531531
if (versions) {
532532
const lockfileVersion = lockfile?.features[userFeatureId]?.version;
533533
let wanted = lockfileVersion;
@@ -550,7 +550,7 @@ export async function loadVersionInfo(params: ContainerFeatureInternalParams, co
550550
wanted,
551551
wantedMajor: wanted && semver.major(wanted)?.toString(),
552552
latest: versions[0],
553-
latestMajor: semver.major(versions[0])?.toString(),
553+
latestMajor: versions[0] && semver.major(versions[0])?.toString(),
554554
};
555555
}
556556
}

src/test/container-features/configs/lockfile-outdated-command/.devcontainer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"ghcr.io/devcontainers/features/github-cli": "latest",
88
"ghcr.io/devcontainers/features/azure-cli:0": "latest",
99
"ghcr.io/codspace/versioning/foo:0.3.1": "latest",
10+
"ghcr.io/codspace/doesnotexist:0.1.2": "latest",
1011
"./mylocalfeature": {},
1112
"terraform": "latest",
1213
"https://myfeatures.com/features.tgz": "latest"

src/test/container-features/lockfile.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ describe('Lockfile', function () {
123123
assert.strictEqual(foo.wantedMajor, '0');
124124
assert.strictEqual(foo.latest, '2.11.1');
125125
assert.strictEqual(foo.latestMajor, '2');
126+
127+
const doesnotexist = response.features['ghcr.io/codspace/doesnotexist:0.1.2'];
128+
assert.ok(doesnotexist);
129+
assert.strictEqual(doesnotexist.current, undefined);
130+
assert.strictEqual(doesnotexist.wanted, undefined);
131+
assert.strictEqual(doesnotexist.wantedMajor, undefined);
132+
assert.strictEqual(doesnotexist.latest, undefined);
133+
assert.strictEqual(doesnotexist.latestMajor, undefined);
126134
});
127135

128136
it('outdated command with text output', async () => {
@@ -131,7 +139,7 @@ describe('Lockfile', function () {
131139
const res = await shellExec(`${cli} outdated --workspace-folder ${workspaceFolder} --output-format text`);
132140
const response = res.stdout;
133141
// Count number of lines of output
134-
assert.strictEqual(response.split('\n').length, 7); // 5 valid Features + header + empty line
142+
assert.strictEqual(response.split('\n').length, 8); // 5 valid Features + header + empty line
135143

136144
// Check that the header is present
137145
assert.ok(response.includes('Current'), 'Current column is missing');
@@ -145,6 +153,7 @@ describe('Lockfile', function () {
145153
assert.ok(response.includes('ghcr.io/devcontainers/features/github-cli'), 'github-cli Feature is missing');
146154
assert.ok(response.includes('ghcr.io/devcontainers/features/azure-cli'), 'azure-cli Feature is missing');
147155
assert.ok(response.includes('ghcr.io/codspace/versioning/foo'), 'foo Feature is missing');
156+
assert.ok(response.includes('ghcr.io/codspace/doesnotexist'), 'doesnotexist Feature is missing');
148157

149158
// Check that filtered Features are not present
150159
assert.ok(!response.includes('mylocalfeature'));

0 commit comments

Comments
 (0)