Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion docs/features/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ reportResults

## dev-container-features-test-lib

The `dev-container-features-test-lib` is convenience helper [defined in the CLI](https://github.com/devcontainers/cli/blob/1910ca41015c627b884ddd69ebc52d1e8cdd8cf0/src/spec-node/featuresCLI/utils.ts#L59) that adds several bash functions to organize test asserts. Note that using this libary **is not required**.
The `dev-container-features-test-lib` is convenience helper [defined in the CLI](https://github.com/devcontainers/cli/blob/1910ca41015c627b884ddd69ebc52d1e8cdd8cf0/src/spec-node/featuresCLI/utils.ts#L59) that adds several bash functions to organize test asserts. Note that using this library **is not required**.

#### `check <LABEL> <cmd> [args...]`
Description: Executes `cmd` and prints success/failed depending on exit code (0 === success) of `cmd`.
Expand Down
4 changes: 2 additions & 2 deletions src/spec-common/commonUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,8 @@ async function findLocalWindowsExecutable(command: string, cwd = process.cwd(),
}
}
// Not found in PATH. Bail out.
output.write(`findLocalWindowsExecutable: Exectuable '${command}' not found on PATH '${pathValue}'.`);
const err = new Error(`Exectuable '${command}' not found on PATH '${pathValue}'.`);
output.write(`findLocalWindowsExecutable: Executable '${command}' not found on PATH '${pathValue}'.`);
const err = new Error(`Executable '${command}' not found on PATH '${pathValue}'.`);
(err as any).code = 'ENOENT';
throw err;
}
Expand Down
2 changes: 1 addition & 1 deletion src/spec-configuration/containerCollectionsOCI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ export async function getManifest(params: CommonParams, url: string, ref: OCIRef
// Per the specification:
// https://github.com/opencontainers/distribution-spec/blob/v1.0.1/spec.md#pulling-manifests
// The registry server SHOULD return the canonical content digest in a header, but it's not required to.
// That is useful to have, so if the server doesn't provide it, recalculate it outselves.
// That is useful to have, so if the server doesn't provide it, recalculate it ourselves.
// Headers are always automatically downcased by node.
let contentDigest = headers['docker-content-digest'];
if (!contentDigest || expectedDigest) {
Expand Down
4 changes: 2 additions & 2 deletions src/spec-configuration/containerFeaturesConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export interface FeatureSet {

export interface FeaturesConfig {
featureSets: FeatureSet[];
dstFolder?: string; // set programatically
dstFolder?: string; // set programmatically
}

export interface GitHubApiReleaseInfo {
Expand Down Expand Up @@ -1029,7 +1029,7 @@ async function fetchFeatures(params: { extensionPath: string; cwd: string; outpu
if (authenticatedGithubTarballUri) {
tarballUris.push(authenticatedGithubTarballUri);
} else {
output.write('Failed to generate autenticated tarball URI for provided feature, despite a GitHub token present', LogLevel.Warning);
output.write('Failed to generate authenticated tarball URI for provided feature, despite a GitHub token present', LogLevel.Warning);
}
headers.Accept = 'Accept: application/octet-stream';
}
Expand Down
6 changes: 3 additions & 3 deletions src/spec-configuration/containerFeaturesOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface FNode {
// FeatureSet contains 'sourceInformation', useful for:
// Providing information on if Feature is an OCI Feature, Direct HTTPS Feature, or Local Feature.
// Additionally, contains 'ref' and 'manifestDigest' for OCI Features - useful for sorting.
// Property set programatically when discovering all the nodes in the graph.
// Property set programmatically when discovering all the nodes in the graph.
featureSet?: FeatureSet;

// Graph directed adjacency lists.
Expand Down Expand Up @@ -71,7 +71,7 @@ function satisfiesSoftDependency(params: CommonParams, node: FNode, softDep: FNo
let softDepSourceInfo = softDep.featureSet?.sourceInformation; // Mutable only for type-casting.

if (!nodeSourceInfo || !softDepSourceInfo) {
output.write(`Missing sourceInfo: satisifiesSoftDependency(${nodeSourceInfo?.userFeatureId}, ${softDepSourceInfo?.userFeatureId})`, LogLevel.Trace);
output.write(`Missing sourceInfo: satisfiesSoftDependency(${nodeSourceInfo?.userFeatureId}, ${softDepSourceInfo?.userFeatureId})`, LogLevel.Trace);
throw new Error('ERR: Failure resolving Features.');
}

Expand Down Expand Up @@ -624,7 +624,7 @@ export async function computeDependsOnInstallationOrder(
const round = worklist.filter(node =>
// If the node has no hard/soft dependencies, the node can always be installed.
(node.dependsOn.length === 0 && node.installsAfter.length === 0)
// OR, every hard-dependency (dependsOn) AND soft-dependency (installsAfter) has been satified in prior rounds
// OR, every hard-dependency (dependsOn) AND soft-dependency (installsAfter) has been satisfied in prior rounds
|| node.dependsOn.every(dep =>
installationOrder.some(installed => equals(params, installed, dep)))
&& node.installsAfter.every(dep =>
Expand Down
6 changes: 3 additions & 3 deletions src/spec-configuration/containerTemplatesConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ export interface Template {
description?: string;
documentationURL?: string;
licenseURL?: string;
type?: string; // Added programatically during packaging
fileCount?: number; // Added programatically during packaging
type?: string; // Added programmatically during packaging
fileCount?: number; // Added programmatically during packaging
featureIds?: string[];
options?: Record<string, TemplateOption>;
platforms?: string[];
publisher?: string;
keywords?: string[];
optionalPaths?: string[];
files: string[]; // Added programatically during packaging
files: string[]; // Added programmatically during packaging
}

export type TemplateOption = {
Expand Down
2 changes: 1 addition & 1 deletion src/spec-node/collectionCommonUtils/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function publishOptions(y: Argv, collectionType: string) {
return y
.options({
'registry': { type: 'string', alias: 'r', default: 'ghcr.io', description: 'Name of the OCI registry.' },
'namespace': { type: 'string', alias: 'n', require: true, description: `Unique indentifier for the collection of ${collectionType}s. Example: <owner>/<repo>` },
'namespace': { type: 'string', alias: 'n', require: true, description: `Unique identifier for the collection of ${collectionType}s. Example: <owner>/<repo>` },
'log-level': { choices: ['info' as 'info', 'debug' as 'debug', 'trace' as 'trace'], default: 'info' as 'info', description: 'Log level.' }
})
.positional('target', { type: 'string', default: '.', description: targetPositionalDescription(collectionType) })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function getSemanticTags(version: string, tags: string[], output: Log) {

semanticVersions = [];

// Adds semantic versions depending upon the existings (published) versions
// Adds semantic versions depending upon the existing (published) versions
// eg. 1.2.3 --> [1, 1.2, 1.2.3, latest]
updateSemanticTagsList(tags, version, `${parsedVersion.major}.x.x`, `${parsedVersion.major}`);
updateSemanticTagsList(tags, version, `${parsedVersion.major}.${parsedVersion.minor}.x`, `${parsedVersion.major}.${parsedVersion.minor}`);
Expand Down
4 changes: 2 additions & 2 deletions src/spec-node/dockerCompose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,11 @@ export async function buildAndExtendDockerCompose(configWithRaw: SubstitutedConf
const originalDockerfile = (await cliHost.readFile(resolvedDockerfilePath)).toString();
dockerfile = originalDockerfile;
if (target) {
// Explictly set build target for the dev container build features on that
// Explicitly set build target for the dev container build features on that
baseName = target;
} else {
// Use the last stage in the Dockerfile
// Find the last line that starts with "FROM" (possibly preceeded by white-space)
// Find the last line that starts with "FROM" (possibly preceded by white-space)
const { lastStageName, modifiedDockerfile } = ensureDockerfileHasFinalStageName(originalDockerfile, baseName);
baseName = lastStageName;
if (modifiedDockerfile) {
Expand Down
12 changes: 6 additions & 6 deletions src/spec-node/dockerfileUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,15 @@ function extractInstructions(stageStr: string) {
}

function getExpressionValue(option: string, isSet: boolean, word: string, value: string) {
const operations: Record<string, Function> = {
const operations: Record<string, Function> = {
'-': (isSet: boolean, word: string, value: string) => isSet ? value : word,
'+': (isSet: boolean, word: string, value: string) => isSet ? word : value,
};

return operations[option](isSet, word, value).replace(/^['"]|['"]$/g, ''); // remove quotes from start and end of the string
}

function replaceVariables(dockerfile: Dockerfile, buildArgs: Record<string, string>, baseImageEnv: Record<string, string>, globalBuildxPlatformArgs: Record<string, string> = {}, str: string, stage: { from?: From; instructions: Instruction[] }, beforeInstructionIndex: number) {
function replaceVariables(dockerfile: Dockerfile, buildArgs: Record<string, string>, baseImageEnv: Record<string, string>, globalBuildxPlatformArgs: Record<string, string> = {}, str: string, stage: { from?: From; instructions: Instruction[] }, beforeInstructionIndex: number) {
return [...str.matchAll(argumentExpression)]
.map(match => {
const variable = match.groups!.variable;
Expand Down Expand Up @@ -225,7 +225,7 @@ function findLastIndex<T>(array: T[], predicate: (value: T, index: number, obj:
// not expected to be called externally (exposed for testing)
export function ensureDockerfileHasFinalStageName(dockerfile: string, defaultLastStageName: string): { lastStageName: string; modifiedDockerfile: string | undefined } {

// Find the last line that starts with "FROM" (possibly preceeded by white-space)
// Find the last line that starts with "FROM" (possibly preceded by white-space)
const fromLines = [...dockerfile.matchAll(findFromLines)];
if (fromLines.length === 0) {
throw new Error('Error parsing Dockerfile: Dockerfile contains no FROM instructions');
Expand Down Expand Up @@ -273,9 +273,9 @@ export function supportsBuildContexts(dockerfile: Dockerfile) {
}

/**
* Convert mount command' arguments to string
* @param mount
* @returns mount command string
* Convert mount command' arguments to string
* @param mount
* @returns mount command string
*/
export function generateMountCommand(mount: Mount | string): string[] {
const command: string = '--mount';
Expand Down
2 changes: 1 addition & 1 deletion src/spec-node/featuresCLI/generateDocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function featuresGenerateDocsOptions(y: Argv) {
.options({
'project-folder': { type: 'string', alias: 'p', default: '.', description: 'Path to folder containing \'src\' and \'test\' sub-folders. This is likely the git root of the project.' },
'registry': { type: 'string', alias: 'r', default: 'ghcr.io', description: 'Name of the OCI registry.' },
'namespace': { type: 'string', alias: 'n', require: true, description: `Unique indentifier for the collection of features. Example: <owner>/<repo>` },
'namespace': { type: 'string', alias: 'n', require: true, description: `Unique identifier for the collection of features. Example: <owner>/<repo>` },
'github-owner': { type: 'string', default: '', description: `GitHub owner for docs.` },
'github-repo': { type: 'string', default: '', description: `GitHub repo for docs.` },
'log-level': { choices: ['info' as 'info', 'debug' as 'debug', 'trace' as 'trace'], default: 'info' as 'info', description: 'Log level.' }
Expand Down
6 changes: 3 additions & 3 deletions src/spec-node/singleContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,11 @@ async function buildAndExtendImage(buildParams: DockerResolverParameters, config
const originalDockerfile = dockerfile;
let baseName = 'dev_container_auto_added_stage_label';
if (config.build?.target) {
// Explictly set build target for the dev container build features on that
// Explicitly set build target for the dev container build features on that
baseName = config.build.target;
} else {
// Use the last stage in the Dockerfile
// Find the last line that starts with "FROM" (possibly preceeded by white-space)
// Find the last line that starts with "FROM" (possibly preceded by white-space)
const { lastStageName, modifiedDockerfile } = ensureDockerfileHasFinalStageName(dockerfile, baseName);
baseName = lastStageName;
if (modifiedDockerfile) {
Expand Down Expand Up @@ -189,7 +189,7 @@ async function buildAndExtendImage(buildParams: DockerResolverParameters, config
if (buildParams.buildxPush) {
args.push('--push');
} else {
if (buildParams.buildxOutput) {
if (buildParams.buildxOutput) {
args.push('--output', buildParams.buildxOutput);
} else {
args.push('--load'); // (short for --output=docker, i.e. load into normal 'docker images' collection)
Expand Down
6 changes: 3 additions & 3 deletions src/spec-node/typings/node-pty.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ declare module 'node-pty' {
* escaped properly.
* @param options The options of the terminal.
* @see CommandLineToArgvW https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
* @see Parsing C++ Comamnd-Line Arguments https://msdn.microsoft.com/en-us/library/17w5ykft.aspx
* @see Parsing C++Command-Line Arguments https://msdn.microsoft.com/en-us/library/17w5ykft.aspx
* @see GetCommandLine https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156.aspx
*/
export function spawn(file: string, args: string[] | string, options: IPtyForkOptions | IWindowsPtyForkOptions): IPty;
Expand All @@ -25,7 +25,7 @@ declare module 'node-pty' {
name?: string;

/**
* Number of intial cols of the pty.
* Number of initial cols of the pty.
*/
cols?: number;

Expand Down Expand Up @@ -199,4 +199,4 @@ declare module 'node-pty' {
export interface IEvent<T> {
(listener: (e: T) => any): IDisposable;
}
}
}
2 changes: 1 addition & 1 deletion src/test/cli.build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ describe('Dev Containers CLI', function () {
const nonCachedImageWithoutBaseImageLayers = nonCachedImageLayers.slice(baseImageLayers.length);

assert.deepEqual(originalImageWithoutBaseImageLayers, cachedImageWithoutBaseImageLayers, 'because they are the same image built sequentially therefore the second should have used caching');
assert.equal(haveCommonEntries(cachedImageWithoutBaseImageLayers, nonCachedImageWithoutBaseImageLayers), false, 'because we passed the --no-cache argument which disables the use of the cache, therefore the non-base image layers should have nothin in common');
assert.equal(haveCommonEntries(cachedImageWithoutBaseImageLayers, nonCachedImageWithoutBaseImageLayers), false, 'because we passed the --no-cache argument which disables the use of the cache, therefore the non-base image layers should have nothing in common');
});

it('should fail with "not found" error when config is not found', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ describe('Feature Dependencies', function () {

assert.deepStrictEqual(actual.length, 6);

// Despite having different options, these two Features should have the same canconical ID (same exact contents, just run with a different set of options)
// Despite having different options, these two Features should have the same canonical ID (same exact contents, just run with a different set of options)
const firstA = actual[2];
const secondA = actual[3];
assert.strictEqual(firstA.canonicalId, secondA.canonicalId);
Expand Down
4 changes: 2 additions & 2 deletions src/test/container-features/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,13 @@ describe('Dev Container Features E2E (local-path)', function () {
beforeEach(async () => containerId = (await devContainerUp(cli, testFolder, { 'logLevel': 'trace' })).containerId);
afterEach(async () => await devContainerDown({ containerId }));

it('should exec the color commmand', async () => {
it('should exec the color command', async () => {
const res = await shellExec(`${cli} exec --workspace-folder ${testFolder} color`);
assert.isNull(res.error);
assert.match(res.stdout, /my favorite color is gold/);
});

it('should exec the helloworld commmand', async () => {
it('should exec the helloworld command', async () => {
const res = await shellExec(`${cli} exec --workspace-folder ${testFolder} hello`);
assert.isNull(res.error);
assert.match(res.stdout, /Hello there, vscode!!!!/);
Expand Down
6 changes: 3 additions & 3 deletions src/test/container-features/lifecycleHooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('Feature lifecycle hooks', function () {
await shellExec(`rm -f ${testFolder}/test-secrets-temp.json`, undefined, undefined, true);
});

it('secrets should be availale to the lifecycle hooks during up command', async () => {
it('secrets should be available to the lifecycle hooks during up command', async () => {
{
const res = await shellExec(`${cli} exec --workspace-folder ${testFolder} ls -altr`);
assert.strictEqual(res.error, null);
Expand Down Expand Up @@ -215,7 +215,7 @@ describe('Feature lifecycle hooks', function () {
await shellExec(`rm -f ${testFolder}/test-secrets-temp.json`, undefined, undefined, true);
});

it('secrets should be availale to the lifecycle hooks during run-user-commands command', async () => {
it('secrets should be available to the lifecycle hooks during run-user-commands command', async () => {
{
const expectedTestMarkerFiles = [
'0.panda.onCreateCommand.testMarker',
Expand Down Expand Up @@ -459,4 +459,4 @@ describe('Feature lifecycle hooks', function () {
});
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface TestPlan {
testFeatureId: string;
testCommand?: string;
testCommandResult?: RegExp;
// Optionally tell the test to set up with a specfic auth strategy.
// Optionally tell the test to set up with a specific auth strategy.
// If not set, the test will run with anonymous.
// NOTE: These will be skipped unless the environment has the relevant 'authStrategyKey' set in the environment.
// This data is specific to each strategy and parsed about below accordingly.
Expand Down Expand Up @@ -170,4 +170,4 @@ describe('Registry Compatibility', function () {
});
});

});
});
4 changes: 2 additions & 2 deletions src/test/container-templates/templatesCLICommands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ describe('template metadata', async function () {
await shellExec(`npm --prefix ${tmp} install devcontainers-cli-${pkg.version}.tgz`);
});

it('successfully fetches metdata off a published Template', async function () {
it('successfully fetches metadata off a published Template', async function () {
let success = false;
let result: ExecResult | undefined = undefined;
try {
Expand All @@ -326,4 +326,4 @@ describe('template metadata', async function () {
assert.strictEqual('Simple test', json.description);

});
});
});