Skip to content

Commit 59516b3

Browse files
committed
0.11.0 & --skip-feature-auto-mapping
1 parent 1f35c44 commit 59516b3

File tree

8 files changed

+36
-9
lines changed

8 files changed

+36
-9
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Notable changes.
44

55
## August 2022
66

7+
### [0.11.0]
8+
9+
- WIP on features v2:
10+
- Auto map old feature ids to OCI features. (https://github.com/devcontainers/cli/pull/100)
11+
712
### [0.10.0]
813

914
- Implement optional default values in localEnv/containerEnv expansions. (https://github.com/devcontainers/cli/issues/50)

package.json

+1-1
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.10.0",
4+
"version": "0.11.0",
55
"bin": {
66
"devcontainer": "devcontainer.js"
77
},

src/spec-common/injectHeadless.ts

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export interface ResolverParameters {
5858
remoteEnv: Record<string, string>;
5959
buildxPlatform: string | undefined;
6060
buildxPush: boolean;
61+
skipFeatureAutoMapping: boolean;
6162
}
6263

6364
export interface PostCreate {

src/spec-configuration/containerFeaturesConfiguration.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ function updateFromOldProperties<T extends { features: (Feature & { extensions?:
383383

384384
// Generate a base featuresConfig object with the set of locally-cached features,
385385
// as well as downloading and merging in remote feature definitions.
386-
export async function generateFeaturesConfig(params: { extensionPath: string; cwd: string; output: Log; env: NodeJS.ProcessEnv }, dstFolder: string, config: DevContainerConfig, getLocalFeaturesFolder: (d: string) => string) {
386+
export async function generateFeaturesConfig(params: { extensionPath: string; cwd: string; output: Log; env: NodeJS.ProcessEnv; skipFeatureAutoMapping: boolean }, dstFolder: string, config: DevContainerConfig, getLocalFeaturesFolder: (d: string) => string) {
387387
const { output } = params;
388388

389389
const workspaceCwd = params.cwd;
@@ -412,7 +412,7 @@ export async function generateFeaturesConfig(params: { extensionPath: string; cw
412412

413413
// Read features and get the type.
414414
output.write('--- Processing User Features ----', LogLevel.Trace);
415-
featuresConfig = await processUserFeatures(params.output, params.env, workspaceCwd, userFeatures, featuresConfig);
415+
featuresConfig = await processUserFeatures(params.output, params.env, workspaceCwd, userFeatures, featuresConfig, params.skipFeatureAutoMapping);
416416
output.write(JSON.stringify(featuresConfig, null, 4), LogLevel.Trace);
417417

418418
const ociCacheDir = await prepareOCICache(dstFolder);
@@ -461,9 +461,9 @@ function featuresToArray(config: DevContainerConfig): DevContainerFeature[] | un
461461

462462
// Process features contained in devcontainer.json
463463
// Creates one feature set per feature to aid in support of the previous structure.
464-
async function processUserFeatures(output: Log, env: NodeJS.ProcessEnv, workspaceCwd: string, userFeatures: DevContainerFeature[], featuresConfig: FeaturesConfig): Promise<FeaturesConfig> {
464+
async function processUserFeatures(output: Log, env: NodeJS.ProcessEnv, workspaceCwd: string, userFeatures: DevContainerFeature[], featuresConfig: FeaturesConfig, skipFeatureAutoMapping: boolean): Promise<FeaturesConfig> {
465465
for (const userFeature of userFeatures) {
466-
const newFeatureSet = await processFeatureIdentifier(output, env, workspaceCwd, userFeature);
466+
const newFeatureSet = await processFeatureIdentifier(output, env, workspaceCwd, userFeature, skipFeatureAutoMapping);
467467
if (!newFeatureSet) {
468468
throw new Error(`Failed to process feature ${userFeature.id}`);
469469
}
@@ -547,11 +547,13 @@ export function getBackwardCompatibleFeatureId(id: string) {
547547

548548
// Strictly processes the user provided feature identifier to determine sourceInformation type.
549549
// Returns a featureSet per feature.
550-
export async function processFeatureIdentifier(output: Log, env: NodeJS.ProcessEnv, workspaceCwd: string, userFeature: DevContainerFeature): Promise<FeatureSet | undefined> {
550+
export async function processFeatureIdentifier(output: Log, env: NodeJS.ProcessEnv, workspaceCwd: string, userFeature: DevContainerFeature, skipFeatureAutoMapping?: boolean): Promise<FeatureSet | undefined> {
551551
output.write(`* Processing feature: ${userFeature.id}`);
552552

553553
// Adding backward compatibility
554-
userFeature.id = getBackwardCompatibleFeatureId(userFeature.id);
554+
if (!skipFeatureAutoMapping) {
555+
userFeature.id = getBackwardCompatibleFeatureId(userFeature.id);
556+
}
555557

556558
const { type, manifest } = await getFeatureIdType(output, env, userFeature.id);
557559

src/spec-node/devContainers.ts

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export interface ProvisionOptions {
4949
omitLoggerHeader?: boolean | undefined;
5050
buildxPlatform: string | undefined;
5151
buildxPush: boolean;
52+
skipFeatureAutoMapping: boolean;
5253
}
5354

5455
export async function launch(options: ProvisionOptions, disposables: (() => Promise<unknown> | undefined)[]) {
@@ -119,6 +120,7 @@ export async function createDockerParams(options: ProvisionOptions, disposables:
119120
remoteEnv,
120121
buildxPlatform: options.buildxPlatform,
121122
buildxPush: options.buildxPush,
123+
skipFeatureAutoMapping: options.skipFeatureAutoMapping,
122124
};
123125

124126
const dockerPath = options.dockerPath || 'docker';

src/spec-node/devContainersSpecCLI.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ function provisionOptions(y: Argv) {
9494
'remote-env': { type: 'string', description: 'Remote environment variables of the format name=value. These will be added when executing the user commands.' },
9595
'cache-from': { type: 'string', description: 'Additional image to use as potential layer cache during image building' },
9696
'buildkit': { choices: ['auto' as 'auto', 'never' as 'never'], default: 'auto' as 'auto', description: 'Control whether BuildKit should be used' },
97+
'skip-feature-auto-mapping': { type: 'boolean', default: false, hidden: true, description: 'Temporary option for testing.' },
9798
})
9899
.check(argv => {
99100
const idLabels = (argv['id-label'] && (Array.isArray(argv['id-label']) ? argv['id-label'] : [argv['id-label']])) as string[] | undefined;
@@ -152,6 +153,7 @@ async function provision({
152153
'remote-env': addRemoteEnv,
153154
'cache-from': addCacheFrom,
154155
'buildkit': buildkit,
156+
'skip-feature-auto-mapping': skipFeatureAutoMapping,
155157
}: ProvisionArgs) {
156158

157159
const workspaceFolder = workspaceFolderArg ? path.resolve(process.cwd(), workspaceFolderArg) : undefined;
@@ -195,6 +197,7 @@ async function provision({
195197
useBuildKit: buildkit,
196198
buildxPlatform: undefined,
197199
buildxPush: false,
200+
skipFeatureAutoMapping,
198201
};
199202

200203
const result = await doProvision(options);
@@ -254,6 +257,7 @@ function buildOptions(y: Argv) {
254257
'buildkit': { choices: ['auto' as 'auto', 'never' as 'never'], default: 'auto' as 'auto', description: 'Control whether BuildKit should be used' },
255258
'platform': { type: 'string', description: 'Set target platforms.' },
256259
'push': { type: 'boolean', default: false, description: 'Push to a container registry.' },
260+
'skip-feature-auto-mapping': { type: 'boolean', default: false, hidden: true, description: 'Temporary option for testing.' },
257261
});
258262
}
259263

@@ -284,6 +288,7 @@ async function doBuild({
284288
'buildkit': buildkit,
285289
'platform': buildxPlatform,
286290
'push': buildxPush,
291+
'skip-feature-auto-mapping': skipFeatureAutoMapping,
287292
}: BuildArgs) {
288293
const disposables: (() => Promise<unknown> | undefined)[] = [];
289294
const dispose = async () => {
@@ -323,6 +328,7 @@ async function doBuild({
323328
useBuildKit: buildkit,
324329
buildxPlatform,
325330
buildxPush,
331+
skipFeatureAutoMapping,
326332
}, disposables);
327333

328334
const { common, dockerCLI, dockerComposeCLI } = params;
@@ -453,6 +459,7 @@ function runUserCommandsOptions(y: Argv) {
453459
prebuild: { type: 'boolean', default: false, description: 'Stop after onCreateCommand and updateContentCommand, rerunning updateContentCommand if it has run before.' },
454460
'stop-for-personalization': { type: 'boolean', default: false, description: 'Stop for personalization.' },
455461
'remote-env': { type: 'string', description: 'Remote environment variables of the format name=value. These will be added when executing the user commands.' },
462+
'skip-feature-auto-mapping': { type: 'boolean', default: false, hidden: true, description: 'Temporary option for testing.' },
456463
})
457464
.check(argv => {
458465
const idLabels = (argv['id-label'] && (Array.isArray(argv['id-label']) ? argv['id-label'] : [argv['id-label']])) as string[] | undefined;
@@ -501,6 +508,7 @@ async function doRunUserCommands({
501508
prebuild,
502509
'stop-for-personalization': stopForPersonalization,
503510
'remote-env': addRemoteEnv,
511+
'skip-feature-auto-mapping': skipFeatureAutoMapping,
504512
}: RunUserCommandsArgs) {
505513
const disposables: (() => Promise<unknown> | undefined)[] = [];
506514
const dispose = async () => {
@@ -541,6 +549,7 @@ async function doRunUserCommands({
541549
useBuildKit: 'auto',
542550
buildxPlatform: undefined,
543551
buildxPush: false,
552+
skipFeatureAutoMapping,
544553
}, disposables);
545554

546555
const { common } = params;
@@ -599,6 +608,7 @@ function readConfigurationOptions(y: Argv) {
599608
'terminal-columns': { type: 'number', implies: ['terminal-rows'], description: 'Number of rows to render the output for. This is required for some of the subprocesses to correctly render their output.' },
600609
'terminal-rows': { type: 'number', implies: ['terminal-columns'], description: 'Number of columns to render the output for. This is required for some of the subprocesses to correctly render their output.' },
601610
'include-features-configuration': { type: 'boolean', default: false, description: 'Include features configuration.' },
611+
'skip-feature-auto-mapping': { type: 'boolean', default: false, hidden: true, description: 'Temporary option for testing.' },
602612
});
603613
}
604614

@@ -619,6 +629,7 @@ async function readConfiguration({
619629
'terminal-rows': terminalRows,
620630
'terminal-columns': terminalColumns,
621631
'include-features-configuration': includeFeaturesConfig,
632+
'skip-feature-auto-mapping': skipFeatureAutoMapping,
622633
}: ReadConfigurationArgs) {
623634
const disposables: (() => Promise<unknown> | undefined)[] = [];
624635
const dispose = async () => {
@@ -650,7 +661,7 @@ async function readConfiguration({
650661
if (!configs) {
651662
throw new ContainerError({ description: `Dev container config (${uriToFsPath(configFile || getDefaultDevContainerConfigPath(cliHost, workspace!.configFolderPath), cliHost.platform)}) not found.` });
652663
}
653-
const featuresConfiguration = includeFeaturesConfig ? await generateFeaturesConfig({ extensionPath, cwd, output, env: cliHost.env }, (await createFeaturesTempFolder({ cliHost, package: pkg })), configs.config, getContainerFeaturesFolder) : undefined;
664+
const featuresConfiguration = includeFeaturesConfig ? await generateFeaturesConfig({ extensionPath, cwd, output, env: cliHost.env, skipFeatureAutoMapping }, (await createFeaturesTempFolder({ cliHost, package: pkg })), configs.config, getContainerFeaturesFolder) : undefined;
654665
await new Promise<void>((resolve, reject) => {
655666
process.stdout.write(JSON.stringify({
656667
configuration: configs.config,
@@ -690,6 +701,7 @@ function execOptions(y: Argv) {
690701
'terminal-rows': { type: 'number', implies: ['terminal-columns'], description: 'Number of columns to render the output for. This is required for some of the subprocesses to correctly render their output.' },
691702
'default-user-env-probe': { choices: ['none' as 'none', 'loginInteractiveShell' as 'loginInteractiveShell', 'interactiveShell' as 'interactiveShell', 'loginShell' as 'loginShell'], default: defaultDefaultUserEnvProbe, description: 'Default value for the devcontainer.json\'s "userEnvProbe".' },
692703
'remote-env': { type: 'string', description: 'Remote environment variables of the format name=value. These will be added when executing the user commands.' },
704+
'skip-feature-auto-mapping': { type: 'boolean', default: false, hidden: true, description: 'Temporary option for testing.' },
693705
})
694706
.positional('cmd', {
695707
type: 'string',
@@ -746,6 +758,7 @@ export async function doExec({
746758
'terminal-columns': terminalColumns,
747759
'default-user-env-probe': defaultUserEnvProbe,
748760
'remote-env': addRemoteEnv,
761+
'skip-feature-auto-mapping': skipFeatureAutoMapping,
749762
_: restArgs,
750763
}: ExecArgs & { _?: string[] }) {
751764
const disposables: (() => Promise<unknown> | undefined)[] = [];
@@ -788,6 +801,7 @@ export async function doExec({
788801
omitLoggerHeader: true,
789802
buildxPlatform: undefined,
790803
buildxPush: false,
804+
skipFeatureAutoMapping,
791805
}, disposables);
792806

793807
const { common } = params;

src/spec-node/featuresCLI/testCommandImpl.ts

+3
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ async function launchProject(params: DockerResolverParameters, workspaceFolder:
309309
`devcontainer.local_folder=${workspaceFolder}`
310310
],
311311
remoteEnv: common.remoteEnv,
312+
skipFeatureAutoMapping: common.skipFeatureAutoMapping,
312313
log: text => quiet ? null : process.stderr.write(text),
313314
};
314315

@@ -357,6 +358,7 @@ async function exec(_params: DockerResolverParameters, cmd: string, args: string
357358
const execArgs = {
358359
...staticExecParams,
359360
'workspace-folder': workspaceFolder,
361+
'skip-feature-auto-mapping': false,
360362
cmd,
361363
args,
362364
_: [
@@ -400,5 +402,6 @@ async function generateDockerParams(workspaceFolder: string, args: FeaturesTestC
400402
useBuildKit: 'auto',
401403
buildxPlatform: undefined,
402404
buildxPush: false,
405+
skipFeatureAutoMapping: false,
403406
}, disposables);
404407
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ describe('validate generateFeaturesConfig()', function () {
1414

1515
// Setup
1616
const env = { 'SOME_KEY': 'SOME_VAL' };
17-
const params = { extensionPath: '', cwd: '', output, env, persistedFolder: '' };
17+
const params = { extensionPath: '', cwd: '', output, env, persistedFolder: '', skipFeatureAutoMapping: false };
1818

1919
// Mocha executes with the root of the project as the cwd.
2020
const localFeaturesFolder = (_: string) => {

0 commit comments

Comments
 (0)