Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/spec-node/containerFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const getSafeId = (str: string) => str
.replace(/^[\d_]+/g, '_')
.toUpperCase();

Comment thread
prathameshzarkar9 marked this conversation as resolved.
export async function extendImage(params: DockerResolverParameters, config: SubstitutedConfig<DevContainerConfig>, imageName: string, additionalImageNames: string[], additionalFeatures: Record<string, string | boolean | Record<string, string | boolean>>, canAddLabelsToContainer: boolean) {
export async function extendImage(params: DockerResolverParameters, config: SubstitutedConfig<DevContainerConfig>, imageName: string, additionalImageNames: string[], imageLabels: string[], additionalFeatures: Record<string, string | boolean | Record<string, string | boolean>>, canAddLabelsToContainer: boolean) {
Comment thread
prathameshzarkar9 marked this conversation as resolved.
Outdated
const { common } = params;
const { cliHost, output } = common;

Expand Down Expand Up @@ -113,6 +113,7 @@ export async function extendImage(params: DockerResolverParameters, config: Subs
'--target', featureBuildInfo.overrideTarget,
'-f', dockerfilePath,
...additionalImageNames.length > 0 ? additionalImageNames.map(name => ['-t', name]).flat() : ['-t', updatedImageName],
...imageLabels.length > 0 ? imageLabels.map(label => ['--label', label]).flat() : ['--label', imageLabels.toString()],
Comment thread
prathameshzarkar9 marked this conversation as resolved.
Outdated
emptyTempDir
);

Expand Down
3 changes: 3 additions & 0 deletions src/spec-node/devContainers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export interface ProvisionOptions {
omitLoggerHeader?: boolean | undefined;
buildxPlatform: string | undefined;
buildxPush: boolean;
buildxLabel: string | undefined;
buildxOutput: string | undefined;
buildxCacheTo: string | undefined;
additionalFeatures?: Record<string, string | boolean | Record<string, string | boolean>>;
Expand Down Expand Up @@ -146,6 +147,7 @@ export async function createDockerParams(options: ProvisionOptions, disposables:
secretsP,
buildxPlatform: options.buildxPlatform,
buildxPush: options.buildxPush,
buildxLabel: options.buildxLabel,
Comment thread
prathameshzarkar9 marked this conversation as resolved.
Outdated
buildxOutput: options.buildxOutput,
buildxCacheTo: options.buildxCacheTo,
skipFeatureAutoMapping: options.skipFeatureAutoMapping,
Expand Down Expand Up @@ -227,6 +229,7 @@ export async function createDockerParams(options: ProvisionOptions, disposables:
experimentalFrozenLockfile,
buildxPlatform: common.buildxPlatform,
buildxPush: common.buildxPush,
buildxLabel: options.buildxLabel,
buildxOutput: common.buildxOutput,
buildxCacheTo: common.buildxCacheTo,
platformInfo
Expand Down
14 changes: 12 additions & 2 deletions src/spec-node/devContainersSpecCLI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ async function provision({
useBuildKit: buildkit,
buildxPlatform: undefined,
buildxPush: false,
buildxLabel: undefined,
buildxOutput: undefined,
buildxCacheTo: addCacheTo,
additionalFeatures,
Expand Down Expand Up @@ -431,6 +432,7 @@ async function doSetUp({
useBuildKit: 'auto',
buildxPlatform: undefined,
buildxPush: false,
buildxLabel: undefined,
buildxOutput: undefined,
buildxCacheTo: undefined,
skipFeatureAutoMapping: false,
Expand Down Expand Up @@ -508,6 +510,7 @@ function buildOptions(y: Argv) {
'buildkit': { choices: ['auto' as 'auto', 'never' as 'never'], default: 'auto' as 'auto', description: 'Control whether BuildKit should be used' },
'platform': { type: 'string', description: 'Set target platforms.' },
'push': { type: 'boolean', default: false, description: 'Push to a container registry.' },
'label': { type: 'string', description: 'Provide key and value for the metadata of the container. (<key1>=<value1> <key2>=<value2> )' },
Comment thread
prathameshzarkar9 marked this conversation as resolved.
Outdated
'output': { type: 'string', description: 'Overrides the default behavior to load built images into the local docker registry. Valid options are the same ones provided to the --output option of docker buildx build.' },
'additional-features': { type: 'string', description: 'Additional features to apply to the dev container (JSON as per "features" section in devcontainer.json)' },
'skip-feature-auto-mapping': { type: 'boolean', default: false, hidden: true, description: 'Temporary option for testing.' },
Expand Down Expand Up @@ -546,6 +549,7 @@ async function doBuild({
'buildkit': buildkit,
'platform': buildxPlatform,
'push': buildxPush,
'label': buildxLabel,
'output': buildxOutput,
'cache-to': buildxCacheTo,
'additional-features': additionalFeaturesJson,
Expand Down Expand Up @@ -593,6 +597,7 @@ async function doBuild({
useBuildKit: buildkit,
buildxPlatform,
buildxPush,
buildxLabel,
buildxOutput,
buildxCacheTo,
skipFeatureAutoMapping,
Expand Down Expand Up @@ -629,10 +634,13 @@ async function doBuild({
// Support multiple use of `--image-name`
const imageNames = (argImageName && (Array.isArray(argImageName) ? argImageName : [argImageName]) as string[]) || undefined;

// Support multiple use of `--label`
const imageLabels = (buildxLabel && (Array.isArray(buildxLabel) ? buildxLabel : [buildxLabel]) as string[]) || undefined;

if (isDockerFileConfig(config)) {

// Build the base image and extend with features etc.
let { updatedImageName } = await buildNamedImageAndExtend(params, configWithRaw as SubstitutedConfig<DevContainerFromDockerfileConfig>, additionalFeatures, false, imageNames);
let { updatedImageName } = await buildNamedImageAndExtend(params, configWithRaw as SubstitutedConfig<DevContainerFromDockerfileConfig>, additionalFeatures, false, imageNames, imageLabels);

if (imageNames) {
imageNameResult = imageNames;
Expand Down Expand Up @@ -695,7 +703,7 @@ async function doBuild({
}

await inspectDockerImage(params, config.image, true);
const { updatedImageName } = await extendImage(params, configWithRaw, config.image, imageNames || [], additionalFeatures, false);
const { updatedImageName } = await extendImage(params, configWithRaw, config.image, imageNames || [], imageLabels || [], additionalFeatures, false);

if (imageNames) {
imageNameResult = imageNames;
Expand Down Expand Up @@ -858,6 +866,7 @@ async function doRunUserCommands({
useBuildKit: 'auto',
buildxPlatform: undefined,
buildxPush: false,
buildxLabel: undefined,
buildxOutput: undefined,
buildxCacheTo: undefined,
skipFeatureAutoMapping,
Expand Down Expand Up @@ -1306,6 +1315,7 @@ export async function doExec({
omitLoggerHeader: true,
buildxPlatform: undefined,
buildxPush: false,
buildxLabel: undefined,
buildxCacheTo: undefined,
skipFeatureAutoMapping,
buildxOutput: undefined,
Expand Down
5 changes: 3 additions & 2 deletions src/spec-node/singleContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,16 @@ async function setupContainer(container: ContainerDetails, params: DockerResolve
function getDefaultName(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig, params: DockerResolverParameters) {
return 'image' in config && config.image ? config.image : getFolderImageName(params.common);
}
export async function buildNamedImageAndExtend(params: DockerResolverParameters, configWithRaw: SubstitutedConfig<DevContainerFromDockerfileConfig | DevContainerFromImageConfig>, additionalFeatures: Record<string, string | boolean | Record<string, string | boolean>>, canAddLabelsToContainer: boolean, argImageNames?: string[]): Promise<{ updatedImageName: string[]; imageMetadata: SubstitutedConfig<ImageMetadataEntry[]>; imageDetails: () => Promise<ImageDetails>; labels?: Record<string, string> }> {
export async function buildNamedImageAndExtend(params: DockerResolverParameters, configWithRaw: SubstitutedConfig<DevContainerFromDockerfileConfig | DevContainerFromImageConfig>, additionalFeatures: Record<string, string | boolean | Record<string, string | boolean>>, canAddLabelsToContainer: boolean, argImageNames?: string[], imageLabels?: string[]): Promise<{ updatedImageName: string[]; imageMetadata: SubstitutedConfig<ImageMetadataEntry[]>; imageDetails: () => Promise<ImageDetails>; labels?: Record<string, string> }> {
Comment thread
prathameshzarkar9 marked this conversation as resolved.
Outdated
const { config } = configWithRaw;
const imageNames = argImageNames ?? [getDefaultName(config, params)];
const imagelabel = imageLabels ?? [getDefaultName(config, params)];
Comment thread
prathameshzarkar9 marked this conversation as resolved.
Outdated
params.common.progress(ResolverProgress.BuildingImage);
if (isDockerFileConfig(config)) {
return await buildAndExtendImage(params, configWithRaw as SubstitutedConfig<DevContainerFromDockerfileConfig>, imageNames, params.buildNoCache ?? false, additionalFeatures);
}
// image-based dev container - extend
return await extendImage(params, configWithRaw, imageNames[0], argImageNames || [], additionalFeatures, canAddLabelsToContainer);
return await extendImage(params, configWithRaw, imageNames[0], argImageNames || [], imagelabel || [], additionalFeatures, canAddLabelsToContainer);
}

async function buildAndExtendImage(buildParams: DockerResolverParameters, configWithRaw: SubstitutedConfig<DevContainerFromDockerfileConfig>, baseImageNames: string[], noCache: boolean, additionalFeatures: Record<string, string | boolean | Record<string, string | boolean>>) {
Expand Down
1 change: 1 addition & 0 deletions src/spec-node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export interface DockerResolverParameters {
experimentalFrozenLockfile?: boolean;
buildxPlatform: string | undefined;
buildxPush: boolean;
buildxLabel: string | undefined;
Comment thread
prathameshzarkar9 marked this conversation as resolved.
Outdated
buildxOutput: string | undefined;
buildxCacheTo: string | undefined;
platformInfo: PlatformInfo;
Expand Down
9 changes: 9 additions & 0 deletions src/test/cli.build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ describe('Dev Containers CLI', function () {

describe('Command build', () => {

it('should build successfully with valid image metadata --label property', async () => {
const testFolder = `${__dirname}/configs/example`;
const response = await shellExec(`${cli} build --workspace-folder ${testFolder} --label 'name=label-test' --label 'type=multiple-labels'`);
const res = JSON.parse(response.stdout);
assert.equal(res.outcome, 'success');
const labels = await shellExec(`docker inspect --format '{{json .Config.Labels}}' ${res.imageName} | jq`);
assert.match(labels.stdout.toString(), /\"name\": \"label-test\"/);
});

it('should fail to build with correct error message for local feature', async () => {
const testFolder = `${__dirname}/configs/image-with-local-feature`;
try {
Expand Down