Skip to content

Commit

Permalink
Pass env vars to devcontainer up (#211)
Browse files Browse the repository at this point in the history
* And env vars to build/up commands
* Add env-vars-on-post-create tests
* Update docs on env vars
  • Loading branch information
stuartleeks committed Feb 24, 2023
1 parent 3e5d540 commit fb6a663
Show file tree
Hide file tree
Showing 11 changed files with 307 additions and 2 deletions.
27 changes: 27 additions & 0 deletions .azure-devops/azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,33 @@ jobs:
imageTag: $(IMAGE_TAG)
sourceBranchFilterForPush: ''

- job: test_env_vars_on_post_create
displayName: Test env-vars-on-post-create
steps:
- script: |
docker login -u $ACR_USERNAME -p $ACR_TOKEN $(ACR_NAME).azurecr.io
displayName: 'Log in to Azure Container Registry'
env:
ACR_NAME: $(ACR_NAME)
ACR_TOKEN: $(ACR_TOKEN)
ACR_USERNAME: $(ACR_USERNAME)
- task: DevcontainersCi@0
env: # TEST_ENV_VALUE1 is set via devcontainer.json using a localEnv reference
TEST_ENV_VALUE1: SetViaDevcontainerJsonLocalEnv
inputs:
imageName: '$(ACR_NAME).azurecr.io/devcontainers-ci/azdo-devcontainer-build-run/test/env-vars-on-post-create'
subFolder: github-tests/Dockerfile/env-vars-on-post-create
runCmd: |
cat marker.txt
cat marker.txt | grep 'post-create: TEST_ENV_VALUE1=SetViaDevcontainerJsonLocalEnv'
cat marker.txt | grep 'post-create: TEST_ENV_VALUE2=AdditionalEnvVar'
env: | # TEST_ENV_VALUE2 is an additional env var to pass to the container
TEST_ENV_VALUE2=AdditionalEnvVar
imageTag: $(IMAGE_TAG)
sourceBranchFilterForPush: ''


- job: test_simple
displayName: Test simple
steps:
Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/ci_common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ jobs:
- test-simple
- test-no-run
- test-platform-with-runcmd
- test-env-vars-on-post-create
- test-multiple-tags-job2
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -499,6 +500,58 @@ jobs:
push
pull_request
test-env-vars-on-post-create:
name: Run GitHub env-vars-on-post-create test
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout
uses: actions/checkout@v3
with:
persist-credentials: false
# if the following value is missing (i.e. not triggered via comment workflow)
# then the default checkout will apply
ref: ${{ inputs.prRef }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Login to GitHub Container Registry
if: ${{ needs.build.outputs.image_push_option == 'filter' }}
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

# Published action contains compiled JS, but we need to compile it here
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Compile GH action
run: |
(cd common && npm install && npm run build)
(cd github-action/ && npm install && npm run build && npm run package)
- name: Run test
uses: ./
env: # TEST_ENV_VALUE1 is set via devcontainer.json using a localEnv reference
TEST_ENV_VALUE1: SetViaDevcontainerJsonLocalEnv
with:
subFolder: github-tests/Dockerfile/env-vars-on-post-create
imageName: ghcr.io/devcontainers/ci/tests/env-vars-on-post-create
env: | # TEST_ENV_VALUE2 is an additional env var to pass to the container
TEST_ENV_VALUE2=AdditionalEnvVar
runCmd: |
cat marker.txt
cat marker.txt | grep 'post-create: TEST_ENV_VALUE1=SetViaDevcontainerJsonLocalEnv'
cat marker.txt | grep 'post-create: TEST_ENV_VALUE2=AdditionalEnvVar'
imageTag: ${{ needs.build.outputs.image_tag }}
push: ${{ needs.build.outputs.image_push_option }}
eventFilterForPush: |
push
pull_request
test-gh-build-args:
name: Run GitHub build-args test
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions azdo-task/DevcontainersCi/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export async function runMain(): Promise<void> {
workspaceFolder,
additionalCacheFroms: cacheFrom,
skipContainerUserIdUpdate,
env: inputEnvsWithDefaults,
};
const upResult = await devcontainer.up(upArgs, log);
if (upResult.outcome !== 'success') {
Expand Down
56 changes: 55 additions & 1 deletion azdo-task/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,64 @@ If you want to pass additional environment variables to the dev container when i
WORLD
```

In this example, the `HELLO` environment variable is specified with the value `Hello` in the `env` input on the devcontainer-build-run step. The `WORLD` environment variable is specified without a value so will pick up the value that is assigned in the standard action's `env` configuration.
In this example, the `HELLO` environment variable is specified with the value `Hello` in the `env` input on the devcontainer-build-run step. The `WORLD` environment variable is specified without a value so will pick up the value that is assigned in the standard task's `env` configuration.

The result from running the container is to output "Hello - World".

## Environment Variables

If you want to pass additional environment variables to the dev container when it is run, you can use the `env` input as shown below.


```yaml
- task: DevcontainersCi@0
env:
WORLD: World
inputs:
imageName: 'yourregistry.azurecr.io/example-dev-container'
runCmd: echo "$HELLO - $WORLD"
env: |
HELLO=Hello
WORLD
```

In this example, the `HELLO` environment variable is specified with the value `Hello` in the `env` input on the devcontainer-build-run step. The `WORLD` environment variable is specified without a value so will pick up the value that is assigned in the standard action's `env` configuration (it could also be picked up from the job environment variables - see the [Azure DevOps Piplines Environment Variables docs](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#variable-scopes) for more information).

The result from running the container is to output "Hello - World".

The environment variables specified in the workflow step are passed along when the run-command is executed. Therefore, they replace environment variables with the same name that are set either directly in the Dockerfile or the `devcontainer.json` under the [`containerEnv`](https://code.visualstudio.com/remote/advancedcontainers/environment-variables#_option-1-add-individual-variables) key.

### remoteEnv

If you have environment variables set in the `remoteEnv` section of your `devcontainer.json` file using `localEnv` references, you need to pass the environment variables in a specific way.

Since `localEnv` references are resolved by the `devcontainer` CLI, we need to ensure that we set the values in the correct context for `localEnv`. To do this, the values should be set using the `env` property on the task, not using the `env` nested under the `with` block.

For example, if you have the following section in your `devcontainer.json`:

```json
{
"remoteEnv": {
"HELLO": "${localEnv:HELLO}"
}
}
```

You should set the `HELLO` environment variable using the `env` property on the task, not using the `env` nested under the `with` block.

```yaml
- task: DevcontainersCi@0
env:
# Set HELLO here so that it is resolved via the localEnv context
HELLO: hello
inputs:
imageName: 'yourregistry.azurecr.io/example-dev-container'
runCmd: echo "$HELLO"
# Don't use the env block here to set the HELLO environment variable
# as it will be overridden by the value from localEnv context
# when the CLI starts the container
```

## Multi-Platform Builds

Builds for multiple platforms have special considerations, detailed at [mutli-platform-builds.md](multi-platform-builds.md).
3 changes: 3 additions & 0 deletions common/src/dev-container-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,19 @@ export interface DevContainerCliUpArgs {
workspaceFolder: string;
additionalCacheFroms?: string[];
skipContainerUserIdUpdate?: boolean;
env?: string[];
userDataFolder?: string;
}
async function devContainerUp(
args: DevContainerCliUpArgs,
log: (data: string) => void,
): Promise<DevContainerCliUpResult | DevContainerCliError> {
const remoteEnvArgs = getRemoteEnvArray(args.env);
const commandArgs: string[] = [
'up',
'--workspace-folder',
args.workspaceFolder,
...remoteEnvArgs,
];
if (args.additionalCacheFroms) {
args.additionalCacheFroms.forEach(cacheFrom =>
Expand Down
56 changes: 55 additions & 1 deletion docs/azure-devops-task.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,64 @@ If you want to pass additional environment variables to the dev container when i
WORLD
```

In this example, the `HELLO` environment variable is specified with the value `Hello` in the `env` input on the devcontainer-build-run step. The `WORLD` environment variable is specified without a value so will pick up the value that is assigned in the standard action's `env` configuration.
In this example, the `HELLO` environment variable is specified with the value `Hello` in the `env` input on the devcontainer-build-run step. The `WORLD` environment variable is specified without a value so will pick up the value that is assigned in the standard task's `env` configuration.

The result from running the container is to output "Hello - World".

## Environment Variables

If you want to pass additional environment variables to the dev container when it is run, you can use the `env` input as shown below.


```yaml
- task: DevcontainersCi@0
env:
WORLD: World
inputs:
imageName: 'yourregistry.azurecr.io/example-dev-container'
runCmd: echo "$HELLO - $WORLD"
env: |
HELLO=Hello
WORLD
```

In this example, the `HELLO` environment variable is specified with the value `Hello` in the `env` input on the devcontainer-build-run step. The `WORLD` environment variable is specified without a value so will pick up the value that is assigned in the standard action's `env` configuration (it could also be picked up from the job environment variables - see the [Azure DevOps Piplines Environment Variables docs](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#variable-scopes) for more information).

The result from running the container is to output "Hello - World".

The environment variables specified in the workflow step are passed along when the run-command is executed. Therefore, they replace environment variables with the same name that are set either directly in the Dockerfile or the `devcontainer.json` under the [`containerEnv`](https://code.visualstudio.com/remote/advancedcontainers/environment-variables#_option-1-add-individual-variables) key.

### remoteEnv

If you have environment variables set in the `remoteEnv` section of your `devcontainer.json` file using `localEnv` references, you need to pass the environment variables in a specific way.

Since `localEnv` references are resolved by the `devcontainer` CLI, we need to ensure that we set the values in the correct context for `localEnv`. To do this, the values should be set using the `env` property on the task, not using the `env` nested under the `with` block.

For example, if you have the following section in your `devcontainer.json`:

```json
{
"remoteEnv": {
"HELLO": "${localEnv:HELLO}"
}
}
```

You should set the `HELLO` environment variable using the `env` property on the task, not using the `env` nested under the `with` block.

```yaml
- task: DevcontainersCi@0
env:
# Set HELLO here so that it is resolved via the localEnv context
HELLO: hello
inputs:
imageName: 'yourregistry.azurecr.io/example-dev-container'
runCmd: echo "$HELLO"
# Don't use the env block here to set the HELLO environment variable
# as it will be overridden by the value from localEnv context
# when the CLI starts the container
```

## Multi-Platform Builds

Builds for multiple platforms have special considerations, detailed at [mutli-platform-builds.md](multi-platform-builds.md).
32 changes: 32 additions & 0 deletions docs/github-action.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,38 @@ The result from running the container is to output "Hello - World".

The environment variables specified in the workflow step are passed along when the run-command is executed. Therefore, they replace environment variables with the same name that are set either directly in the Dockerfile or the `devcontainer.json` under the [`containerEnv`](https://code.visualstudio.com/remote/advancedcontainers/environment-variables#_option-1-add-individual-variables) key.

### remoteEnv

If you have environment variables set in the `remoteEnv` section of your `devcontainer.json` file using `localEnv` references, you need to pass the environment variables in a specific way.

Since `localEnv` references are resolved by the `devcontainer` CLI, we need to ensure that we set the values in the correct context for `localEnv`. To do this, the values should be set using the `env` property on the action, not using the `env` nested under the `with` block.

For example, if you have the following section in your `devcontainer.json`:

```json
{
"remoteEnv": {
"HELLO": "${localEnv:HELLO}"
}
}
```

You should set the `HELLO` environment variable using the `env` property on the action, not using the `env` nested under the `with` block.

```yaml
- name: Build and run dev container task
uses: devcontainers/ci@v0.3
env:
# Set HELLO here so that it is resolved via the localEnv context
HELLO: hello
with:
imageName: ghcr.io/example/example-devcontainer
runCmd: echo "$HELLO"
# Don't use the env block here to set the HELLO environment variable
# as it will be overridden by the value from localEnv context
# when the CLI starts the container
```

## Multi-Platform Builds

Builds for multiple platforms have special considerations, detailed at [mutli-platform-builds.md](multi-platform-builds.md).
1 change: 1 addition & 0 deletions github-action/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export async function runMain(): Promise<void> {
workspaceFolder,
additionalCacheFroms: cacheFrom,
skipContainerUserIdUpdate,
env: inputEnvsWithDefaults,
userDataFolder,
};
const result = await devcontainer.up(args, log);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# [Choice] Debian / Ubuntu version: debian-10, debian-9, ubuntu-20.04, ubuntu-18.04
# See https://github.com/microsoft/vscode-dev-containers/tree/master/containers/debian
ARG VARIANT=debian-10
FROM mcr.microsoft.com/vscode/devcontainers/base:${VARIANT}


# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive

# Set env for tracking that we're running in a devcontainer
ENV DEVCONTAINER=true

# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
# will be updated to match your local UID/GID (when using the dockerFile property).
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

USER $USERNAME
RUN \
mkdir -p ~/.local/bin \
&& echo "export PATH=\$PATH:~/.local/bin" >> ~/.bashrc

# Configure apt, install packages and general tools
RUN sudo apt-get update \
&& sudo apt-get -y install --no-install-recommends apt-utils dialog nano bash-completion sudo bsdmainutils \
#
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
&& sudo apt-get -y install git iproute2 procps lsb-release figlet build-essential

# Save command line history
RUN echo "export HISTFILE=/home/$USERNAME/commandhistory/.bash_history" >> "/home/$USERNAME/.bashrc" \
&& echo "export PROMPT_COMMAND='history -a'" >> "/home/$USERNAME/.bashrc" \
&& mkdir -p /home/$USERNAME/commandhistory \
&& touch /home/$USERNAME/commandhistory/.bash_history \
&& chown -R $USERNAME /home/$USERNAME/commandhistory

# Set env for tracking that we're running in a devcontainer
ENV DEVCONTAINER=true

# __DEVCONTAINER_SNIPPET_INSERT__ (control where snippets get inserted using the devcontainer CLI)

# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.117.1/containers/go
{
"name": "env-vars-on-post-create",
"dockerFile": "Dockerfile",
"build": {
"cacheFrom": "ghcr.io/devcontainers/ci/tests/env-vars-on-post-create:latest"
},
"remoteEnv": {
"TEST_ENV_VALUE": "${localEnv:TEST_ENV_VALUE}"
},

// Add the IDs of extensions you want installed when the container is created.
// "extensions": [],

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "./.devcontainer/post-create.sh",

"remoteUser": "vscode"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
set -e

echo "**************************************************"
echo "*** In post-create.sh "
echo "*** TEST_ENV_VALUE=${TEST_ENV_VALUE}"
echo "*** TEST_ENV_VALUE2=${TEST_ENV_VALUE2}"
echo "**************************************************"
echo "post-create: TEST_ENV_VALUE=${TEST_ENV_VALUE}" > marker.txt
echo "post-create: TEST_ENV_VALUE2=${TEST_ENV_VALUE2}" >> marker.txt

0 comments on commit fb6a663

Please sign in to comment.