5 Matching Annotations
  1. Jun 2024
    1. Sample .devcontainer/devcontainer.json:

      json { "name": "Global", "build": { "context": "..", "dockerfile": "Dockerfile" }, "containerEnv": { "PYTHONPATH": "." }, "customizations": { "vscode": { "settings": { "extensions.verifySignature": false }, "extensions": [ "GitHub.copilot", "ms-python.vscode-pylance", "ms-python.python", "eamodio.gitlens" ] } }, "initializeCommand": "/bin/bash -c '[[ -d ${HOME}/.aws ]] || { echo \"Error: ${HOME}/.aws directory not found.\"; exit 1; }; [[ -f ${HOME}/.netrc ]] || { echo \"Error: ${HOME}/.netrc file not found.\"; exit 1; }; [[ -d ${HOME}/.ssh ]] || { echo \"Error: ${HOME}/.ssh directory not found.\"; exit 1; }; echo \"\n> All required mounts found on the host machine.\"'", "onCreateCommand": { "hadolint": "apt-get update && apt-get install wget -y && wget -O /bin/hadolint https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 && chmod u+x /usr/bin/hadolint", "precommit": "pip install pre-commit" }, "updateContentCommand": "/bin/bash -c 'if grep -A 2 \"machine gitlab.com\" ~/.netrc | grep -q \"password\" && GITLAB_TOKEN=$(grep -A 2 \"machine gitlab.com\" ~/.netrc | grep -oP \"(?<=password ).*\" | tr -d \"\\n\") && [ -n \"$GITLAB_TOKEN\" ]; then echo \"\n> Token found in ~/.netrc\"; else read -sp \"\n> Enter your GitLab token: \" GITLAB_TOKEN && echo; fi; echo \"export GITLAB_TOKEN=$GITLAB_TOKEN\" >> ~/.bashrc && . ~/.bashrc && poetry config http-basic.abc __token__ $GITLAB_TOKEN'", "postCreateCommand": ". ~/.bashrc && curl -s --location 'https://gitlab.com/api/v4/projects/12345/repository/files/.pre-commit-config.yaml/raw?ref=main' --header \"PRIVATE-TOKEN: $GITLAB_TOKEN\" -o .pre-commit-config.yaml", "postAttachCommand": "/bin/bash -c '. ~/.bashrc && read -p \"\n> Do you want to update the content of devcontainer.json? (y/n): \" response; if [[ \"$response\" == \"y\" ]]; then curl -s --location \"https://gitlab.com/api/v4/projects/12345/repository/files/devcontainer.json/raw?ref=main\" --header \"PRIVATE-TOKEN: $GITLAB_TOKEN\" -o .devcontainer/devcontainer.json; else echo \"\n> Skipping update of devcontainer.json\"; fi'", "mounts": [ "source=${localEnv:HOME}/.aws/,target=/root/.aws/,type=bind,readonly", "source=${localEnv:HOME}/.netrc,target=/root/.netrc,type=bind,readonly", "source=${localEnv:HOME}/.ssh/,target=/root/.ssh/,type=bind,readonly" ] }

    2. Some more of my recent learning with devcontainer.json (its Dev Container metadata):

      • Interactive commands (those waiting for user input like read) do not display the input request in (at least onCreateCommand and postCreateCommand sections), so it is better to keep them in updateContentCommand or postAttachCommand.
      • If there are 2 read commands in a single section, like updateContentCommand, only the 1st one is displayed to the user, and the 2nd one is ignored.
      • When I put a read command within a dictionary (with at lest 2 key/values) of postAttachCommand, the interactive command wasn't being displayed.
      • We need to use /bin/bash -c to be able to use read -s (the -s flag) which allows for securely passing the password so that it does not stay in the VS Code console. Also, I had trouble with interactive commands and if statements without it.
      • Using "GITLAB_TOKEN": "${localEnv:GITLAB_TOKEN}" does not easily work as it is looking for GITLAB_TOKEN env variable set locally on our host computers, and I believe no one does it.
      • The dictionary seems to be executing its scripts in parallel; therefore, it is not easily possible to break down long lines which have to execute in a chronological sequence.
      • JSON does not allow for human-readable line breaks; therefore, indeed, it seems impossible to improve the long one-liners.
      • The files/folders mentioned within mounts need to exist locally (otherwise, Docker container build fails). They are mounted before any other section. Technically, we can protect ourselves with the following command to find an extra message in VS Code container logs:

      json "initializeCommand": "/bin/bash -c '[[ -d ${HOME}/.aws ]] || { echo \"Error: ${HOME}/.aws directory not found.\"; exit 1; }; [[ -f ${HOME}/.netrc ]] || { echo \"Error: ${HOME}/.netrc file not found.\"; exit 1; }; [[ -d ${HOME}/.ssh ]] || { echo \"Error: ${HOME}/.ssh directory not found.\"; exit 1; }'",

      Other option is to get rid of the error completely, but this creates files on the host machine; therefore, it is not an ideal solution:

      json "initializeCommand": "mkdir -p ~/.ssh ~/.aws && touch ~/.netrc",

    3. ["bash", "-i", "-c", "read -p 'Type a message: ' -t 10 && echo Attach $REPLY"],

      I would also simply put the following:

      bash /bin/bash -c 'read -p 'Type a message: ' -t 10 && echo Attach $REPLY'

    4. Consequently, it’s one of the only commands that consistently allows interactions with users.

      I also found that updateContentCommand allows for the user interaction (it displays interactive command in the VS Code console).

    5. There are six available lifecycle script hooks

      Explanation of 6 available devcontainer.json (Dev Container in VS Code) hooks.