Dev Container CLI

repository·main·Indexed 25 days ago

https://github.com/devcontainers/cli

A tool for creating, building, and managing development containers using a devcontainer.json configuration. It enables reproducible development environments for local development, CI/CD, and testing. Key capabilities include building container images, spinning up containers with 'up', executing commands via 'exec', and testing Dev Container Features.

Tokens
9.9K
Snippets
17
Records
72
Agent score
84%

What's inside devcontainers-cli

  1. Set up a local development environment for Dev Containers CLI

    main

    To develop on the Dev Containers CLI locally, ensure you have the following prerequisites installed:

    • Node.js >= 20
    • Docker (required for integration tests)
    • Git
    • yarn

    Installation Steps

    1. Fork and clone the repository:
    git clone https://github.com/<your-username>/cli.git
    cd cli
    1. Install dependencies:
    yarn install
    1. Cross-architecture emulation (Linux/Windows only): If you are on a non-macOS host and need to run tests for different architectures (e.g., linux/arm64 on x64), register QEMU emulators:
    docker run --privileged --rm tonistiigi/binfmt --install all

    Note: On macOS with Docker Desktop, this step is not required.

    Podman Support (Optional)

    If you wish to run Podman-specific tests, install Podman. The CLI supports both Docker and Podman. If Podman is not installed, the cli.podman.test.ts tests will fail with spawn podman ENOENT, which is expected behavior.

    git clone https://github.com/<your-username>/cli.git
    cd cli
    yarn install
    docker run --privileged --rm tonistiigi/binfmt --install all
  2. Provide additional build files for scenarios

    main

    You can provide extra files (like a Dockerfile or lifecycle scripts) for a specific scenario by creating a directory named after the scenario inside test/<FEATURE>/. The contents of this directory are copied into the hidden .devcontainer folder used during the build.

    Example Structure: If you have a scenario named frowning_with_a_dockerfile:

    └── test
        └── smile
            ├── frowning_with_a_dockerfile  <-- Folder name matches scenario
            │   └── Dockerfile              <-- Copied to .devcontainer/
            └── frowning_with_a_dockerfile.sh
  3. Install the Dev Container CLI via install script

    main

    You can install the CLI using a standalone script that downloads a bundled Node.js runtime. This method does not require a pre-installed Node.js environment. It is supported on Linux and macOS (x64 and arm64).

    To install, run the curl script and then add the installation directory to your PATH.

  4. Install the Dev Container CLI

    main

    To use the Dev Container CLI, you must first install Node.js and its build dependencies.

    Prerequisites:

    1. Node.js 16+: Install via a manager like nvm.
    2. node-gyp dependencies:
      • Linux/WSL2: sudo apt-get update && sudo apt-get install python3-minimal gcc g++ make (on Ubuntu/Debian).
      • macOS: Install XCode Command Line Tools.
    3. OpenSSH: Ensure an OpenSSH compliant ssh command is in your PATH (required for SSH-based examples).

    Installation Command: Install the latest version globally using npm:

    npm install -g @devcontainers/cli
  5. Run duplicate-style idempotency tests

    main

    Duplicate-style tests verify that a Feature can be installed multiple times with different options without causing conflicts. If a Feature contains a duplicate.sh script, the CLI will automatically generate a test case installing that Feature twice.

    During these tests, the options used for the distinct installations are passed into the duplicate.sh script as environment variables. For example, if a Feature has a version option, the script can access ${VERSION} (for the randomized installation) and ${VERSION__DEFAULT} (for the default installation).

  6. Build the Dev Containers CLI

    main

    The CLI is written in TypeScript and uses esbuild for bundling. You can build the project using the following commands:

    Incremental Builds (Watch Mode)

    Run these in separate terminals to automatically rebuild on file changes:

    npm run watch            # incremental esbuild (rebuilds on save)
    npm run type-check-watch # tsc in watch mode (reports type errors)

    One-shot Builds

    • Compile: npm run compile (builds the project once).
    • Clean: npm run clean (removes all build output).

    VS Code Integration

    Use the default build task (Ctrl+Shift+B / Cmd+Shift+B) to run npm run watch and npm run type-check-watch in parallel.

    npm run watch
    npm run type-check-watch
  7. Install the Dev Container CLI via npm

    main

    To install the CLI as an npm package, use the @devcontainers/cli package. Note that you must have Python and C/C++ installed on your system to build required dependencies.

    npm install -g @devcontainers/cli
  8. Test Dev Container Features using the `test` command

    main

    The test command provides a built-in testing framework for iterating on self-authored Features. It utilizes the CLI's build and exec commands to test Features within your local source tree.

    By default, the command looks for a src directory containing Feature source code and a test directory containing assertion scripts. For a Feature named <FEATURE>, it auto-generates a test and executes test/<FEATURE>/test.sh inside the container. A test passes if the container builds successfully and the script exits with code 0.

    To run tests for a specific feature (e.g., dotnet) with a specific base image, use:

    devcontainer features test -f dotnet --base-image ubuntu
    devcontainer features test  -f dotnet --base-image ubuntu
  9. Run tests for Dev Containers CLI

    main

    Tests use Mocha and Chai and require Docker. Crucially, you must package the CLI into a tarball before running tests, as the test suite installs the CLI from a .tgz file and executes it as a subprocess.

    Test Workflow

    1. Package the CLI:
    npm run package

    Note: You must re-run this command after any code change so the tarball reflects your latest changes.

    1. Execute Tests:
    npm test                          # all tests
    npm run test-container-features   # Features tests only
    npm run test-container-templates  # Templates tests only

    Adding New Tests

    • Place new test files in src/test/ with a .test.ts suffix.
    • Place test fixture devcontainer.json configurations under src/test/configs/<your-config-name>/.
    • Use helpers in src/test/testUtils.ts (e.g., shellExec, devContainerUp, devContainerDown) for container lifecycle management.
    npm run package
    npm test
  10. Manage lockfiles in Dev Container builds

    main

    The CLI generates .devcontainer-lock.json files by default during build or up operations to pin feature versions for reproducible builds. You can control this behavior using the following flags:

    • --no-lockfile: Opt out of generating/using a lockfile.
    • --frozen-lockfile: Enforce the use of an existing lockfile.
  11. Define Feature test scenarios with `scenarios.json`

    main

    Scenarios allow you to test complex configurations, such as multiple Features in one container or specific Feature options. A scenario is defined as a JSON object where the key is the scenario name and the value is a devcontainer.json configuration snippet.

    When a scenario is defined, the CLI looks for a shell script named <scenario_name>.sh in the test/<FEATURE>/ directory to execute the assertions.

    Example test/oryx/scenarios.json:

    {
        "install_dotnet_and_oryx": {
            "image": "ubuntu:focal",
            "features": {
                "dotnet": {
                    "version": "6",
                    "installUsingApt": "false"
                },
                "oryx": {}
            }
        }
    }

    In this example, the CLI will execute test/oryx/install_dotnet_and_oryx.sh inside the container.