From 2ddc99cf12277648201c4e93dc006de785ace1ec Mon Sep 17 00:00:00 2001 From: Kristjana Popovski Date: Mon, 20 Dec 2021 12:11:07 -0500 Subject: [PATCH 01/14] added documentation skeleton --- CONTRIBUTING.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7860901468..c78c2d31cc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -176,6 +176,20 @@ The Remote - Containers extension ships into **VS Code Insiders** as new feature If there is an urgent need for an update to the definitions outside of this release cycle, please raise an issue in this repository requesting an out-of-band release to fix a critical issue. +## Contributing Dev Container Features + +### Creating a new feature + +**Registering a feature** + +**Feature testing** + +**Feature documentation** + +### Best practices for writing an install script + +### Contributing container features in vscode-dev-containers vs. in a new repository + ## Contributing to Documentation The majority of VS Code Remote's documentation can be found in the [VS Code docs repository](https://github.com/Microsoft/vscode-docs). This is usually the best place to contribute, but if you have a correction or suggestion for the content found here, we welcome your contributions. From 1e39ea55f80d755fafc1933fdee473a189352dea Mon Sep 17 00:00:00 2001 From: "Bill DeRusha (HE/HIM)" Date: Mon, 20 Dec 2021 15:16:35 -0500 Subject: [PATCH 02/14] Add wire-up docs to CONTRIBUTING.md --- CONTRIBUTING.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c78c2d31cc..a8352fd4ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -180,12 +180,78 @@ If there is an urgent need for an update to the definitions outside of this rele ### Creating a new feature +A dev container feature is an installation script which can be run on an existing container to add additional tools and functionality. + **Registering a feature** +Create the install script in the [script-library](script-library/) directory with the naming convention `-.sh`. EG `python-debian.sh` or `common-alpine.sh` + +Add a new object to the [features.json](script-library/container-features/src/features.json) file: + + ```json + "id": "", // Must match the used to name the install script. + "name": "Display Name of Feature", + "documentationURL": "https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/.md", + "options": { + "scriptArgument$1": { + "type": "string", // Either "string" or "boolean" + "proposals": [], // Array of valid string values for this option. + "default": "", // Default value if user does not specify. + "description": "" // User-facing description of this option. + }, + "scriptArgument$2": { + "type":"boolean", // Either "string" or "boolean" + "default": false, // Either true or false + "description": "" // User-facing description of this option. + } + }, + "buildArg": "_VSC_INSTALL_", // Must match the ENV VAR defined in the feature-scripts.env file. + "extensions": [], // Array of VS Code extensions to install with this feature. + "include": [] // Array of base containers this script can be used on. + ``` + +Add your buildArg to the [feature-scripts.env](script-library/container-features/src/feature-scripts.env) file with all script arguments specified (even if they duplicate a script default). + + ``` + _VSC_INSTALL_="-debian.sh ${_BUILD_ARG__:-} ${_BUILD_ARG__:-_` and their default should match the declared default for that option. + +EG `_VSC_INSTALL_AZURE_CLI="azcli-debian.sh ${_BUILD_ARG_AZURE_CLI_VERSION:-latest}"` + **Feature testing** +Unit tests +- Add your feature to the [run-scripts.sh](script-library/test/regression/run-scripts.sh) file to ensure it is included in CI tests. +- Your addition should take the form `runScript `. EG `runScript dotnet "3.1 true ${USERNAME} false /opt/dotnet dotnet"` +- If your script takes the installation user as an argument, be sure to specify it as ${USERNAME} in the tests for programatic testing. + +Regression tests +- Add your feature to the [test-features.env](script-library/container-features/test-features.env) file to include it in regression tests of the container-feature functionality. By setting the `_VSC_INSTALL_` ENV VAR to true and adding the expected _BUILD_ARG options for your feature. + +EG + ``` + _VSC_INSTALL_DOTNET=true + _BUILD_ARG_DOTNET_VERSION=latest + _BUILD_ARG_DOTNET_RUNTIMEONLY=false + ``` + **Feature documentation** +Add your new feature to the list of scripts in the [script-library README.md](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/README.md#scripts). + +Add documentation for your new feature script to the [script-library/docs](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs) directory. + +Documentation should include: +- the status of the script and supported operating systems +- the syntax expected to run as a feature or script +- a description of the arguments +- detailed usage instructions + +Feel free to use other scripts in that directory as inspiration. + + ### Best practices for writing an install script ### Contributing container features in vscode-dev-containers vs. in a new repository From afac5ebc9c96e000aee9d68748ba4c6a96f7c2b7 Mon Sep 17 00:00:00 2001 From: Kristjana Popovski Date: Mon, 20 Dec 2021 14:51:29 -0500 Subject: [PATCH 03/14] added list of best practices --- CONTRIBUTING.md | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a8352fd4ae..0f9064a678 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -239,20 +239,46 @@ EG **Feature documentation** -Add your new feature to the list of scripts in the [script-library README.md](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/README.md#scripts). +### Best practices for writing feature install scripts + +- Decouple sections of the shellscript that handle user setup, helper functions, and feature installation. Doing so will apply a logical and natural flow to the script for future developers and maintainers to follow. One way to denote this distinction is to use in-line comments throughout the script. + ```md + # Logical flow recommended: + 1. File header and description. + 2. Define constants and default values. + 3. User setup and user validation. + 4. Helper functions. + 5. Checks for dependencies being installed or Installs dependencies. + 6. Runs container feature installs. + 7. Gives the user correct permissions if necessary. + ``` -Add documentation for your new feature script to the [script-library/docs](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs) directory. +- Error messages from the script should echo to `STDERR`, while regular status messages should echo to `STDOUT`. This makes troubleshooting the script easier for developers. One way to facilitate this is to create an `err()` function like so: + ```sh + # Setup STDERR. + err() { + echo "(!) $*" >&2 + } + ``` -Documentation should include: -- the status of the script and supported operating systems -- the syntax expected to run as a feature or script -- a description of the arguments -- detailed usage instructions +- Always make sure to use double quotes and braces when referencing variables: + ```sh + echo "${variable}" + ``` -Feel free to use other scripts in that directory as inspiration. +- For code clarity, assign return values from functions to a new variable and use the keyword `local` for vars inside of functions. This will ensure the global space is not crowded with unnecessary variables. For example: + ```sh + test_function() { + local test = "hello world!" + echo "${test}" + } + + test=$(test_function) + ``` +- If you are using temporary files within the script, make sure to run a cleanup function when the script exists. The recommended method is to use `trap`. -### Best practices for writing an install script +- Consider using [shellcheck](https://github.com/koalaman/shellcheck) to apply linting and static code analysis to the bash script to ensure it is formatted correctly. ### Contributing container features in vscode-dev-containers vs. in a new repository From a478dc3b125ecee88981198579e12d58ed6e9eca Mon Sep 17 00:00:00 2001 From: "Bill DeRusha (HE/HIM)" Date: Mon, 20 Dec 2021 16:02:08 -0500 Subject: [PATCH 04/14] Update based on live edits --- CONTRIBUTING.md | 128 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 42 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0f9064a678..4a97c5d748 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -178,9 +178,9 @@ If there is an urgent need for an update to the definitions outside of this rele ## Contributing Dev Container Features -### Creating a new feature +A dev container feature is an installation script which can be run on an existing container to add additional tools and functionality. -A dev container feature is an installation script which can be run on an existing container to add additional tools and functionality. +### Creating a new feature **Registering a feature** @@ -188,57 +188,81 @@ Create the install script in the [script-library](script-library/) directory wit Add a new object to the [features.json](script-library/container-features/src/features.json) file: - ```json - "id": "", // Must match the used to name the install script. - "name": "Display Name of Feature", - "documentationURL": "https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/.md", - "options": { - "scriptArgument$1": { - "type": "string", // Either "string" or "boolean" - "proposals": [], // Array of valid string values for this option. - "default": "", // Default value if user does not specify. - "description": "" // User-facing description of this option. - }, - "scriptArgument$2": { - "type":"boolean", // Either "string" or "boolean" - "default": false, // Either true or false - "description": "" // User-facing description of this option. - } +```json +{ + "id": "", // Must match the used to name the install script. + "name": "Display Name of Feature", + "documentationURL": "https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/.md", + "options": { + "scriptArgument$1": { + "type": "string", // Either "string" or "boolean" + "proposals": [], // Array of valid string values for this option. + "default": "", // Default value if user does not specify. + "description": "" // User-facing description of this option. }, - "buildArg": "_VSC_INSTALL_", // Must match the ENV VAR defined in the feature-scripts.env file. - "extensions": [], // Array of VS Code extensions to install with this feature. - "include": [] // Array of base containers this script can be used on. - ``` + "scriptArgument$2": { + "type":"boolean", // Either "string" or "boolean" + "default": false, // Either true or false + "description": "" // User-facing description of this option. + } + }, + "buildArg": "_VSC_INSTALL_", // Must match the ENV VAR defined in the feature-scripts.env file. + "extensions": [], // Array of VS Code extensions to install with this feature. + "include": [] // Array of base containers this script can be used on. +} +``` Add your buildArg to the [feature-scripts.env](script-library/container-features/src/feature-scripts.env) file with all script arguments specified (even if they duplicate a script default). - ``` - _VSC_INSTALL_="-debian.sh ${_BUILD_ARG__:-} ${_BUILD_ARG__:-_` and their default should match the declared default for that option. +``` +_VSC_INSTALL_="-debian.sh ${_BUILD_ARG__:-} ${_BUILD_ARG__:-_` and their default should match the declared default for that option. +- EG `_VSC_INSTALL_AZURE_CLI="azcli-debian.sh ${_BUILD_ARG_AZURE_CLI_VERSION:-latest}"` **Feature testing** -Unit tests +*Local testing* + +- Create a devcontainer with a target base image. +- Add your script to the root. +- Bring up the container image. +- Run your script in the container with required arguments. +- Verify expected results. +- Bring down container to clean up. + +Repeat as needed to iterate from a clean workspace. + +*Unit tests* - Add your feature to the [run-scripts.sh](script-library/test/regression/run-scripts.sh) file to ensure it is included in CI tests. - Your addition should take the form `runScript `. EG `runScript dotnet "3.1 true ${USERNAME} false /opt/dotnet dotnet"` - If your script takes the installation user as an argument, be sure to specify it as ${USERNAME} in the tests for programatic testing. -Regression tests +*Regression tests* - Add your feature to the [test-features.env](script-library/container-features/test-features.env) file to include it in regression tests of the container-feature functionality. By setting the `_VSC_INSTALL_` ENV VAR to true and adding the expected _BUILD_ARG options for your feature. EG - ``` - _VSC_INSTALL_DOTNET=true - _BUILD_ARG_DOTNET_VERSION=latest - _BUILD_ARG_DOTNET_RUNTIMEONLY=false - ``` +``` + _VSC_INSTALL_DOTNET=true + _BUILD_ARG_DOTNET_VERSION=latest + _BUILD_ARG_DOTNET_RUNTIMEONLY=false +``` **Feature documentation** +Add your new feature to the list of scripts in the [script-library README.md](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/README.md#scripts). + +Add documentation for your new feature script to the [script-library/docs](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs) directory. + +Documentation should include: +- the status of the script, supported operating systems, and maintainer. +- the syntax expected to run as a feature or script +- a description of the script arguments +- detailed usage instructions + +Feel free to use other scripts in that directory as inspiration. + ### Best practices for writing feature install scripts - Decouple sections of the shellscript that handle user setup, helper functions, and feature installation. Doing so will apply a logical and natural flow to the script for future developers and maintainers to follow. One way to denote this distinction is to use in-line comments throughout the script. @@ -248,7 +272,7 @@ EG 2. Define constants and default values. 3. User setup and user validation. 4. Helper functions. - 5. Checks for dependencies being installed or Installs dependencies. + 5. Checks for dependencies being installed or installs dependencies. 6. Runs container feature installs. 7. Gives the user correct permissions if necessary. ``` @@ -258,11 +282,15 @@ EG # Setup STDERR. err() { echo "(!) $*" >&2 - } + } + + err "Something went wrong!" + exit 1 ``` -- Always make sure to use double quotes and braces when referencing variables: +- Always make sure to use double quotes and braces when referencing named variables: ```sh + variable="My example var" echo "${variable}" ``` @@ -273,14 +301,30 @@ EG echo "${test}" } - test=$(test_function) + global_test=$(test_function) ``` -- If you are using temporary files within the script, make sure to run a cleanup function when the script exists. The recommended method is to use `trap`. +- If you are using temporary files within the script, make sure to run a cleanup function when the script exists. The recommended method is to use `trap`. For example: + + ```sh + # Cleanup temporary directory and associated files when exiting the script. + cleanup() { + EXIT_CODE=$? + set +e + if [[ -n "${TMP_DIR}" ]]; then + echo "Executing cleanup of tmp files" + rm -Rf "${TMP_DIR}" + fi + exit $EXIT_CODE + } + trap cleanup EXIT + ``` -- Consider using [shellcheck](https://github.com/koalaman/shellcheck) to apply linting and static code analysis to the bash script to ensure it is formatted correctly. +- Consider using [shellcheck](https://github.com/koalaman/shellcheck) or the [vscode-shellcheck extension](https://github.com/vscode-shellcheck/vscode-shellcheck) to apply linting and static code analysis to the bash script to ensure it is formatted correctly. -### Contributing container features in vscode-dev-containers vs. in a new repository +- Consider using common helper functions from [shared/utils.sh](script-library\shared\utils.sh) when managing common tasks (like updating PATH variables, or managing gpg keys) by copying them directly into your script. + - NOTE: This is done to minimize the impact that any change can have on existing working scripts. + - Similarly, if you add a helper function to your script that could benefit others in the future, consider adding it to the `utils.sh` file as well. ## Contributing to Documentation From ee3354217e9871c5dfcf23bb8f66105a457c3221 Mon Sep 17 00:00:00 2001 From: "Bill DeRusha (HE/HIM)" Date: Mon, 20 Dec 2021 16:20:43 -0500 Subject: [PATCH 05/14] Fixup --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4a97c5d748..46bd7c81d5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -322,7 +322,7 @@ Feel free to use other scripts in that directory as inspiration. - Consider using [shellcheck](https://github.com/koalaman/shellcheck) or the [vscode-shellcheck extension](https://github.com/vscode-shellcheck/vscode-shellcheck) to apply linting and static code analysis to the bash script to ensure it is formatted correctly. -- Consider using common helper functions from [shared/utils.sh](script-library\shared\utils.sh) when managing common tasks (like updating PATH variables, or managing gpg keys) by copying them directly into your script. +- Consider using common helper functions from [shared/utils.sh](script-library/shared/utils.sh) when managing common tasks (like updating PATH variables, or managing gpg keys) by copying them directly into your script. - NOTE: This is done to minimize the impact that any change can have on existing working scripts. - Similarly, if you add a helper function to your script that could benefit others in the future, consider adding it to the `utils.sh` file as well. From 91ae214151358b457e868f53922f86dc1d751ed6 Mon Sep 17 00:00:00 2001 From: Kristjana Popovski Date: Thu, 13 Jan 2022 15:00:14 -0500 Subject: [PATCH 06/14] changes per PR reviews --- CONTRIBUTING.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46bd7c81d5..90d9d2c356 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -215,7 +215,7 @@ Add a new object to the [features.json](script-library/container-features/src/fe Add your buildArg to the [feature-scripts.env](script-library/container-features/src/feature-scripts.env) file with all script arguments specified (even if they duplicate a script default). ``` -_VSC_INSTALL_="-debian.sh ${_BUILD_ARG__:-} ${_BUILD_ARG__:-="-debian.sh ${_BUILD_ARG__:-} ${_BUILD_ARG__:-} hardcodedThirdArgument" ``` - Options declared in `features.json` are mapped using the naming convention `_BUILD_ARG__` and their default should match the declared default for that option. @@ -277,7 +277,7 @@ Feel free to use other scripts in that directory as inspiration. 7. Gives the user correct permissions if necessary. ``` -- Error messages from the script should echo to `STDERR`, while regular status messages should echo to `STDOUT`. This makes troubleshooting the script easier for developers. One way to facilitate this is to create an `err()` function like so: +- One way to make troubleshooting the script easier when writing a bash shell script is to echo error messages to `STDERR`. A possible way we implemented this in bash scripts is to create an `err()` function like so: ```sh # Setup STDERR. err() { @@ -288,13 +288,13 @@ Feel free to use other scripts in that directory as inspiration. exit 1 ``` -- Always make sure to use double quotes and braces when referencing named variables: +- If writing a bash shellscript, we recommend using double quotes and braces when referencing named variables: ```sh variable="My example var" echo "${variable}" ``` -- For code clarity, assign return values from functions to a new variable and use the keyword `local` for vars inside of functions. This will ensure the global space is not crowded with unnecessary variables. For example: +- One method to to ensure the global space in a script is not too crowded with unnecessary variables is to assign return values from functions to a new variable, and use the keyword `local` for vars inside of functions. For example: ```sh test_function() { local test = "hello world!" @@ -304,8 +304,7 @@ Feel free to use other scripts in that directory as inspiration. global_test=$(test_function) ``` -- If you are using temporary files within the script, make sure to run a cleanup function when the script exists. The recommended method is to use `trap`. For example: - +- If using temporary files within the script, we recommend removing all those files once they are no longer needed. One method for doing this is running a cleanup function with a `trap` method when the script exits: ```sh # Cleanup temporary directory and associated files when exiting the script. cleanup() { @@ -324,7 +323,7 @@ Feel free to use other scripts in that directory as inspiration. - Consider using common helper functions from [shared/utils.sh](script-library/shared/utils.sh) when managing common tasks (like updating PATH variables, or managing gpg keys) by copying them directly into your script. - NOTE: This is done to minimize the impact that any change can have on existing working scripts. - - Similarly, if you add a helper function to your script that could benefit others in the future, consider adding it to the `utils.sh` file as well. + - Similarly, if you add a helper function to your script that could benefit others in the future, consider adding it to the `shared/utils.sh` file as well. ## Contributing to Documentation From 6f95e0a7e9a3462a78c37c0877842d4a68d51554 Mon Sep 17 00:00:00 2001 From: Kristjana Popovski Date: Tue, 18 Jan 2022 16:34:56 -0500 Subject: [PATCH 07/14] adding section to summary --- CONTRIBUTING.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c0bf8f4c04..3b47457bf2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,6 +13,9 @@ This document outlines a number of ways you can get involved. - [Developing and testing a definition](#developing-and-testing-a-definition) - [Adding a Database Definition to an existing Container](#adding-a-database-definition-to-an-existing-container) - [Release cadence for new containers or container updates](#release-cadence-for-new-containers-or-container-updates) + - [Contributing Dev Container Features](#contributing-dev-container-features) + - [Creating a new feature](#creating-a-new-feature) + - [Best practices for writing feature install scripts](#best-practices-for-writing-feature-install-scripts) - [Contributing to Documentation](#contributing-to-documentation) - [Reporting Issues](#reporting-issues) - [Identify Where to Report](#identify-where-to-report) @@ -305,7 +308,14 @@ Repeat as needed to iterate from a clean workspace. *Unit tests* - Add your feature to the [run-scripts.sh](script-library/test/regression/run-scripts.sh) file to ensure it is included in CI tests. -- Your addition should take the form `runScript `. EG `runScript dotnet "3.1 true ${USERNAME} false /opt/dotnet dotnet"` + +- Your addition should take the form `runScript `. + +EG +```sh +runScript dotnet "3.1 true ${USERNAME} false /opt/dotnet dotnet" +``` + - If your script takes the installation user as an argument, be sure to specify it as ${USERNAME} in the tests for programatic testing. *Regression tests* @@ -394,6 +404,8 @@ Feel free to use other scripts in that directory as inspiration. - NOTE: This is done to minimize the impact that any change can have on existing working scripts. - Similarly, if you add a helper function to your script that could benefit others in the future, consider adding it to the `shared/utils.sh` file as well. +- [shared/settings.env](script-library/shared/settings.env) contains shared environment variables used in many install scripts, such as `GPG Keys` and `Archive Architectures`. Consider adding your new env. variables to this script when applicable, or reusing existing variables when pertinent. + ## Contributing to Documentation The majority of VS Code Remote's documentation can be found in the [VS Code docs repository](https://github.com/Microsoft/vscode-docs). This is usually the best place to contribute, but if you have a correction or suggestion for the content found here, we welcome your contributions. From 560af631e2047b354751fb95bd114552b9503642 Mon Sep 17 00:00:00 2001 From: Kristjana Popovski Date: Thu, 20 Jan 2022 15:05:02 -0500 Subject: [PATCH 08/14] reallocated DCF documentation --- CONTRIBUTING.md | 161 -------------------- script-library/container-features/README.md | 158 ++++++++++++++++++- 2 files changed, 157 insertions(+), 162 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3b47457bf2..9e551c33fc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,9 +13,6 @@ This document outlines a number of ways you can get involved. - [Developing and testing a definition](#developing-and-testing-a-definition) - [Adding a Database Definition to an existing Container](#adding-a-database-definition-to-an-existing-container) - [Release cadence for new containers or container updates](#release-cadence-for-new-containers-or-container-updates) - - [Contributing Dev Container Features](#contributing-dev-container-features) - - [Creating a new feature](#creating-a-new-feature) - - [Best practices for writing feature install scripts](#best-practices-for-writing-feature-install-scripts) - [Contributing to Documentation](#contributing-to-documentation) - [Reporting Issues](#reporting-issues) - [Identify Where to Report](#identify-where-to-report) @@ -248,164 +245,6 @@ The Remote - Containers extension ships into **VS Code Insiders** as new feature If there is an urgent need for an update to the definitions outside of this release cycle, please raise an issue in this repository requesting an out-of-band release to fix a critical issue. -## Contributing Dev Container Features - -A dev container feature is an installation script which can be run on an existing container to add additional tools and functionality. - -### Creating a new feature - -**Registering a feature** - -Create the install script in the [script-library](script-library/) directory with the naming convention `-.sh`. EG `python-debian.sh` or `common-alpine.sh` - -Add a new object to the [features.json](script-library/container-features/src/features.json) file: - -```json -{ - "id": "", // Must match the used to name the install script. - "name": "Display Name of Feature", - "documentationURL": "https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/.md", - "options": { - "scriptArgument$1": { - "type": "string", // Either "string" or "boolean" - "proposals": [], // Array of valid string values for this option. - "default": "", // Default value if user does not specify. - "description": "" // User-facing description of this option. - }, - "scriptArgument$2": { - "type":"boolean", // Either "string" or "boolean" - "default": false, // Either true or false - "description": "" // User-facing description of this option. - } - }, - "buildArg": "_VSC_INSTALL_", // Must match the ENV VAR defined in the feature-scripts.env file. - "extensions": [], // Array of VS Code extensions to install with this feature. - "include": [] // Array of base containers this script can be used on. -} -``` - -Add your buildArg to the [feature-scripts.env](script-library/container-features/src/feature-scripts.env) file with all script arguments specified (even if they duplicate a script default). - -``` -_VSC_INSTALL_="-debian.sh ${_BUILD_ARG__:-} ${_BUILD_ARG__:-} hardcodedThirdArgument" -``` - -- Options declared in `features.json` are mapped using the naming convention `_BUILD_ARG__` and their default should match the declared default for that option. -- EG `_VSC_INSTALL_AZURE_CLI="azcli-debian.sh ${_BUILD_ARG_AZURE_CLI_VERSION:-latest}"` - -**Feature testing** - -*Local testing* - -- Create a devcontainer with a target base image. -- Add your script to the root. -- Bring up the container image. -- Run your script in the container with required arguments. -- Verify expected results. -- Bring down container to clean up. - -Repeat as needed to iterate from a clean workspace. - -*Unit tests* -- Add your feature to the [run-scripts.sh](script-library/test/regression/run-scripts.sh) file to ensure it is included in CI tests. - -- Your addition should take the form `runScript `. - -EG -```sh -runScript dotnet "3.1 true ${USERNAME} false /opt/dotnet dotnet" -``` - -- If your script takes the installation user as an argument, be sure to specify it as ${USERNAME} in the tests for programatic testing. - -*Regression tests* -- Add your feature to the [test-features.env](script-library/container-features/test-features.env) file to include it in regression tests of the container-feature functionality. By setting the `_VSC_INSTALL_` ENV VAR to true and adding the expected _BUILD_ARG options for your feature. - -EG -``` - _VSC_INSTALL_DOTNET=true - _BUILD_ARG_DOTNET_VERSION=latest - _BUILD_ARG_DOTNET_RUNTIMEONLY=false -``` - -**Feature documentation** - -Add your new feature to the list of scripts in the [script-library README.md](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/README.md#scripts). - -Add documentation for your new feature script to the [script-library/docs](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs) directory. - -Documentation should include: -- the status of the script, supported operating systems, and maintainer. -- the syntax expected to run as a feature or script -- a description of the script arguments -- detailed usage instructions - -Feel free to use other scripts in that directory as inspiration. - -### Best practices for writing feature install scripts - -- Decouple sections of the shellscript that handle user setup, helper functions, and feature installation. Doing so will apply a logical and natural flow to the script for future developers and maintainers to follow. One way to denote this distinction is to use in-line comments throughout the script. - ```md - # Logical flow recommended: - 1. File header and description. - 2. Define constants and default values. - 3. User setup and user validation. - 4. Helper functions. - 5. Checks for dependencies being installed or installs dependencies. - 6. Runs container feature installs. - 7. Gives the user correct permissions if necessary. - ``` - -- One way to make troubleshooting the script easier when writing a bash shell script is to echo error messages to `STDERR`. A possible way we implemented this in bash scripts is to create an `err()` function like so: - ```sh - # Setup STDERR. - err() { - echo "(!) $*" >&2 - } - - err "Something went wrong!" - exit 1 - ``` - -- If writing a bash shellscript, we recommend using double quotes and braces when referencing named variables: - ```sh - variable="My example var" - echo "${variable}" - ``` - -- One method to to ensure the global space in a script is not too crowded with unnecessary variables is to assign return values from functions to a new variable, and use the keyword `local` for vars inside of functions. For example: - ```sh - test_function() { - local test = "hello world!" - echo "${test}" - } - - global_test=$(test_function) - ``` - -- If using temporary files within the script, we recommend removing all those files once they are no longer needed. One method for doing this is running a cleanup function with a `trap` method when the script exits: - ```sh - # Cleanup temporary directory and associated files when exiting the script. - cleanup() { - EXIT_CODE=$? - set +e - if [[ -n "${TMP_DIR}" ]]; then - echo "Executing cleanup of tmp files" - rm -Rf "${TMP_DIR}" - fi - exit $EXIT_CODE - } - trap cleanup EXIT - ``` - -- Consider using [shellcheck](https://github.com/koalaman/shellcheck) or the [vscode-shellcheck extension](https://github.com/vscode-shellcheck/vscode-shellcheck) to apply linting and static code analysis to the bash script to ensure it is formatted correctly. - -- Consider using common helper functions from [shared/utils.sh](script-library/shared/utils.sh) when managing common tasks (like updating PATH variables, or managing gpg keys) by copying them directly into your script. - - NOTE: This is done to minimize the impact that any change can have on existing working scripts. - - Similarly, if you add a helper function to your script that could benefit others in the future, consider adding it to the `shared/utils.sh` file as well. - -- [shared/settings.env](script-library/shared/settings.env) contains shared environment variables used in many install scripts, such as `GPG Keys` and `Archive Architectures`. Consider adding your new env. variables to this script when applicable, or reusing existing variables when pertinent. - ## Contributing to Documentation The majority of VS Code Remote's documentation can be found in the [VS Code docs repository](https://github.com/Microsoft/vscode-docs). This is usually the best place to contribute, but if you have a correction or suggestion for the content found here, we welcome your contributions. diff --git a/script-library/container-features/README.md b/script-library/container-features/README.md index f5a05bb516..8edd9eac23 100644 --- a/script-library/container-features/README.md +++ b/script-library/container-features/README.md @@ -1 +1,157 @@ -This folder includes some explorations around dynamic container feature injection. Nothing stable yet. \ No newline at end of file +# Container Features + +This folder includes some explorations around dynamic container feature injection. Nothing stable yet. + +## Contributing to Container Features + +### Creating a new feature + +**Registering a feature** + +Create the install script in the [script-library](script-library/) directory with the naming convention `-.sh`. EG `python-debian.sh` or `common-alpine.sh` + +Add a new object to the [features.json](script-library/container-features/src/features.json) file: + +```json +{ + "id": "", // Must match the used to name the install script. + "name": "Display Name of Feature", + "documentationURL": "https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/.md", + "options": { + "scriptArgument$1": { + "type": "string", // Either "string" or "boolean" + "proposals": [], // Array of valid string values for this option. + "default": "", // Default value if user does not specify. + "description": "" // User-facing description of this option. + }, + "scriptArgument$2": { + "type":"boolean", // Either "string" or "boolean" + "default": false, // Either true or false + "description": "" // User-facing description of this option. + } + }, + "buildArg": "_VSC_INSTALL_", // Must match the ENV VAR defined in the feature-scripts.env file. + "extensions": [], // Array of VS Code extensions to install with this feature. + "include": [] // Array of base containers this script can be used on. +} +``` + +Add your buildArg to the [feature-scripts.env](script-library/container-features/src/feature-scripts.env) file with all script arguments specified (even if they duplicate a script default). + +``` +_VSC_INSTALL_="-debian.sh ${_BUILD_ARG__:-} ${_BUILD_ARG__:-} hardcodedThirdArgument" +``` + +- Options declared in `features.json` are mapped using the naming convention `_BUILD_ARG__` and their default should match the declared default for that option. +- EG `_VSC_INSTALL_AZURE_CLI="azcli-debian.sh ${_BUILD_ARG_AZURE_CLI_VERSION:-latest}"` + +**Feature testing** + +*Local testing* + +- Create a devcontainer with a target base image. +- Add your script to the root. +- Bring up the container image. +- Run your script in the container with required arguments. +- Verify expected results. +- Bring down container to clean up. + +Repeat as needed to iterate from a clean workspace. + +*Unit tests* +- Add your feature to the [run-scripts.sh](script-library/test/regression/run-scripts.sh) file to ensure it is included in CI tests. + +- Your addition should take the form `runScript `. + +EG +```sh +runScript dotnet "3.1 true ${USERNAME} false /opt/dotnet dotnet" +``` + +- If your script takes the installation user as an argument, be sure to specify it as ${USERNAME} in the tests for programatic testing. + +*Regression tests* +- Add your feature to the [test-features.env](script-library/container-features/test-features.env) file to include it in regression tests of the container-feature functionality. By setting the `_VSC_INSTALL_` ENV VAR to true and adding the expected _BUILD_ARG options for your feature. + +EG +``` + _VSC_INSTALL_DOTNET=true + _BUILD_ARG_DOTNET_VERSION=latest + _BUILD_ARG_DOTNET_RUNTIMEONLY=false +``` + +**Feature documentation** + +Add your new feature to the list of scripts in the [script-library README.md](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/README.md#scripts). + +Add documentation for your new feature script to the [script-library/docs](https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs) directory. + +Documentation should include: +- the status of the script, supported operating systems, and maintainer. +- the syntax expected to run as a feature or script +- a description of the script arguments +- detailed usage instructions + +Feel free to use other scripts in that directory as inspiration. + +### Best practices for writing feature install scripts + +- Decouple sections of the shellscript that handle user setup, helper functions, and feature installation. Doing so will apply a logical and natural flow to the script for future developers and maintainers to follow. One way to denote this distinction is to use in-line comments throughout the script. + ```md + # Logical flow recommended: + 1. File header and description. + 2. Define constants and default values. + 3. User setup and user validation. + 4. Helper functions. + 5. Checks for dependencies being installed or installs dependencies. + 6. Runs container feature installs. + 7. Gives the user correct permissions if necessary. + ``` + +- One way to make troubleshooting the script easier when writing a bash shell script is to echo error messages to `STDERR`. A possible way we implemented this in bash scripts is to create an `err()` function like so: + ```sh + # Setup STDERR. + err() { + echo "(!) $*" >&2 + } + err "Something went wrong!" + exit 1 + ``` + +- If writing a bash shellscript, we recommend using double quotes and braces when referencing named variables: + ```sh + variable="My example var" + echo "${variable}" + ``` + +- One method to to ensure the global space in a script is not too crowded with unnecessary variables is to assign return values from functions to a new variable, and use the keyword `local` for vars inside of functions. For example: + ```sh + test_function() { + local test = "hello world!" + echo "${test}" + } + global_test=$(test_function) + ``` + +- If using temporary files within the script, we recommend removing all those files once they are no longer needed. One method for doing this is running a cleanup function with a `trap` method when the script exits: + ```sh + # Cleanup temporary directory and associated files when exiting the script. + cleanup() { + EXIT_CODE=$? + set +e + if [[ -n "${TMP_DIR}" ]]; then + echo "Executing cleanup of tmp files" + rm -Rf "${TMP_DIR}" + fi + exit $EXIT_CODE + } + trap cleanup EXIT + ``` + +- Consider using [shellcheck](https://github.com/koalaman/shellcheck) or the [vscode-shellcheck extension](https://github.com/vscode-shellcheck/vscode-shellcheck) to apply linting and static code analysis to the bash script to ensure it is formatted correctly. + +- Consider using common helper functions from [shared/utils.sh](script-library/shared/utils.sh) when managing common tasks (like updating PATH variables, or managing gpg keys) by copying them directly into your script. + - NOTE: This is done to minimize the impact that any change can have on existing working scripts. + - Similarly, if you add a helper function to your script that could benefit others in the future, consider adding it to the `shared/utils.sh` file as well. + +- [shared/settings.env](script-library/shared/settings.env) contains shared environment variables used in many install scripts, such as `GPG Keys` and `Archive Architectures`. Consider adding your new env. variables to this script when applicable, or reusing existing variables when pertinent. \ No newline at end of file From b8c302a1f4691b752f22ea3259f8c219f1ea6512 Mon Sep 17 00:00:00 2001 From: Kristjana Popovski Date: Tue, 22 Feb 2022 11:46:08 -0500 Subject: [PATCH 09/14] changes to container feature script --- script-library/ruby-debian.sh | 45 +++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/script-library/ruby-debian.sh b/script-library/ruby-debian.sh index 9908510012..6f11aba990 100755 --- a/script-library/ruby-debian.sh +++ b/script-library/ruby-debian.sh @@ -7,11 +7,13 @@ # Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/ruby.md # Maintainer: The VS Code and Codespaces Teams # -# Syntax: ./ruby-debian.sh [Ruby version] [non-root user] [Add to rc files flag] [Install tools flag] +# Syntax: ./ruby-debian.sh [Ruby version] [non-root user] [Add to rc files flag] [rbenv enabled] [RVM enabled] [Install tools flag] RUBY_VERSION=${1:-"latest"} USERNAME=${2:-"automatic"} UPDATE_RC=${3:-"true"} +RBENV_ENABLED=${4:-"true"} +RVM_ENABLED=${5:-"true"} INSTALL_RUBY_TOOLS=${6:-"true"} # Note: ruby-debug-ide will install the right version of debase if missing and @@ -236,8 +238,11 @@ if [ "${INSTALL_RUBY_TOOLS}" = "true" ]; then su ${USERNAME} -c ". /usr/local/rvm/scripts/rvm && \"$(which gem || echo ${ROOT_GEM})\" install ${DEFAULT_GEMS}" fi -# VS Code server usually first in the path, so silence annoying rvm warning (that does not apply) and then source it -updaterc "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi\nsource /usr/local/rvm/scripts/rvm > /dev/null 2>&1" +if [ "${RVM_ENABLED}" = "true" ]; then + echo "Enabling RVM usage" + # VS Code server usually first in the path, so silence annoying rvm warning (that does not apply) and then source it + updaterc "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi\nsource /usr/local/rvm/scripts/rvm > /dev/null 2>&1" +fi # Install rbenv/ruby-build for good measure git clone --depth=1 \ @@ -247,21 +252,25 @@ git clone --depth=1 \ -c fetch.fsck.zeroPaddedFilemode=ignore \ -c receive.fsck.zeroPaddedFilemode=ignore \ https://github.com/rbenv/rbenv.git /usr/local/share/rbenv -ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin -updaterc 'eval "$(rbenv init -)"' -git clone --depth=1 \ - -c core.eol=lf \ - -c core.autocrlf=false \ - -c fsck.zeroPaddedFilemode=ignore \ - -c fetch.fsck.zeroPaddedFilemode=ignore \ - -c receive.fsck.zeroPaddedFilemode=ignore \ - https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build -mkdir -p /root/.rbenv/plugins -ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build -if [ "${USERNAME}" != "root" ]; then - mkdir -p /home/${USERNAME}/.rbenv/plugins - chown -R ${USERNAME} /home/${USERNAME}/.rbenv - ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build + +if [ "${RBENV_ENABLED}" = "true" ]; then + echo "Enabling rbenv usage" + ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin + updaterc 'eval "$(rbenv init -)"' + git clone --depth=1 \ + -c core.eol=lf \ + -c core.autocrlf=false \ + -c fsck.zeroPaddedFilemode=ignore \ + -c fetch.fsck.zeroPaddedFilemode=ignore \ + -c receive.fsck.zeroPaddedFilemode=ignore \ + https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build + mkdir -p /root/.rbenv/plugins + ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build + if [ "${USERNAME}" != "root" ]; then + mkdir -p /home/${USERNAME}/.rbenv/plugins + chown -R ${USERNAME} /home/${USERNAME}/.rbenv + ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build + fi fi # Clean up From 6387b3b9a632d7c11ece74d8281ff1a7d852690f Mon Sep 17 00:00:00 2001 From: Kristjana Popovski Date: Mon, 28 Feb 2022 11:36:33 -0500 Subject: [PATCH 10/14] testing ruby rvm installation --- .../library-scripts/ruby-debian.sh | 21 ++++++---- script-library/ruby-debian.sh | 42 +++++++++++-------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh b/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh index 9908510012..8b72a1bd3a 100755 --- a/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh +++ b/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh @@ -225,7 +225,7 @@ else # Install rvm curl -sSL https://get.rvm.io | bash -s stable --ignore-dotfiles ${RVM_INSTALL_ARGS} --with-default-gems="${DEFAULT_GEMS}" 2>&1 usermod -aG rvm ${USERNAME} - su ${USERNAME} -c ". /usr/local/rvm/scripts/rvm && rvm fix-permissions system" + su ${USERNAME} -c "/usr/local/rvm/scripts/rvm fix-permissions system" rm -rf ${GNUPGHOME} fi @@ -233,11 +233,12 @@ if [ "${INSTALL_RUBY_TOOLS}" = "true" ]; then # Non-root user may not have "gem" in path when script is run and no ruby version # is installed by rvm, so handle this by using root's default gem in this case ROOT_GEM='$(which gem || echo "")' - su ${USERNAME} -c ". /usr/local/rvm/scripts/rvm && \"$(which gem || echo ${ROOT_GEM})\" install ${DEFAULT_GEMS}" + su ${USERNAME} -c "\"$(which gem || echo ${ROOT_GEM})\" install ${DEFAULT_GEMS}" fi # VS Code server usually first in the path, so silence annoying rvm warning (that does not apply) and then source it -updaterc "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi\nsource /usr/local/rvm/scripts/rvm > /dev/null 2>&1" +updaterc "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi" +# \nsource /usr/local/rvm/scripts/rvm > /dev/null 2>&1 # Install rbenv/ruby-build for good measure git clone --depth=1 \ @@ -247,8 +248,12 @@ git clone --depth=1 \ -c fetch.fsck.zeroPaddedFilemode=ignore \ -c receive.fsck.zeroPaddedFilemode=ignore \ https://github.com/rbenv/rbenv.git /usr/local/share/rbenv -ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin -updaterc 'eval "$(rbenv init -)"' + +updaterc 'if [ "${RBENV_ENABLED}" = "true" ]; then + ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin + eval "$(rbenv init -)" +fi' + git clone --depth=1 \ -c core.eol=lf \ -c core.autocrlf=false \ @@ -265,7 +270,9 @@ if [ "${USERNAME}" != "root" ]; then fi # Clean up -source /usr/local/rvm/scripts/rvm -rvm cleanup all +updaterc 'if [ "${RVM_ENABLED}" = "true" ]; then + source /usr/local/rvm/scripts/rvm +fi' +/usr/local/rvm/scripts/rvm cleanup all gem cleanup echo "Done!" diff --git a/script-library/ruby-debian.sh b/script-library/ruby-debian.sh index 6f11aba990..5c7f0cb580 100755 --- a/script-library/ruby-debian.sh +++ b/script-library/ruby-debian.sh @@ -12,8 +12,6 @@ RUBY_VERSION=${1:-"latest"} USERNAME=${2:-"automatic"} UPDATE_RC=${3:-"true"} -RBENV_ENABLED=${4:-"true"} -RVM_ENABLED=${5:-"true"} INSTALL_RUBY_TOOLS=${6:-"true"} # Note: ruby-debug-ide will install the right version of debase if missing and @@ -238,11 +236,12 @@ if [ "${INSTALL_RUBY_TOOLS}" = "true" ]; then su ${USERNAME} -c ". /usr/local/rvm/scripts/rvm && \"$(which gem || echo ${ROOT_GEM})\" install ${DEFAULT_GEMS}" fi -if [ "${RVM_ENABLED}" = "true" ]; then - echo "Enabling RVM usage" - # VS Code server usually first in the path, so silence annoying rvm warning (that does not apply) and then source it - updaterc "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi\nsource /usr/local/rvm/scripts/rvm > /dev/null 2>&1" -fi + +##TODO +# VS Code server usually first in the path, so silence annoying rvm warning (that does not apply) and then source it +updaterc $'if [ "${RVM_ENABLED}" = "true" ]; then + "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi\nsource /usr/local/rvm/scripts/rvm > /dev/null 2>&1" +fi' # Install rbenv/ruby-build for good measure git clone --depth=1 \ @@ -253,17 +252,21 @@ git clone --depth=1 \ -c receive.fsck.zeroPaddedFilemode=ignore \ https://github.com/rbenv/rbenv.git /usr/local/share/rbenv -if [ "${RBENV_ENABLED}" = "true" ]; then - echo "Enabling rbenv usage" +##TODO +updaterc 'if [ "${RBENV_ENABLED}" = "true" ]; then ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin - updaterc 'eval "$(rbenv init -)"' - git clone --depth=1 \ - -c core.eol=lf \ - -c core.autocrlf=false \ - -c fsck.zeroPaddedFilemode=ignore \ - -c fetch.fsck.zeroPaddedFilemode=ignore \ - -c receive.fsck.zeroPaddedFilemode=ignore \ - https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build + eval "$(rbenv init -)" +fi' + +git clone --depth=1 \ + -c core.eol=lf \ + -c core.autocrlf=false \ + -c fsck.zeroPaddedFilemode=ignore \ + -c fetch.fsck.zeroPaddedFilemode=ignore \ + -c receive.fsck.zeroPaddedFilemode=ignore \ + https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build + +if [ "${RBENV_ENABLED}" = "true" ]; then mkdir -p /root/.rbenv/plugins ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build if [ "${USERNAME}" != "root" ]; then @@ -274,7 +277,10 @@ if [ "${RBENV_ENABLED}" = "true" ]; then fi # Clean up -source /usr/local/rvm/scripts/rvm +if [ "${RVM_ENABLED}" = "true" ]; then + source /usr/local/rvm/scripts/rvm +fi + rvm cleanup all gem cleanup echo "Done!" From b889371d6b50ff6f988b3d3187bf69993dccac56 Mon Sep 17 00:00:00 2001 From: KanishkT123 Date: Tue, 1 Mar 2022 11:38:38 -0500 Subject: [PATCH 11/14] Working Ruby tools enabled and disabled, with conditionals and variables added to devcontainer.json --- .../ruby/.devcontainer/devcontainer.json | 5 ++ .../library-scripts/ruby-debian.sh | 32 +++++++---- script-library/ruby-debian.sh | 54 ++++++++++--------- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/containers/ruby/.devcontainer/devcontainer.json b/containers/ruby/.devcontainer/devcontainer.json index 9d75e9bf4b..86515e9bd6 100644 --- a/containers/ruby/.devcontainer/devcontainer.json +++ b/containers/ruby/.devcontainer/devcontainer.json @@ -12,6 +12,11 @@ } }, + "containerEnv": { + "RBENV_ENABLED": "false", + "RVM_ENABLED": "false" + }, + // Set *default* container specific settings.json values on container create. "settings": {}, diff --git a/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh b/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh index 8b72a1bd3a..3525d9afbe 100755 --- a/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh +++ b/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh @@ -238,7 +238,6 @@ fi # VS Code server usually first in the path, so silence annoying rvm warning (that does not apply) and then source it updaterc "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi" -# \nsource /usr/local/rvm/scripts/rvm > /dev/null 2>&1 # Install rbenv/ruby-build for good measure git clone --depth=1 \ @@ -249,11 +248,6 @@ git clone --depth=1 \ -c receive.fsck.zeroPaddedFilemode=ignore \ https://github.com/rbenv/rbenv.git /usr/local/share/rbenv -updaterc 'if [ "${RBENV_ENABLED}" = "true" ]; then - ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin - eval "$(rbenv init -)" -fi' - git clone --depth=1 \ -c core.eol=lf \ -c core.autocrlf=false \ @@ -261,18 +255,34 @@ git clone --depth=1 \ -c fetch.fsck.zeroPaddedFilemode=ignore \ -c receive.fsck.zeroPaddedFilemode=ignore \ https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build + mkdir -p /root/.rbenv/plugins -ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build + if [ "${USERNAME}" != "root" ]; then mkdir -p /home/${USERNAME}/.rbenv/plugins - chown -R ${USERNAME} /home/${USERNAME}/.rbenv - ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build fi -# Clean up -updaterc 'if [ "${RVM_ENABLED}" = "true" ]; then +# Update bashrc and zshrc with conditionals +# We use "not false" so that the default state is true, i.e., enabled +updaterc 'if [ "${RVM_ENABLED}" != "false" ]; then source /usr/local/rvm/scripts/rvm fi' + +if [ "${USERNAME}" != "root" ]; then + mkdir -p /home/${USERNAME}/.rbenv/plugins + updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then + chown -R ${USERNAME} /home/${USERNAME}/.rbenv + ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build + fi' +fi + +updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then + sudo ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin + eval "$(rbenv init -)" + sudo ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build +fi' + +# Clean up /usr/local/rvm/scripts/rvm cleanup all gem cleanup echo "Done!" diff --git a/script-library/ruby-debian.sh b/script-library/ruby-debian.sh index 5c7f0cb580..3525d9afbe 100755 --- a/script-library/ruby-debian.sh +++ b/script-library/ruby-debian.sh @@ -7,7 +7,7 @@ # Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/ruby.md # Maintainer: The VS Code and Codespaces Teams # -# Syntax: ./ruby-debian.sh [Ruby version] [non-root user] [Add to rc files flag] [rbenv enabled] [RVM enabled] [Install tools flag] +# Syntax: ./ruby-debian.sh [Ruby version] [non-root user] [Add to rc files flag] [Install tools flag] RUBY_VERSION=${1:-"latest"} USERNAME=${2:-"automatic"} @@ -225,7 +225,7 @@ else # Install rvm curl -sSL https://get.rvm.io | bash -s stable --ignore-dotfiles ${RVM_INSTALL_ARGS} --with-default-gems="${DEFAULT_GEMS}" 2>&1 usermod -aG rvm ${USERNAME} - su ${USERNAME} -c ". /usr/local/rvm/scripts/rvm && rvm fix-permissions system" + su ${USERNAME} -c "/usr/local/rvm/scripts/rvm fix-permissions system" rm -rf ${GNUPGHOME} fi @@ -233,15 +233,11 @@ if [ "${INSTALL_RUBY_TOOLS}" = "true" ]; then # Non-root user may not have "gem" in path when script is run and no ruby version # is installed by rvm, so handle this by using root's default gem in this case ROOT_GEM='$(which gem || echo "")' - su ${USERNAME} -c ". /usr/local/rvm/scripts/rvm && \"$(which gem || echo ${ROOT_GEM})\" install ${DEFAULT_GEMS}" + su ${USERNAME} -c "\"$(which gem || echo ${ROOT_GEM})\" install ${DEFAULT_GEMS}" fi - -##TODO # VS Code server usually first in the path, so silence annoying rvm warning (that does not apply) and then source it -updaterc $'if [ "${RVM_ENABLED}" = "true" ]; then - "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi\nsource /usr/local/rvm/scripts/rvm > /dev/null 2>&1" -fi' +updaterc "if ! grep rvm_silence_path_mismatch_check_flag \$HOME/.rvmrc > /dev/null 2>&1; then echo 'rvm_silence_path_mismatch_check_flag=1' >> \$HOME/.rvmrc; fi" # Install rbenv/ruby-build for good measure git clone --depth=1 \ @@ -252,12 +248,6 @@ git clone --depth=1 \ -c receive.fsck.zeroPaddedFilemode=ignore \ https://github.com/rbenv/rbenv.git /usr/local/share/rbenv -##TODO -updaterc 'if [ "${RBENV_ENABLED}" = "true" ]; then - ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin - eval "$(rbenv init -)" -fi' - git clone --depth=1 \ -c core.eol=lf \ -c core.autocrlf=false \ @@ -265,22 +255,34 @@ git clone --depth=1 \ -c fetch.fsck.zeroPaddedFilemode=ignore \ -c receive.fsck.zeroPaddedFilemode=ignore \ https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build - -if [ "${RBENV_ENABLED}" = "true" ]; then - mkdir -p /root/.rbenv/plugins - ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build - if [ "${USERNAME}" != "root" ]; then - mkdir -p /home/${USERNAME}/.rbenv/plugins + +mkdir -p /root/.rbenv/plugins + +if [ "${USERNAME}" != "root" ]; then + mkdir -p /home/${USERNAME}/.rbenv/plugins +fi + +# Update bashrc and zshrc with conditionals +# We use "not false" so that the default state is true, i.e., enabled +updaterc 'if [ "${RVM_ENABLED}" != "false" ]; then + source /usr/local/rvm/scripts/rvm +fi' + +if [ "${USERNAME}" != "root" ]; then + mkdir -p /home/${USERNAME}/.rbenv/plugins + updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then chown -R ${USERNAME} /home/${USERNAME}/.rbenv ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build - fi + fi' fi -# Clean up -if [ "${RVM_ENABLED}" = "true" ]; then - source /usr/local/rvm/scripts/rvm -fi +updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then + sudo ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin + eval "$(rbenv init -)" + sudo ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build +fi' -rvm cleanup all +# Clean up +/usr/local/rvm/scripts/rvm cleanup all gem cleanup echo "Done!" From 4c04305ccb1f8cf9b4db972478295a1b467bf969 Mon Sep 17 00:00:00 2001 From: KanishkT123 Date: Wed, 2 Mar 2022 11:35:01 -0500 Subject: [PATCH 12/14] RM -f symlinks and changes per reviewer comments --- .../.devcontainer/library-scripts/ruby-debian.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh b/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh index 3525d9afbe..ebe5904455 100755 --- a/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh +++ b/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh @@ -268,19 +268,25 @@ updaterc 'if [ "${RVM_ENABLED}" != "false" ]; then source /usr/local/rvm/scripts/rvm fi' +# All commands have the output redirected to /dev/null so that there is no output on shell startup. if [ "${USERNAME}" != "root" ]; then mkdir -p /home/${USERNAME}/.rbenv/plugins updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then chown -R ${USERNAME} /home/${USERNAME}/.rbenv - ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build + ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build > /dev/null 2>&1 + else + rm -f /home/${USERNAME}/.rbenv/plugins/ruby-build > /dev/null 2>&1 fi' fi updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then - sudo ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin - eval "$(rbenv init -)" - sudo ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build -fi' + sudo ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin > /dev/null 2>&1 + eval "$(rbenv init -)" + sudo ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build > /dev/null 2>&1 + else + rm -f /root/.rbenv/plugins/ruby-build > /dev/null 2>&1 + rm -f /usr/local/bin/rbenv > /dev/null 2>&1 + fi' # Clean up /usr/local/rvm/scripts/rvm cleanup all From 46a7e87cb7cc1abde82f23e4b4446b1b5f66d9ce Mon Sep 17 00:00:00 2001 From: KanishkT123 Date: Wed, 2 Mar 2022 11:39:41 -0500 Subject: [PATCH 13/14] Default enabled in devcontainer.json and updated README --- .../ruby/.devcontainer/devcontainer.json | 4 +-- containers/ruby/README.md | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/containers/ruby/.devcontainer/devcontainer.json b/containers/ruby/.devcontainer/devcontainer.json index 86515e9bd6..bae30e2731 100644 --- a/containers/ruby/.devcontainer/devcontainer.json +++ b/containers/ruby/.devcontainer/devcontainer.json @@ -13,8 +13,8 @@ }, "containerEnv": { - "RBENV_ENABLED": "false", - "RVM_ENABLED": "false" + "RBENV_ENABLED": "true", + "RVM_ENABLED": "true" }, // Set *default* container specific settings.json values on container create. diff --git a/containers/ruby/README.md b/containers/ruby/README.md index 13f84bba4e..eee9af8a26 100644 --- a/containers/ruby/README.md +++ b/containers/ruby/README.md @@ -61,6 +61,33 @@ Given JavaScript front-end web client code written for use in conjunction with a } ``` +### Enabling and Disabling Ruby Version Managers (RVM and RBENV) + +This Dev Container comes pre-packaged with a `ruby-debian.sh` shell script which installs `rbenv` and `rvm`. Both tools and their configuration files are enabled in the devcontainer by default. If you want to use them, simply start the container as normal. You can test the `rbenv` installation by running: + +```bash +rbenv -v +``` + +And the `rvm` installation by running: + +```bash +rvm -v +``` + +These commands can be run in the integrated terminal. + +To disable these tools, change the `containerEnv` variables in `devcontainer.json`: + +```jsonc +"containerEnv": { + "RBENV_ENABLED": "false", + "RVM_ENABLED": "false" +}, +``` + +These variables need to be explicitly set to `false` for the tools to be disabled. Any other input will result in `rvm` and `rbenv` being enabled for the container. + ### Adding the definition to your folder 1. If this is your first time using a development container, please see getting started information on [setting up](https://aka.ms/vscode-remote/containers/getting-started) Remote-Containers or [creating a codespace](https://aka.ms/ghcs-open-codespace) using GitHub Codespaces. From f04e329ddfc491a8a27edde3fa6c16f7235dfb95 Mon Sep 17 00:00:00 2001 From: KanishkT123 Date: Fri, 4 Mar 2022 10:27:47 -0500 Subject: [PATCH 14/14] Changed scripts per reviewer comments --- .../library-scripts/ruby-debian.sh | 20 ++++--------------- script-library/ruby-debian.sh | 18 ++++++----------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh b/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh index ebe5904455..bb22596e65 100755 --- a/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh +++ b/containers/ruby/.devcontainer/library-scripts/ruby-debian.sh @@ -257,9 +257,12 @@ git clone --depth=1 \ https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build mkdir -p /root/.rbenv/plugins +ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build if [ "${USERNAME}" != "root" ]; then mkdir -p /home/${USERNAME}/.rbenv/plugins + chown -R ${USERNAME} /home/${USERNAME}/.rbenv + ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build fi # Update bashrc and zshrc with conditionals @@ -268,24 +271,9 @@ updaterc 'if [ "${RVM_ENABLED}" != "false" ]; then source /usr/local/rvm/scripts/rvm fi' -# All commands have the output redirected to /dev/null so that there is no output on shell startup. -if [ "${USERNAME}" != "root" ]; then - mkdir -p /home/${USERNAME}/.rbenv/plugins - updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then - chown -R ${USERNAME} /home/${USERNAME}/.rbenv - ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build > /dev/null 2>&1 - else - rm -f /home/${USERNAME}/.rbenv/plugins/ruby-build > /dev/null 2>&1 - fi' -fi - updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then - sudo ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin > /dev/null 2>&1 + export PATH=$PATH:/usr/local/share/rbenv/bin eval "$(rbenv init -)" - sudo ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build > /dev/null 2>&1 - else - rm -f /root/.rbenv/plugins/ruby-build > /dev/null 2>&1 - rm -f /usr/local/bin/rbenv > /dev/null 2>&1 fi' # Clean up diff --git a/script-library/ruby-debian.sh b/script-library/ruby-debian.sh index 3525d9afbe..bb22596e65 100755 --- a/script-library/ruby-debian.sh +++ b/script-library/ruby-debian.sh @@ -257,9 +257,12 @@ git clone --depth=1 \ https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build mkdir -p /root/.rbenv/plugins +ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build if [ "${USERNAME}" != "root" ]; then mkdir -p /home/${USERNAME}/.rbenv/plugins + chown -R ${USERNAME} /home/${USERNAME}/.rbenv + ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build fi # Update bashrc and zshrc with conditionals @@ -268,19 +271,10 @@ updaterc 'if [ "${RVM_ENABLED}" != "false" ]; then source /usr/local/rvm/scripts/rvm fi' -if [ "${USERNAME}" != "root" ]; then - mkdir -p /home/${USERNAME}/.rbenv/plugins - updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then - chown -R ${USERNAME} /home/${USERNAME}/.rbenv - ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build - fi' -fi - updaterc 'if [ "${RBENV_ENABLED}" != "false" ]; then - sudo ln -s /usr/local/share/rbenv/bin/rbenv /usr/local/bin - eval "$(rbenv init -)" - sudo ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build -fi' + export PATH=$PATH:/usr/local/share/rbenv/bin + eval "$(rbenv init -)" + fi' # Clean up /usr/local/rvm/scripts/rvm cleanup all