Merge branch 'main' into aws-cli-ssm-plugin

This commit is contained in:
YuanXiao W 2023-09-26 21:58:07 +08:00 committed by GitHub
commit c586ca57eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 3456 additions and 946 deletions

View file

@ -0,0 +1,37 @@
name: "Stress test - Docker in Docker"
on:
pull_request:
paths:
- 'src/docker-in-docker/**'
workflow_dispatch:
jobs:
test:
strategy:
matrix:
test-pass: [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50 ]
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: "Install latest devcontainer CLI"
run: npm install -g @devcontainers/cli
- name: "Generating tests for 'docker-in-docker' which validates if docker daemon is running"
run: devcontainer features test --skip-scenarios -f docker-in-docker -i mcr.microsoft.com/devcontainers/base:ubuntu .
test-onCreate:
strategy:
matrix:
test-pass: [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50 ]
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: "Install latest devcontainer CLI"
run: npm install -g @devcontainers/cli
- name: "Generating tests for 'docker-in-docker' which validates if docker daemon is available within 'onCreateCommand'"
run: devcontainer features test -f docker-in-docker --skip-autogenerated --filter "docker_with_on_create_command"

View file

@ -42,7 +42,6 @@ jobs:
]
baseImage:
[
"ubuntu:bionic",
"ubuntu:focal",
"ubuntu:jammy",
"debian:11",
@ -112,4 +111,4 @@ jobs:
run: npm install -g @devcontainers/cli
- name: "Testing global scenarios"
run: devcontainer features test --global-scenarios-only .
run: devcontainer features test --global-scenarios-only .

View file

@ -49,7 +49,6 @@ jobs:
features: ${{ fromJSON(needs.detect-changes.outputs.features) }}
baseImage:
[
"ubuntu:bionic",
"ubuntu:focal",
"ubuntu:jammy",
"debian:11",
@ -80,4 +79,4 @@ jobs:
run: npm install -g @devcontainers/cli
- name: "Testing '${{ matrix.features }}' scenarios"
run: devcontainer features test -f ${{ matrix.features }} --skip-autogenerated .
run: devcontainer features test -f ${{ matrix.features }} --skip-autogenerated .

View file

@ -0,0 +1,49 @@
name: "Updates vendor 'dotnet-install' script"
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # Runs every Sunday at midnight UTC (adjust as needed)
jobs:
fetch-latest-dotnet-install:
runs-on: ubuntu-latest
environment: documentation # grants access to secrets.PAT, for creating pull requests
steps:
- uses: actions/checkout@v3
- name: Run fetch-latest-dotnet-install.sh
run: src/dotnet/scripts/fetch-latest-dotnet-install.sh
- name: Create a PR for dotnet-install.sh
id: push_image_info
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
run: |
set -e
echo "Start."
# Configure git and Push updates
git config --global user.email github-actions@github.com
git config --global user.name github-actions
git config pull.rebase false
branch=automated-script-update-$GITHUB_RUN_ID
git checkout -b $branch
message='[Updates] Automated vendor 'dotnet-install' script'
# Add / update and commit
git add src/dotnet/scripts/vendor/dotnet-install.sh
git commit -m 'Automated dotnet-install script update' || export NO_UPDATES=true
# Push
if [ "$NO_UPDATES" != "true" ] ; then
git push origin "$branch"
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
/repos/${GITHUB_REPOSITORY}/pulls \
-f title="$message" \
-f body="$message" \
-f head="$branch" \
-f base="$GITHUB_REF_NAME"
fi

View file

@ -18,7 +18,7 @@ Installs the Azure CLI along with needed dependencies. Useful for base Dockerfil
| version | Select or enter an Azure CLI version. (Available versions may vary by Linux distribution.) | string | latest |
| extensions | Optional comma separated list of Azure CLI extensions to install in profile. | string | - |
| installBicep | Optionally install Azure Bicep | boolean | false |
| installUsingPython | Install Azure CLI using Python instead of pipx | boolean | true |
| installUsingPython | Install Azure CLI using Python instead of pipx | boolean | false |
## Customizations

View file

@ -1,6 +1,6 @@
{
"id": "azure-cli",
"version": "1.2.0",
"version": "1.2.1",
"name": "Azure CLI",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/azure-cli",
"description": "Installs the Azure CLI along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like gpg.",
@ -26,7 +26,7 @@
"installUsingPython": {
"type": "boolean",
"description": "Install Azure CLI using Python instead of pipx",
"default": true
"default": false
}
},
"customizations": {

View file

@ -141,7 +141,6 @@ install_using_pip_strategy() {
ver="==${AZ_VERSION}"
fi
# Temprary quick fix for https://github.com/devcontainers/features/issues/624
if [ "${INSTALL_USING_PYTHON}" = "true" ]; then
install_with_complete_python_installation "${ver}" || install_with_pipx "${ver}" || return 1
else

View file

@ -18,6 +18,7 @@ Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-r
| installZsh | Install ZSH? | boolean | true |
| configureZshAsDefaultShell | Change default shell to ZSH? | boolean | false |
| installOhMyZsh | Install Oh My Zsh!? | boolean | true |
| installOhMyZshConfig | Allow installing the default dev container .zshrc templates? | boolean | true |
| upgradePackages | Upgrade OS packages? | boolean | true |
| username | Enter name of a non-root user to configure or none to skip | string | automatic |
| userUid | Enter UID for non-root user | string | automatic |

View file

@ -1,6 +1,6 @@
{
"id": "common-utils",
"version": "2.0.10",
"version": "2.1.3",
"name": "Common Utilities",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/common-utils",
"description": "Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user.",
@ -20,6 +20,11 @@
"default": true,
"description": "Install Oh My Zsh!?"
},
"installOhMyZshConfig": {
"type": "boolean",
"default": true,
"description": "Allow installing the default dev container .zshrc templates?"
},
"upgradePackages": {
"type": "boolean",
"default": true,

View file

@ -12,6 +12,7 @@ set -e
INSTALL_ZSH="${INSTALLZSH:-"true"}"
CONFIGURE_ZSH_AS_DEFAULT_SHELL="${CONFIGUREZSHASDEFAULTSHELL:-"false"}"
INSTALL_OH_MY_ZSH="${INSTALLOHMYZSH:-"true"}"
INSTALL_OH_MY_ZSH_CONFIG="${INSTALLOHMYZSHCONFIG:-"true"}"
UPGRADE_PACKAGES="${UPGRADEPACKAGES:-"true"}"
USERNAME="${USERNAME:-"automatic"}"
USER_UID="${UID:-"automatic"}"

View file

@ -12,6 +12,7 @@ set -e
INSTALL_ZSH="${INSTALLZSH:-"true"}"
CONFIGURE_ZSH_AS_DEFAULT_SHELL="${CONFIGUREZSHASDEFAULTSHELL:-"false"}"
INSTALL_OH_MY_ZSH="${INSTALLOHMYZSH:-"true"}"
INSTALL_OH_MY_ZSH_CONFIG="${INSTALLOHMYZSHCONFIG:-"true"}"
UPGRADE_PACKAGES="${UPGRADEPACKAGES:-"true"}"
USERNAME="${USERNAME:-"automatic"}"
USER_UID="${USERUID:-"automatic"}"
@ -27,7 +28,10 @@ install_debian_packages() {
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
local package_list="apt-utils \
local package_list=""
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
package_list="${package_list} \
apt-utils \
openssh-client \
gnupg2 \
dirmngr \
@ -69,6 +73,34 @@ install_debian_packages() {
manpages-dev \
init-system-helpers"
# Include libssl1.1 if available
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
package_list="${package_list} libssl1.1"
fi
# Include libssl3 if available
if [[ ! -z $(apt-cache --names-only search ^libssl3$) ]]; then
package_list="${package_list} libssl3"
fi
# Include appropriate version of libssl1.0.x if available
local libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
if [ "$(echo "$libssl_package" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
# Debian 9
package_list="${package_list} libssl1.0.2"
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
# Ubuntu 18.04
package_list="${package_list} libssl1.0.0"
fi
fi
# Include git if not already installed (may be more recent than distro version)
if ! type git > /dev/null 2>&1; then
package_list="${package_list} git"
fi
fi
# Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian
if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then
# Bring in variables from /etc/os-release like VERSION_CODENAME
@ -87,33 +119,6 @@ install_debian_packages() {
package_list="${package_list} manpages-posix manpages-posix-dev"
fi
# Include libssl1.1 if available
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
package_list="${package_list} libssl1.1"
fi
# Include libssl3 if available
if [[ ! -z $(apt-cache --names-only search ^libssl3$) ]]; then
package_list="${package_list} libssl3"
fi
# Include appropriate version of libssl1.0.x if available
local libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
if [ "$(echo "$libssl_package" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
# Debian 9
package_list="${package_list} libssl1.0.2"
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
# Ubuntu 18.04
package_list="${package_list} libssl1.0.0"
fi
fi
# Include git if not already installed (may be more recent than distro version)
if ! type git > /dev/null 2>&1; then
package_list="${package_list} git"
fi
# Install the list of packages
echo "Packages to verify are installed: ${package_list}"
rm -rf /var/lib/apt/lists/*
@ -138,6 +143,8 @@ install_debian_packages() {
LOCALE_ALREADY_SET="true"
fi
PACKAGES_ALREADY_INSTALLED="true"
# Clean up
apt-get -y clean
rm -rf /var/lib/apt/lists/*
@ -145,34 +152,42 @@ install_debian_packages() {
# RedHat / RockyLinux / CentOS / Fedora packages
install_redhat_packages() {
local package_list="\
gawk \
openssh-clients \
gnupg2 \
iproute \
procps \
lsof \
net-tools \
psmisc \
wget \
ca-certificates \
rsync \
unzip \
zip \
nano \
vim-minimal \
less \
jq \
openssl-libs \
krb5-libs \
libicu \
zlib \
sudo \
sed \
grep \
which \
man-db \
strace"
local package_list=""
local remove_epel="false"
local install_cmd=dnf
if ! type dnf > /dev/null 2>&1; then
install_cmd=yum
fi
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
package_list="${package_list} \
gawk \
openssh-clients \
gnupg2 \
iproute \
procps \
lsof \
net-tools \
psmisc \
wget \
ca-certificates \
rsync \
unzip \
zip \
nano \
vim-minimal \
less \
jq \
openssl-libs \
krb5-libs \
libicu \
zlib \
sudo \
sed \
grep \
which \
man-db \
strace"
# rockylinux:9 installs 'curl-minimal' which clashes with 'curl'
# Install 'curl' for every OS except this rockylinux:9
@ -180,19 +195,26 @@ install_redhat_packages() {
package_list="${package_list} curl"
fi
# Install OpenSSL 1.0 compat if needed
if ${install_cmd} -q list compat-openssl10 >/dev/null 2>&1; then
package_list="${package_list} compat-openssl10"
fi
# Install OpenSSL 1.0 compat if needed
if ${install_cmd} -q list compat-openssl10 >/dev/null 2>&1; then
package_list="${package_list} compat-openssl10"
fi
# Install lsb_release if available
if ${install_cmd} -q list redhat-lsb-core >/dev/null 2>&1; then
package_list="${package_list} redhat-lsb-core"
fi
# Install lsb_release if available
if ${install_cmd} -q list redhat-lsb-core >/dev/null 2>&1; then
package_list="${package_list} redhat-lsb-core"
fi
# Install git if not already installed (may be more recent than distro version)
if ! type git > /dev/null 2>&1; then
package_list="${package_list} git"
# Install git if not already installed (may be more recent than distro version)
if ! type git > /dev/null 2>&1; then
package_list="${package_list} git"
fi
# Install EPEL repository if needed (required to install 'jq' for CentOS)
if ! ${install_cmd} -q list jq >/dev/null 2>&1; then
${install_cmd} -y install epel-release
remove_epel="true"
fi
fi
# Install zsh if needed
@ -200,73 +222,80 @@ install_redhat_packages() {
package_list="${package_list} zsh"
fi
local install_cmd=dnf
if ! type dnf > /dev/null 2>&1; then
install_cmd=yum
fi
${install_cmd} -y install ${package_list}
# Get to latest versions of all packages
if [ "${UPGRADE_PACKAGES}" = "true" ]; then
${install_cmd} upgrade -y
fi
if [[ "${remove_epel}" = "true" ]]; then
${install_cmd} -y remove epel-release
fi
PACKAGES_ALREADY_INSTALLED="true"
}
# Alpine Linux packages
install_alpine_packages() {
apk update
apk add --no-cache \
openssh-client \
gnupg \
procps \
lsof \
htop \
net-tools \
psmisc \
curl \
wget \
rsync \
ca-certificates \
unzip \
zip \
nano \
vim \
less \
jq \
libgcc \
libstdc++ \
krb5-libs \
libintl \
libssl1.1 \
lttng-ust \
tzdata \
userspace-rcu \
zlib \
sudo \
coreutils \
sed \
grep \
which \
ncdu \
shadow \
strace
# Install man pages - package name varies between 3.12 and earlier versions
if apk info man > /dev/null 2>&1; then
apk add --no-cache man man-pages
else
apk add --no-cache mandoc man-pages
fi
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
apk add --no-cache \
openssh-client \
gnupg \
procps \
lsof \
htop \
net-tools \
psmisc \
curl \
wget \
rsync \
ca-certificates \
unzip \
zip \
nano \
vim \
less \
jq \
libgcc \
libstdc++ \
krb5-libs \
libintl \
libssl1.1 \
lttng-ust \
tzdata \
userspace-rcu \
zlib \
sudo \
coreutils \
sed \
grep \
which \
ncdu \
shadow \
strace
# Install git if not already installed (may be more recent than distro version)
if ! type git > /dev/null 2>&1; then
apk add --no-cache git
# Install man pages - package name varies between 3.12 and earlier versions
if apk info man > /dev/null 2>&1; then
apk add --no-cache man man-pages
else
apk add --no-cache mandoc man-pages
fi
# Install git if not already installed (may be more recent than distro version)
if ! type git > /dev/null 2>&1; then
apk add --no-cache git
fi
fi
# Install zsh if needed
if [ "${INSTALL_ZSH}" = "true" ] && ! type zsh > /dev/null 2>&1; then
apk add --no-cache zsh
fi
PACKAGES_ALREADY_INSTALLED="true"
}
# ******************
@ -305,20 +334,17 @@ else
fi
# Install packages for appropriate OS
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
case "${ADJUSTED_ID}" in
"debian")
install_debian_packages
;;
"rhel")
install_redhat_packages
;;
"alpine")
install_alpine_packages
;;
esac
PACKAGES_ALREADY_INSTALLED="true"
fi
case "${ADJUSTED_ID}" in
"debian")
install_debian_packages
;;
"rhel")
install_redhat_packages
;;
"alpine")
install_alpine_packages
;;
esac
# If in automatic mode, determine if a user already exists, if not use vscode
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
@ -390,7 +416,8 @@ else
fi
# Restore user .bashrc / .profile / .zshrc defaults from skeleton file if it doesn't exist or is empty
possible_rc_files=( ".bashrc" ".profile" ".zshrc" )
possible_rc_files=( ".bashrc" ".profile" )
[ "$INSTALL_OH_MY_ZSH_CONFIG" == "true" ] && possible_rc_files+=('.zshrc')
for rc_file in "${possible_rc_files[@]}"; do
if [ -f "/etc/skel/${rc_file}" ]; then
if [ ! -e "${user_home}/${rc_file}" ] || [ ! -s "${user_home}/${rc_file}" ]; then
@ -437,39 +464,56 @@ if [ "${INSTALL_ZSH}" = "true" ]; then
fi
if [ "${CONFIGURE_ZSH_AS_DEFAULT_SHELL}" == "true" ]; then
# Fixing chsh always asking for a password on alpine linux
# ref: https://askubuntu.com/questions/812420/chsh-always-asking-a-password-and-get-pam-authentication-failure.
if [ ! -f "/etc/pam.d/chsh" ] || ! grep -Eq '^auth(.*)pam_rootok\.so$' /etc/pam.d/chsh; then
echo "auth sufficient pam_rootok.so" >> /etc/pam.d/chsh
elif [[ -n "$(awk '/^auth(.*)pam_rootok\.so$/ && !/^auth[[:blank:]]+sufficient[[:blank:]]+pam_rootok\.so$/' /etc/pam.d/chsh)" ]]; then
awk '/^auth(.*)pam_rootok\.so$/ { $2 = "sufficient" } { print }' /etc/pam.d/chsh > /tmp/chsh.tmp && mv /tmp/chsh.tmp /etc/pam.d/chsh
fi
chsh --shell /bin/zsh ${USERNAME}
fi
# Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme.
# See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script.
oh_my_install_dir="${user_home}/.oh-my-zsh"
if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MY_ZSH}" = "true" ]; then
template_path="${oh_my_install_dir}/templates/zshrc.zsh-template"
if [ "${INSTALL_OH_MY_ZSH}" = "true" ]; then
user_rc_file="${user_home}/.zshrc"
umask g-w,o-w
mkdir -p ${oh_my_install_dir}
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/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1
echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file}
sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="devcontainers"/g' ${user_rc_file}
oh_my_install_dir="${user_home}/.oh-my-zsh"
template_path="${oh_my_install_dir}/templates/zshrc.zsh-template"
if [ ! -d "${oh_my_install_dir}" ]; then
umask g-w,o-w
mkdir -p ${oh_my_install_dir}
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/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1
# Shrink git while still enabling updates
cd "${oh_my_install_dir}"
git repack -a -d -f --depth=1 --window=1
fi
# Add Dev Containers theme
mkdir -p ${oh_my_install_dir}/custom/themes
cp -f "${FEATURE_DIR}/scripts/devcontainers.zsh-theme" "${oh_my_install_dir}/custom/themes/devcontainers.zsh-theme"
ln -s "${oh_my_install_dir}/custom/themes/devcontainers.zsh-theme" "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme"
ln -sf "${oh_my_install_dir}/custom/themes/devcontainers.zsh-theme" "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme"
# Add devcontainer .zshrc template
if [ "$INSTALL_OH_MY_ZSH_CONFIG" = "true" ]; then
echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file}
sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="devcontainers"/g' ${user_rc_file}
fi
# Shrink git while still enabling updates
cd "${oh_my_install_dir}"
git repack -a -d -f --depth=1 --window=1
# Copy to non-root user if one is specified
if [ "${USERNAME}" != "root" ]; then
cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root
chown -R ${USERNAME}:${group_name} "${oh_my_install_dir}" "${user_rc_file}"
copy_to_user_files=("${oh_my_install_dir}")
[ -f "$user_rc_file" ] && copy_to_user_files+=("$user_rc_file")
cp -rf "${copy_to_user_files[@]}" /root
chown -R ${USERNAME}:${group_name} "${copy_to_user_files[@]}"
fi
fi
fi

View file

@ -25,7 +25,7 @@ You can also connect to the desktop using a [VNC viewer](https://www.realvnc.com
## Customizing Fluxbox
The window manager is installed is [Fluxbox](http://fluxbox.org/). **Right-click** to see the application menu. In addition, any UI-based commands you execute inside the dev container will automatically appear on the desktop.
The window manager installed is [Fluxbox](http://fluxbox.org/). **Right-click** to see the application menu. In addition, any UI-based commands you execute inside the dev container will automatically appear on the desktop.
You can customize the desktop using Fluxbox configuration files. The configuration files are located in the `.fluxbox` folder of the home directory of the user you using to connect to the dev container (`$HOME/.fluxbox`).

View file

@ -48,7 +48,7 @@ You can also connect to the desktop using a [VNC viewer](https://www.realvnc.com
## Customizing Fluxbox
The window manager is installed is [Fluxbox](http://fluxbox.org/). **Right-click** to see the application menu. In addition, any UI-based commands you execute inside the dev container will automatically appear on the desktop.
The window manager installed is [Fluxbox](http://fluxbox.org/). **Right-click** to see the application menu. In addition, any UI-based commands you execute inside the dev container will automatically appear on the desktop.
You can customize the desktop using Fluxbox configuration files. The configuration files are located in the `.fluxbox` folder of the home directory of the user you using to connect to the dev container (`$HOME/.fluxbox`).

View file

@ -1,6 +1,6 @@
{
"id": "docker-in-docker",
"version": "2.2.1",
"version": "2.5.0",
"name": "Docker (Docker-in-Docker)",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-in-docker",
"description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.",

View file

@ -5,7 +5,7 @@
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md
# Maintainer: The VS Code and Codespaces Teams
# Maintainer: The Dev Container spec maintainers
DOCKER_VERSION="${VERSION:-"latest"}" # The Docker/Moby Engine + CLI should match in version
@ -16,8 +16,8 @@ DOCKER_DEFAULT_ADDRESS_POOL="${DOCKERDEFAULTADDRESSPOOL}"
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}"
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal jammy"
DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal hirsute impish jammy"
DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal jammy"
DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal hirsute impish jammy"
# Default: Exit on any failure.
set -e
@ -367,7 +367,7 @@ dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAU
find /run /var/run -iname 'docker*.pid' -delete || :
find /run /var/run -iname 'container*.pid' -delete || :
## Dind wrapper script from docker team, adapted to a function
# -- Start: dind wrapper script --
# Maintained: https://github.com/moby/moby/blob/master/hack/dind
export container=docker
@ -384,31 +384,52 @@ dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAU
mount -t tmpfs none /tmp
fi
# cgroup v2: enable nesting
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
# move the processes from the root group to the /init group,
# otherwise writing subtree_control fails with EBUSY.
# An error during moving non-existent process (i.e., "cat") is ignored.
mkdir -p /sys/fs/cgroup/init
xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || :
# enable controllers
sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \
> /sys/fs/cgroup/cgroup.subtree_control
fi
## Dind wrapper over.
set_cgroup_nesting()
{
# cgroup v2: enable nesting
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
# move the processes from the root group to the /init group,
# otherwise writing subtree_control fails with EBUSY.
# An error during moving non-existent process (i.e., "cat") is ignored.
mkdir -p /sys/fs/cgroup/init
xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || :
# enable controllers
sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \
> /sys/fs/cgroup/cgroup.subtree_control
fi
}
# Set cgroup nesting, retrying if necessary
retry_cgroup_nesting=0
until [ "${retry_cgroup_nesting}" -eq "5" ];
do
set +e
set_cgroup_nesting
if [ $? -ne 0 ]; then
echo "(*) cgroup v2: Failed to enable nesting, retrying..."
else
break
fi
retry_cgroup_nesting=`expr $retry_cgroup_nesting + 1`
set -e
done
# -- End: dind wrapper script --
# Handle DNS
set +e
cat /etc/resolv.conf | grep -i 'internal.cloudapp.net'
if [ $? -eq 0 ] && [ "${AZURE_DNS_AUTO_DETECTION}" = "true" ]
then
echo "Setting dockerd Azure DNS."
CUSTOMDNS="--dns 168.63.129.16"
else
echo "Not setting dockerd DNS manually."
CUSTOMDNS=""
fi
cat /etc/resolv.conf | grep -i 'internal.cloudapp.net' > /dev/null 2>&1
if [ $? -eq 0 ] && [ "${AZURE_DNS_AUTO_DETECTION}" = "true" ]
then
echo "Setting dockerd Azure DNS."
CUSTOMDNS="--dns 168.63.129.16"
else
echo "Not setting dockerd DNS manually."
CUSTOMDNS=""
fi
set -e
if [ -z "$DOCKER_DEFAULT_ADDRESS_POOL" ]
@ -423,14 +444,35 @@ dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAU
INNEREOF
)"
# Start using sudo if not invoked as root
if [ "$(id -u)" -ne 0 ]; then
sudo /bin/sh -c "${dockerd_start}"
else
eval "${dockerd_start}"
fi
retry_docker_start_count=0
docker_ok="false"
set +e
until [ "${docker_ok}" = "true" ] || [ "${retry_docker_start_count}" -eq "5" ];
do
# Start using sudo if not invoked as root
if [ "$(id -u)" -ne 0 ]; then
sudo /bin/sh -c "${dockerd_start}"
else
eval "${dockerd_start}"
fi
retry_count=0
until [ "${docker_ok}" = "true" ] || [ "${retry_count}" -eq "5" ];
do
sleep 1s
set +e
docker info > /dev/null 2>&1 && docker_ok="true"
set -e
retry_count=`expr $retry_count + 1`
done
if [ "${docker_ok}" != "true" ]; then
echo "(*) Failed to start docker, retrying..."
fi
retry_docker_start_count=`expr $retry_docker_start_count + 1`
done
# Execute whatever commands were passed in (if any). This allows us
# to set this script to ENTRYPOINT while still executing the default CMD.

View file

@ -1,4 +1,71 @@
## Configuration examples
Installing only the latest .NET SDK version (the default).
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": "latest" // or "" or {}
}
```
Installing an additional SDK version. Multiple versions can be specified as comma-separated values.
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"additionalVersions": "lts"
}
}
```
Installing specific SDK versions.
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "6.0",
"additionalVersions": "7.0, 8.0"
}
}
```
Installing a specific SDK feature band.
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "6.0.4xx",
}
}
```
Installing a specific SDK patch version.
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "6.0.412",
}
}
```
Installing only the .NET Runtime or the ASP.NET Core Runtime. (The SDK includes all runtimes so this configuration is only useful if you need to run .NET apps without building them from source.)
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "none",
"dotnetRuntimeVersions": "latest, lts",
"aspnetCoreRuntimeVersions": "latest, lts",
}
}
```
## OS Support

View file

@ -1,13 +1,13 @@
# Dotnet CLI (dotnet)
Installs the .NET CLI. Provides option of installing sdk or runtime, and option of versions to install. Uses latest version of .NET sdk as defaults to install.
This Feature installs the latest .NET SDK, which includes the .NET CLI and the shared runtime. Options are provided to choose a different version or additional versions.
## Example Usage
```json
"features": {
"ghcr.io/devcontainers/features/dotnet:1": {}
"ghcr.io/devcontainers/features/dotnet:2": {}
}
```
@ -15,9 +15,10 @@ Installs the .NET CLI. Provides option of installing sdk or runtime, and option
| Options Id | Description | Type | Default Value |
|-----|-----|-----|-----|
| version | Select or enter a dotnet CLI version. (Available versions may vary by Linux distribution.) | string | latest |
| runtimeOnly | Install just the dotnet runtime if true, and sdk if false. | boolean | false |
| installUsingApt | If true, it installs using apt instead of the release URL | boolean | true |
| version | Select or enter a .NET SDK version. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | latest |
| additionalVersions | Enter additional .NET SDK versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
| dotnetRuntimeVersions | Enter additional .NET runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
| aspNetCoreRuntimeVersions | Enter additional ASP.NET Core runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
## Customizations
@ -25,7 +26,74 @@ Installs the .NET CLI. Provides option of installing sdk or runtime, and option
- `ms-dotnettools.csharp`
## Configuration examples
Installing only the latest .NET SDK version (the default).
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": "latest" // or "" or {}
}
```
Installing an additional SDK version. Multiple versions can be specified as comma-separated values.
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"additionalVersions": "lts"
}
}
```
Installing specific SDK versions.
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "6.0",
"additionalVersions": "7.0, 8.0"
}
}
```
Installing a specific SDK feature band.
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "6.0.4xx",
}
}
```
Installing a specific SDK patch version.
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "6.0.412",
}
}
```
Installing only the .NET Runtime or the ASP.NET Core Runtime. (The SDK includes all runtimes so this configuration is only useful if you need to run .NET apps without building them from source.)
``` json
{
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "none",
"dotnetRuntimeVersions": "latest, lts",
"aspnetCoreRuntimeVersions": "latest, lts",
}
}
```
## OS Support

View file

@ -1,35 +1,44 @@
{
"id": "dotnet",
"version": "1.1.4",
"version": "2.0.0",
"name": "Dotnet CLI",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/dotnet",
"description": "Installs the .NET CLI. Provides option of installing sdk or runtime, and option of versions to install. Uses latest version of .NET sdk as defaults to install.",
"description": "This Feature installs the latest .NET SDK, which includes the .NET CLI and the shared runtime. Options are provided to choose a different version or additional versions.",
"options": {
"version": {
"type": "string",
"proposals": [
"latest",
"7",
"6",
"3.1"
"lts",
"none",
"8.0",
"7.0",
"6.0"
],
"default": "latest",
"description": "Select or enter a dotnet CLI version. (Available versions may vary by Linux distribution.)"
"description": "Select or enter a .NET SDK version. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
},
"runtimeOnly": {
"type": "boolean",
"default": false,
"description": "Install just the dotnet runtime if true, and sdk if false."
"additionalVersions": {
"type": "string",
"default": "",
"description": "Enter additional .NET SDK versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
},
"installUsingApt": {
"type": "boolean",
"default": true,
"description": "If true, it installs using apt instead of the release URL"
"dotnetRuntimeVersions": {
"type": "string",
"default": "",
"description": "Enter additional .NET runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
},
"aspNetCoreRuntimeVersions": {
"type": "string",
"default": "",
"description": "Enter additional ASP.NET Core runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
}
},
"containerEnv": {
"DOTNET_ROOT": "/usr/local/dotnet/current",
"PATH": "/usr/local/dotnet/current:${PATH}"
"DOTNET_ROOT": "/usr/share/dotnet",
"PATH": "$PATH:$DOTNET_ROOT:~/.dotnet/tools",
"DOTNET_RUNNING_IN_CONTAINER": "true",
"DOTNET_USE_POLLING_FILE_WATCHER": "true"
},
"customizations": {
"vscode": {

View file

@ -4,47 +4,21 @@
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/dotnet.md
# Maintainer: The VS Code and Codespaces Teams
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
# Maintainer: The Dev Container spec maintainers
DOTNET_VERSION="${VERSION:-"latest"}"
DOTNET_RUNTIME_ONLY="${RUNTIMEONLY:-"false"}"
OVERRIDE_DEFAULT_VERSION="${OVERRIDEDEFAULTVERSION:-"true"}"
INSTALL_USING_APT="${INSTALLUSINGAPT:-"true"}"
DOTNET_LATEST="7"
DOTNET_LTS="6"
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
UPDATE_RC="${UPDATE_RC:-"true"}"
TARGET_DOTNET_ROOT="${TARGET_DOTNET_ROOT:-"/usr/local/dotnet"}"
ACCESS_GROUP="${ACCESS_GROUP:-"dotnet"}"
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
DOTNET_ARCHIVE_ARCHITECTURES="amd64"
DOTNET_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal hirsute jammy"
# Feed URI sourced from the official dotnet-install.sh
# https://github.com/dotnet/install-scripts/blob/1b98b94a6f6d81cc4845eb88e0195fac67caa0a6/src/dotnet-install.sh#L1342-L1343
DOTNET_CDN_FEED_URI="https://dotnetcli.azureedge.net"
# Ubuntu 22.04 and on do not ship with libssl1.1, which is required for versions of .NET < 6.0
DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1="buster bullseye bionic focal hirsute"
# Comma-separated list of dotnet versions to be installed
# alongside DOTNET_VERSION, but not set as default.
ADDITIONAL_VERSIONS=${ADDITIONALVERSIONS:-""}
APT_PREFERENCES_CONTENT="$(cat << 'EOF'
Package: *
Pin: origin "packages.microsoft.com"
Pin-Priority: 1001
EOF
)"
APT_PREFERENCES_FILE_ADDED="false"
APT_PREFERENCES_UPDATED="false"
ADDITIONAL_VERSIONS="${ADDITIONALVERSIONS}"
DOTNET_RUNTIME_VERSIONS="${DOTNETRUNTIMEVERSIONS}"
ASPNETCORE_RUNTIME_VERSIONS="${ASPNETCORERUNTIMEVERSIONS}"
set -e
# Import trim_whitespace and split_csv
source "scripts/string-helpers.sh"
# Import install_sdk and install_runtime
source "scripts/dotnet-helpers.sh"
# Clean up
rm -rf /var/lib/apt/lists/*
@ -53,72 +27,14 @@ err() {
echo "(!) $*" >&2
}
# Ensure the appropriate root user is running the script.
if [ "$(id -u)" -ne 0 ]; then
err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
rm -f /etc/profile.d/00-restore-env.sh
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
chmod +x /etc/profile.d/00-restore-env.sh
# Determine the appropriate non-root user.
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
USERNAME=""
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do
if id -u "${CURRENT_USER}" > /dev/null 2>&1; then
USERNAME="${CURRENT_USER}"
break
fi
done
if [ "${USERNAME}" = "" ]; then
USERNAME=root
fi
elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
USERNAME=root
fi
###################
# Helper Functions
###################
# 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
# Add dotnet directory to PATH in bashrc/zshrc files if OVERRIDE_DEFAULT_VERSION=true.
updaterc() {
if [ "${UPDATE_RC}" = "true" ]; then
echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then
echo -e "$1" >> /etc/bash.bashrc
fi
if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then
echo -e "$1" >> /etc/zsh/zshrc
fi
fi
}
apt_get_update()
{
apt_get_update() {
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
echo "Running apt-get update..."
apt-get update -y
fi
}
# Check if packages are installed and installs them if not.
# Checks if packages are installed and installs them if not
check_packages() {
if ! dpkg -s "$@" > /dev/null 2>&1; then
apt_get_update
@ -126,367 +42,77 @@ check_packages() {
fi
}
# Get appropriate architecture name for .NET binaries for the target OS
get_architecture_name_for_target_os() {
local architecture
architecture="$(uname -m)"
case $architecture in
x86_64) architecture="x64";;
aarch64 | armv8*) architecture="arm64";;
*) err "Architecture ${architecture} unsupported"; exit 1 ;;
esac
echo "${architecture}"
}
# Soft version matching that resolves a version for a given package in the *current apt-cache*
# Return value is stored in first argument (the unprocessed version)
apt_cache_package_and_version_soft_match() {
# Version
local version_variable_name="$1"
local requested_version=${!version_variable_name}
# Package Name
local package_variable_name="$2"
local partial_package_name=${!package_variable_name}
local package_name
# Exit on no match?
local exit_on_no_match="${3:-true}"
local major_minor_version
# Ensure we've exported useful variables
. /etc/os-release
local architecture="$(dpkg --print-architecture)"
apt-get update -y
major_minor_version="$(echo "${requested_version}" | cut -d "." --field=1,2)"
package_name="$(apt-cache search "${partial_package_name}-[0-9].[0-9]$" | awk -F" - " '{print $1}' | grep -m 1 "${partial_package_name}-${major_minor_version}")"
dot_escaped="${requested_version//./\\.}"
dot_plus_escaped="${dot_escaped//+/\\+}"
# Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/
version_regex="^(.+:)?${dot_plus_escaped}([\\.\\+ ~:-]|$)"
set +e # Don't exit if finding version fails - handle gracefully
fuzzy_version="$(apt-cache madison ${package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${version_regex}")"
set -e
if [ -z "${fuzzy_version}" ]; then
echo "(!) No full or partial for package \"${partial_package_name}\" (resolved: \"${package_name}\") match found in apt-cache for \"${requested_version}\" on OS ${ID} ${VERSION_CODENAME} (${architecture})."
if $exit_on_no_match; then
echo "Available versions:"
apt-cache madison ${package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+'
exit 1 # Fail entire script
else
echo "Continuing to fallback method if available"
return 1;
fi
fi
# Globally assign fuzzy_version to this value
# Use this value as the return value of this function
declare -g ${version_variable_name}="=${fuzzy_version}"
echo "${version_variable_name} ${!version_variable_name}"
# Globally assign package to this value
# Use this value as the return value of this function
declare -g ${package_variable_name}="${package_name}"
echo "${package_variable_name} ${!package_variable_name}"
}
# Install .NET CLI using apt-get package installer
install_using_apt() {
local sdk_or_runtime="$1"
local target_dotnet_version="$2"
local use_msft_repo="$3"
if [ "${use_msft_repo}" = "true" ]; then
# Install dependencies
check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr
# Import key safely and import Microsoft apt repo
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
[ ! -f /etc/apt/preferences ] && APT_PREFERENCES_FILE_ADDED="true"
APT_PREFERENCES_UPDATED="true"
# See https://github.com/dotnet/core/issues/7699
echo "${APT_PREFERENCES_CONTENT}" >> /etc/apt/preferences
apt-get update -y
fi
# .NET 7 is not a LTS version, so handle latest and LTS versions differently
export APT_DOTNET_VERSION="$target_dotnet_version"
if [ "${APT_DOTNET_VERSION}" = "latest" ]; then
APT_DOTNET_VERSION="${DOTNET_LATEST}.0"
elif [ "${APT_DOTNET_VERSION}" = "lts" ]; then
APT_DOTNET_VERSION="${DOTNET_LTS}.0"
fi
# Sets target_dotnet_version and dotnet_package if matches found.
local base_dotnet_package="dotnet-${sdk_or_runtime}"
export DOTNET_PACKAGE="${base_dotnet_package}"
apt_cache_package_and_version_soft_match APT_DOTNET_VERSION DOTNET_PACKAGE false
if [ "$?" != 0 ] || [ ${DOTNET_PACKAGE} == "${base_dotnet_package}" ]; then
echo "Failed to find requested version."
return 1
fi
if type dotnet > /dev/null 2>&1 && [[ "$(dotnet --version)" == *"${APT_DOTNET_VERSION}"* ]] ; then
echo "dotnet version ${APT_DOTNET_VERSION} is already installed"
return 1
fi
echo "Installing '${DOTNET_PACKAGE}${APT_DOTNET_VERSION}'..."
apt-get install -yq ${DOTNET_PACKAGE}${APT_DOTNET_VERSION}
if [ "$?" != 0 ]; then
echo "Failed to complete apt install of ${DOTNET_PACKAGE}${TARGET_DOTNET_VERSION}"
return 1
fi
# Add symlink for current
CURRENT_DIR="${TARGET_DOTNET_ROOT}/current"
if [[ -d "${CURRENT_DIR}" ]]; then
rm -rf "${CURRENT_DIR}"
fi
mkdir -p "${TARGET_DOTNET_ROOT}"
local dotnet_installed_version="$(dotnet --version)"
# See if its the distro version
if [[ "$(dotnet --info)" == *"Base Path: /usr/lib/dotnet/${DOTNET_SDK_OR_RUNTIME}/${dotnet_installed_version}"* ]]; then
ln -s "/usr/lib/dotnet" "${CURRENT_DIR}"
else
# Location used by MS repo versions
ln -s "/usr/share/dotnet" "${CURRENT_DIR}"
fi
}
# Find and extract .NET binary download details based on user-requested version
# args:
# sdk_or_runtime $1
# dotnet_version_to_download $2
# exports:
# DOTNET_DOWNLOAD_URL
# DOTNET_DOWNLOAD_HASH
# DOTNET_DOWNLOAD_NAME
get_full_version_details() {
local sdk_or_runtime="$1"
local architecture
local dotnet_channel_version
local dotnet_releases_url
local dotnet_releases_json
local dotnet_latest_version
local dotnet_download_details
export DOTNET_DOWNLOAD_VERSION="$2"
export DOTNET_DOWNLOAD_URL
export DOTNET_DOWNLOAD_HASH
export DOTNET_DOWNLOAD_NAME
# Set architecture variable to current user's architecture (x64 or ARM64).
architecture="$(get_architecture_name_for_target_os)"
# Set VERSION to empty string to ensure jq includes all .NET versions in reverse sort below
if [ "${DOTNET_DOWNLOAD_VERSION}" = "latest" ]; then
DOTNET_DOWNLOAD_VERSION=""
fi
dotnet_patchless_version="$(echo "${DOTNET_DOWNLOAD_VERSION}" | cut -d "." --field=1,2)"
set +e
dotnet_channel_version="$(curl -s "${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/releases-index.json" | jq -r --arg channel_version "${dotnet_patchless_version}" '[."releases-index"[]] | sort_by(."channel-version") | reverse | map( select(."channel-version" | startswith($channel_version))) | first | ."channel-version"')"
set -e
# Construct the releases URL using the official channel-version if one was found. Otherwise make a best-effort using the user input.
if [ -n "${dotnet_channel_version}" ] && [ "${dotnet_channel_version}" != "null" ]; then
dotnet_releases_url="${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/${dotnet_channel_version}/releases.json"
else
dotnet_releases_url="${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/${dotnet_patchless_version}/releases.json"
fi
set +e
dotnet_releases_json="$(curl -s "${dotnet_releases_url}")"
set -e
if [ -n "${dotnet_releases_json}" ] && [[ ! "${dotnet_releases_json}" = *"Error"* ]]; then
dotnet_latest_version="$(echo "${dotnet_releases_json}" | jq -r --arg sdk_or_runtime "${sdk_or_runtime}" '."latest-\($sdk_or_runtime)"')"
# If user-specified version has 2 or more dots, use it as is. Otherwise use latest version.
if [ "$(echo "${DOTNET_DOWNLOAD_VERSION}" | grep -o "\." | wc -l)" -lt "2" ]; then
DOTNET_DOWNLOAD_VERSION="${dotnet_latest_version}"
fi
dotnet_download_details="$(echo "${dotnet_releases_json}" | jq -r --arg sdk_or_runtime "${sdk_or_runtime}" --arg dotnet_version "${DOTNET_DOWNLOAD_VERSION}" --arg arch "${architecture}" '.releases[]."\($sdk_or_runtime)" | select(.version==$dotnet_version) | .files[] | select(.name=="dotnet-\($sdk_or_runtime)-linux-\($arch).tar.gz")')"
if [ -n "${dotnet_download_details}" ]; then
echo "Found .NET binary version ${DOTNET_DOWNLOAD_VERSION}"
DOTNET_DOWNLOAD_URL="$(echo "${dotnet_download_details}" | jq -r '.url')"
DOTNET_DOWNLOAD_HASH="$(echo "${dotnet_download_details}" | jq -r '.hash')"
DOTNET_DOWNLOAD_NAME="$(echo "${dotnet_download_details}" | jq -r '.name')"
else
err "Unable to find .NET binary for version ${DOTNET_DOWNLOAD_VERSION}"
exit 1
fi
else
err "Unable to find .NET release details for version ${DOTNET_DOWNLOAD_VERSION} at ${dotnet_releases_url}"
exit 1
fi
}
# Install .NET CLI using the .NET releases url
install_using_dotnet_releases_url() {
local sdk_or_runtime="$1"
local version="$2"
# Check listed package dependencies and install them if they are not already installed.
# NOTE: icu-devtools is a small package with similar dependencies to .NET.
# It will install the appropriate dependencies based on the OS:
# - libgcc-s1 OR libgcc1 depending on OS
# - the latest libicuXX depending on OS (eg libicu57 for stretch)
# - also installs libc6 and libstdc++6 which are required by .NET
check_packages curl ca-certificates tar jq icu-devtools libgssapi-krb5-2 zlib1g
# Starting with Ubuntu 22.04 (jammy), libssl1.1 does not ship with the OS anymore.
if [[ "${DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1}" = *"${VERSION_CODENAME}"* ]]; then
check_packages libssl1.1
else
check_packages libssl3
fi
get_full_version_details "${sdk_or_runtime}" "${version}"
DOTNET_INSTALL_PATH="${TARGET_DOTNET_ROOT}/${DOTNET_DOWNLOAD_VERSION}"
if [ -d "${DOTNET_INSTALL_PATH}" ]; then
echo "(!) Dotnet version ${DOTNET_DOWNLOAD_VERSION} already exists."
exit 1
fi
# exports DOTNET_DOWNLOAD_URL, DOTNET_DOWNLOAD_HASH, DOTNET_DOWNLOAD_NAME
echo "DOWNLOAD LINK: ${DOTNET_DOWNLOAD_URL}"
# Setup the access group and add the user to it.
umask 0002
if ! cat /etc/group | grep -e "^${ACCESS_GROUP}:" > /dev/null 2>&1; then
groupadd -r "${ACCESS_GROUP}"
fi
usermod -a -G "${ACCESS_GROUP}" "${USERNAME}"
# Download the .NET binaries.
echo "DOWNLOADING BINARY..."
TMP_DIR="/tmp/dotnetinstall"
mkdir -p "${TMP_DIR}"
curl -sSL "${DOTNET_DOWNLOAD_URL}" -o "${TMP_DIR}/${DOTNET_DOWNLOAD_NAME}"
# Get checksum from .NET CLI blob storage using the runtime version and
# run validation (sha512sum) of checksum against the expected checksum hash.
echo "VERIFY CHECKSUM"
cd "${TMP_DIR}"
echo "${DOTNET_DOWNLOAD_HASH} *${DOTNET_DOWNLOAD_NAME}" | sha512sum -c -
# Extract binaries and add to path.
mkdir -p "${DOTNET_INSTALL_PATH}"
echo "Extract Binary to ${DOTNET_INSTALL_PATH}"
tar -xzf "${TMP_DIR}/${DOTNET_DOWNLOAD_NAME}" -C "${DOTNET_INSTALL_PATH}" --strip-components=1
CURRENT_DIR="${TARGET_DOTNET_ROOT}/current"
if [[ ! -d "${CURRENT_DIR}" ]]; then
ln -s "${DOTNET_INSTALL_PATH}" "${CURRENT_DIR}"
fi
# Give write permissions to the user.
chown -R "${USERNAME}:${USERNAME}" "${CURRENT_DIR}"
chmod g+r+w+s "${CURRENT_DIR}"
chmod -R g+r+w "${CURRENT_DIR}"
if [[ "${OVERRIDE_DEFAULT_VERSION}" = "true" ]]; then
if [[ $(ls -l ${CURRENT_DIR}) != *"-> ${DOTNET_INSTALL_PATH}"* ]] ; then
rm "${CURRENT_DIR}"
ln -s "${DOTNET_INSTALL_PATH}" "${CURRENT_DIR}"
fi
fi
updaterc "if [[ \"\${PATH}\" != *\"${CURRENT_DIR}\"* ]]; then export PATH=${CURRENT_DIR}:\${PATH}; fi"
}
###########################
# Start .NET installation
###########################
export DEBIAN_FRONTEND=noninteractive
. /etc/os-release
architecture="$(dpkg --print-architecture)"
# Dotnet 3.1 and 5 are not supported on Ubuntu 22.04 (jammy)+,
# due to lack of libssl3.0 support.
# See: https://github.com/microsoft/vscode-dev-containers/issues/1458#issuecomment-1135077775
# NOTE: This will only guard against installation of the dotnet versions we propose via 'features'.
# The user can attempt to install any other version at their own risk.
if [[ "${DOTNET_VERSION}" = "3"* ]] || [[ "${DOTNET_VERSION}" = "5"* ]]; then
if [[ ! "${DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1}" = *"${VERSION_CODENAME}"* ]]; then
err "Dotnet ${DOTNET_VERSION} is not supported on Ubuntu ${VERSION_CODENAME} due to a change in the 'libssl' dependency across distributions.\n Please upgrade your version of dotnet, or downgrade your OS version."
exit 1
fi
fi
# Determine if the user wants to download .NET Runtime only, or .NET SDK & Runtime
# and set the appropriate variables.
if [ "${DOTNET_RUNTIME_ONLY}" = "true" ]; then
DOTNET_SDK_OR_RUNTIME="runtime"
elif [ "${DOTNET_RUNTIME_ONLY}" = "false" ]; then
DOTNET_SDK_OR_RUNTIME="sdk"
else
err "Expected true for installing dotnet Runtime only or false for installing SDK and Runtime. Received ${DOTNET_RUNTIME_ONLY}."
if [ "$(id -u)" -ne 0 ]; then
err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Install the .NET CLI
echo "(*) Installing .NET CLI..."
# For our own convenience, combine DOTNET_VERSION and ADDITIONAL_VERSIONS into a single 'versions' array
versions=()
CHANGE_OWNERSHIP="false"
if [[ "${DOTNET_ARCHIVE_ARCHITECTURES}" = *"${architecture}"* ]] && [[ "${DOTNET_ARCHIVE_VERSION_CODENAMES}" = *"${VERSION_CODENAME}"* ]] && [[ "${INSTALL_USING_APT}" = "true" ]]; then
echo "Detected ${VERSION_CODENAME} on ${architecture}. Attempting to install dotnet from apt"
# The version can be set to 'none' for runtime-only installations, then the array will just remain empty
# Ensure there are no leading or trailing spaces that can break regex pattern matching
if [ "$DOTNET_VERSION" != "none" ]; then
versions+=("$(trim_whitespace "$DOTNET_VERSION")")
for additional_version in $(split_csv "$ADDITIONAL_VERSIONS"); do
versions+=("$additional_version")
done
fi
install_using_apt "${DOTNET_SDK_OR_RUNTIME}" "${DOTNET_VERSION}" false || install_using_apt "${DOTNET_SDK_OR_RUNTIME}" "${DOTNET_VERSION}" true
if [ "$?" != 0 ]; then
echo "Could not install requested version from apt on current distribution."
dotnetRuntimeVersions=()
for dotnetRuntimeVersion in $(split_csv "$DOTNET_RUNTIME_VERSIONS"); do
dotnetRuntimeVersions+=("$dotnetRuntimeVersion")
done
aspNetCoreRuntimeVersions=()
for aspNetCoreRuntimeVersion in $(split_csv "$ASPNETCORE_RUNTIME_VERSIONS"); do
aspNetCoreRuntimeVersions+=("$aspNetCoreRuntimeVersion")
done
# Fail fast in case of bad input to avoid unneccesary work
# v1 of the .NET feature allowed specifying only a major version 'X' like '3'
# v2 removed this ability
# - because install-dotnet.sh does not support it directly
# - because the previous behavior installed an old version like '3.0.103', not the newest version '3.1.426', which was counterintuitive
for version in "${versions[@]}"; do
if [[ "$version" =~ ^[0-9]+$ ]]; then
err "Unsupported .NET SDK version '${version}'. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
exit 1
fi
else
if [[ "${INSTALL_USING_APT}" = "false" ]]; then
echo "Installing dotnet from releases url"
else
echo "Attempting to install dotnet from releases url"
done
for version in "${dotnetRuntimeVersions[@]}"; do
if [[ "$version" =~ ^[0-9]+$ ]]; then
err "Unsupported .NET Runtime version '${version}'. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
exit 1
fi
install_using_dotnet_releases_url "${DOTNET_SDK_OR_RUNTIME}" "${DOTNET_VERSION}"
CHANGE_OWNERSHIP="true"
fi
done
# Additional dotnet versions to be installed but not be set as default.
if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then
OLDIFS=$IFS
IFS=","
read -a additional_versions <<< "$ADDITIONAL_VERSIONS"
for version in "${additional_versions[@]}"; do
OVERRIDE_DEFAULT_VERSION="false"
install_using_dotnet_releases_url "${DOTNET_SDK_OR_RUNTIME}" "${version}"
done
IFS=$OLDIFS
fi
if [ "${CHANGE_OWNERSHIP}" = "true" ]; then
if ! cat /etc/group | grep -e "^dotnet:" > /dev/null 2>&1; then
groupadd -r dotnet
for version in "${aspNetCoreRuntimeVersions[@]}"; do
if [[ "$version" =~ ^[0-9]+$ ]]; then
err "Unsupported ASP.NET Core Runtime version '${version}'. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
exit 1
fi
usermod -a -G dotnet "${USERNAME}"
done
chown -R "${USERNAME}:dotnet" "${TARGET_DOTNET_ROOT}"
chmod -R g+r+w "${TARGET_DOTNET_ROOT}"
find "${TARGET_DOTNET_ROOT}" -type d -print0 | xargs -n 1 -0 chmod g+s
fi
# Install .NET versions and dependencies
# icu-devtools includes dependencies for .NET
check_packages wget ca-certificates icu-devtools
for version in "${versions[@]}"; do
install_sdk "$version"
done
for version in "${dotnetRuntimeVersions[@]}"; do
install_runtime "dotnet" "$version"
done
for version in "${aspNetCoreRuntimeVersions[@]}"; do
install_runtime "aspnetcore" "$version"
done
# Clean up
if [ "${APT_PREFERENCES_UPDATED}" = "true" ]; then
if [ "${APT_PREFERENCES_FILE_ADDED}" = "true" ]; then
rm -f /etc/apt/preferences
else
head -n -3 /etc/apt/preferences > /tmp/preferences-temp && mv /tmp/preferences-temp /etc/apt/preferences
fi
fi
rm -rf /var/lib/apt/lists/*
rm -rf scripts
echo "Done!"

View file

@ -0,0 +1,119 @@
#!/bin/bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
# Maintainer: The Dev Container spec maintainers
DOTNET_SCRIPTS=$(dirname "${BASH_SOURCE[0]}")
DOTNET_INSTALL_SCRIPT="$DOTNET_SCRIPTS/vendor/dotnet-install.sh"
DOTNET_INSTALL_DIR='/usr/share/dotnet'
# Prints the latest dotnet version in the specified channel
# Usage: fetch_latest_version_in_channel <channel> [<runtime>]
# Example: fetch_latest_version_in_channel "LTS"
# Example: fetch_latest_version_in_channel "6.0" "dotnet"
# Example: fetch_latest_version_in_channel "6.0" "aspnetcore"
fetch_latest_version_in_channel() {
local channel="$1"
local runtime="$2"
if [ "$runtime" = "dotnet" ]; then
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Runtime/$channel/latest.version"
elif [ "$runtime" = "aspnetcore" ]; then
wget -qO- "https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$channel/latest.version"
else
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Sdk/$channel/latest.version"
fi
}
# Prints the latest dotnet version
# Usage: fetch_latest_version [<runtime>]
# Example: fetch_latest_version
# Example: fetch_latest_version "dotnet"
# Example: fetch_latest_version "aspnetcore"
fetch_latest_version() {
local runtime="$1"
local sts_version
local lts_version
sts_version=$(fetch_latest_version_in_channel "STS" "$runtime")
lts_version=$(fetch_latest_version_in_channel "LTS" "$runtime")
if [[ "$sts_version" > "$lts_version" ]]; then
echo "$sts_version"
else
echo "$lts_version"
fi
}
# Installs a version of the .NET SDK
# Usage: install_sdk <version>
install_sdk() {
local inputVersion="$1"
local version=""
local channel=""
if [[ "$inputVersion" == "latest" ]]; then
# Fetch the latest version manually, because dotnet-install.sh does not support it directly
version=$(fetch_latest_version)
elif [[ "$inputVersion" == "lts" ]]; then
# When user input is 'lts'
# Then version=latest, channel=LTS
version="latest"
channel="LTS"
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+$ ]]; then
# When user input is form 'A.B' like '3.1'
# Then version=latest, channel=3.1
version="latest"
channel="$inputVersion"
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+\.[0-9]xx$ ]]; then
# When user input is form 'A.B.Cxx' like '6.0.4xx'
# Then version=latest, channel=6.0.4xx
version="latest"
channel="$inputVersion"
else
# Assume version is an exact version string like '6.0.413' or '8.0.100-rc.2.23425.18'
version="$inputVersion"
fi
# Currently this script does not make it possible to qualify the version, 'GA' is always implied
echo "Executing $DOTNET_INSTALL_SCRIPT --version $version --channel $channel --install-dir $DOTNET_INSTALL_DIR --no-path"
"$DOTNET_INSTALL_SCRIPT" \
--version "$version" \
--channel "$channel" \
--install-dir "$DOTNET_INSTALL_DIR" \
--no-path
}
# Installs a version of the .NET Runtime
# Usage: install_runtime <runtime> <version>
install_runtime() {
local runtime="$1"
local inputVersion="$2"
local version=""
local channel=""
if [[ "$inputVersion" == "latest" ]]; then
# Fetch the latest version manually, because dotnet-install.sh does not support it directly
version=$(fetch_latest_version "$runtime")
elif [[ "$inputVersion" == "lts" ]]; then
# When user input is 'lts'
# Then version=latest, channel=LTS
version="latest"
channel="LTS"
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+$ ]]; then
# When user input is form 'A.B' like '3.1'
# Then version=latest, channel=3.1
version="latest"
channel="$inputVersion"
else
# Assume version is an exact version string like '6.0.21' or '8.0.0-preview.7.23375.6'
version="$inputVersion"
fi
echo "Executing $DOTNET_INSTALL_SCRIPT --runtime $runtime --version $version --channel $channel --install-dir $DOTNET_INSTALL_DIR --no-path"
"$DOTNET_INSTALL_SCRIPT" \
--runtime "$runtime" \
--version "$version" \
--channel "$channel" \
--install-dir "$DOTNET_INSTALL_DIR" \
--no-path
}

View file

@ -0,0 +1,16 @@
#!/bin/bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
# Maintainer: The Dev Container spec maintainers
#
# Run this script to replace dotnet-install.sh with the latest and greatest available version
#
DOTNET_SCRIPTS=$(dirname "${BASH_SOURCE[0]}")
DOTNET_INSTALL_SCRIPT="$DOTNET_SCRIPTS/vendor/dotnet-install.sh"
wget https://dot.net/v1/dotnet-install.sh -O "$DOTNET_INSTALL_SCRIPT"
chmod +x "$DOTNET_INSTALL_SCRIPT"

View file

@ -0,0 +1,42 @@
#!/bin/bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
# Maintainer: The Dev Container spec maintainers
# Removes leading and trailing whitespace from an input string
# Usage: trim_whitespace <text>
trim_whitespace() {
text="$1"
# Remove leading spaces
while [ "${text:0:1}" == " " ]; do
text="${text:1}"
done
# Remove trailing spaces
while [ "${text: -1}" == " " ]; do
text="${text:0:-1}"
done
echo "$text"
}
# Splits comma-separated values into an array while ignoring empty entries
# Usage: split_csv <comma-separated-values>
split_csv() {
local -a values=()
while IFS="," read -ra entries; do
for entry in "${entries[@]}"; do
entry="$(trim_whitespace "$entry")"
if [ -n "$entry" ]; then
values+=("$entry")
fi
done
done <<< "$1"
echo "${values[@]}"
}

27
src/dotnet/scripts/vendor/README.md vendored Normal file
View file

@ -0,0 +1,27 @@
### **IMPORTANT NOTE**
Scripts in this directory are sourced externally and not maintained by the Dev Container spec maintainers. Do not make changes directly as they might be overwritten at any moment.
## dotnet-install.sh
`dotnet-install.sh` is a copy of <https://dot.net/v1/dotnet-install.sh>. ([Script reference](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script))
Quick options reminder for `dotnet-install.sh`:
- `--version`: `"latest"` (default) or an exact version in the form A.B.C like `"6.0.413"`
- `--channel`: `"LTS"` (default), `"STS"`, a two-part version in the form A.B like `"6.0"` or three-part form A.B.Cxx like `"6.0.1xx"`
- `--quality`: `"daily"`, `"preview"` or `"GA"`
- The channel option is only used when version is 'latest' because an exact version overrides the channel option
- The quality option is only used when channel is 'A.B' or 'A.B.Cxx' because it can't be used with STS or LTS
Examples
```
dotnet-install.sh [--version latest] [--channel LTS]
dotnet-install.sh [--version latest] --channel STS
dotnet-install.sh [--version latest] --channel 6.0 [--quality GA]
dotnet-install.sh [--version latest] --channel 6.0.4xx [--quality GA]
dotnet-install.sh [--version latest] --channel 8.0 --quality preview
dotnet-install.sh [--version latest] --channel 8.0 --quality daily
dotnet-install.sh --version 6.0.413
```

1746
src/dotnet/scripts/vendor/dotnet-install.sh vendored Executable file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"id": "go",
"version": "1.2.0",
"version": "1.2.1",
"name": "Go",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/go",
"description": "Installs Go and common Go utilities. Auto-detects latest version and installs needed dependencies.",
@ -10,8 +10,8 @@
"proposals": [
"latest",
"none",
"1.19",
"1.18"
"1.21",
"1.20"
],
"default": "latest",
"description": "Select or enter a Go version to install"

View file

@ -18,7 +18,7 @@ Installs Node.js, nvm, yarn, pnpm, and needed dependencies.
| version | Select or enter a Node.js version to install | string | lts |
| nodeGypDependencies | Install dependencies to compile native node modules (node-gyp)? | boolean | true |
| nvmInstallPath | The path where NVM will be installed. | string | /usr/local/share/nvm |
| nvmVersion | Version of NVM to install. | string | 0.39.2 |
| nvmVersion | Version of NVM to install. | string | latest |
## Customizations

View file

@ -1,6 +1,6 @@
{
"id": "node",
"version": "1.2.0",
"version": "1.3.0",
"name": "Node.js (via nvm), yarn and pnpm",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/node",
"description": "Installs Node.js, nvm, yarn, pnpm, and needed dependencies.",
@ -30,7 +30,11 @@
},
"nvmVersion": {
"type": "string",
"default": "0.39.2",
"proposals": [
"latest",
"0.39"
],
"default": "latest",
"description": "Version of NVM to install."
}
},

View file

@ -8,8 +8,8 @@
# Maintainer: The Dev Container spec maintainers
export NODE_VERSION="${VERSION:-"lts"}"
export NVM_VERSION="${NVMVERSION:-"0.39.2"}"
export NVM_DIR=${NVMINSTALLPATH:-"/usr/local/share/nvm"}
export NVM_VERSION="${NVMVERSION:-"latest"}"
export NVM_DIR="${NVMINSTALLPATH:-"/usr/local/share/nvm"}"
INSTALL_TOOLS_FOR_NODE_GYP="${NODEGYPDEPENDENCIES:-true}"
# Comma-separated list of node versions to be installed (with nvm)
@ -78,6 +78,40 @@ check_packages() {
fi
}
# Figure out correct version of a three part version number is not passed
find_version_from_git_tags() {
local variable_name=$1
local requested_version=${!variable_name}
if [ "${requested_version}" = "none" ]; then return; fi
local repository=$2
local prefix=${3:-"tags/v"}
local separator=${4:-"."}
local last_part_optional=${5:-"false"}
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
local escaped_separator=${separator//./\\.}
local last_part
if [ "${last_part_optional}" = "true" ]; then
last_part="(${escaped_separator}[0-9]+)?"
else
last_part="${escaped_separator}[0-9]+"
fi
local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$"
local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)"
if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)"
else
set +e
declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")"
set -e
fi
fi
if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then
echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2
exit 1
fi
echo "${variable_name}=${!variable_name}"
}
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
@ -92,6 +126,10 @@ fi
# Install dependencies
check_packages apt-transport-https curl ca-certificates tar gnupg2 dirmngr
if ! type git > /dev/null 2>&1; then
check_packages git
fi
# Install yarn
if type yarn > /dev/null 2>&1; then
echo "Yarn already installed."
@ -112,16 +150,18 @@ elif [ "${NODE_VERSION}" = "latest" ]; then
export NODE_VERSION="node"
fi
find_version_from_git_tags NVM_VERSION "https://github.com/nvm-sh/nvm"
# Install snipppet that we will run as the user
nvm_install_snippet="$(cat << EOF
set -e
umask 0002
# Do not update profile - we'll do this manually
export PROFILE=/dev/null
curl -so- https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh | bash
source ${NVM_DIR}/nvm.sh
curl -so- "https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh" | bash
source "${NVM_DIR}/nvm.sh"
if [ "${NODE_VERSION}" != "" ]; then
nvm alias default ${NODE_VERSION}
nvm alias default "${NODE_VERSION}"
fi
EOF
)"
@ -149,9 +189,9 @@ usermod -a -G nvm ${USERNAME}
umask 0002
if [ ! -d "${NVM_DIR}" ]; then
# Create nvm dir, and set sticky bit
mkdir -p ${NVM_DIR}
chown "${USERNAME}:nvm" ${NVM_DIR}
chmod g+rws ${NVM_DIR}
mkdir -p "${NVM_DIR}"
chown "${USERNAME}:nvm" "${NVM_DIR}"
chmod g+rws "${NVM_DIR}"
su ${USERNAME} -c "${nvm_install_snippet}" 2>&1
# Update rc files
if [ "${UPDATE_RC}" = "true" ]; then
@ -160,11 +200,11 @@ if [ ! -d "${NVM_DIR}" ]; then
else
echo "NVM already installed."
if [ "${NODE_VERSION}" != "" ]; then
su ${USERNAME} -c "umask 0002 && . $NVM_DIR/nvm.sh && nvm install ${NODE_VERSION} && nvm alias default ${NODE_VERSION}"
su ${USERNAME} -c "umask 0002 && . '$NVM_DIR/nvm.sh' && nvm install '${NODE_VERSION}' && nvm alias default '${NODE_VERSION}'"
fi
fi
# Additional node versions to be installed but not be set as
# Additional node versions to be installed but not be set as
# default we can assume the nvm is the group owner of the nvm
# directory and the sticky bit on directories so any installed
# files will have will have the correct ownership (nvm)
@ -173,12 +213,12 @@ if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then
IFS=","
read -a additional_versions <<< "$ADDITIONAL_VERSIONS"
for ver in "${additional_versions[@]}"; do
su ${USERNAME} -c "umask 0002 && . $NVM_DIR/nvm.sh && nvm install ${ver}"
su ${USERNAME} -c "umask 0002 && . '$NVM_DIR/nvm.sh' && nvm install '${ver}'"
done
# Ensure $NODE_VERSION is on the $PATH
if [ "${NODE_VERSION}" != "" ]; then
su ${USERNAME} -c "umask 0002 && . $NVM_DIR/nvm.sh && nvm use default"
su ${USERNAME} -c "umask 0002 && . '$NVM_DIR/nvm.sh' && nvm use default"
fi
IFS=$OLDIFS
fi
@ -218,7 +258,7 @@ fi
# Clean up
su ${USERNAME} -c "umask 0002 && . $NVM_DIR/nvm.sh && nvm clear-cache"
su ${USERNAME} -c "umask 0002 && . '$NVM_DIR/nvm.sh' && nvm clear-cache"
rm -rf /var/lib/apt/lists/*
# Ensure privs are correct for installed node versions. Unfortunately the

View file

@ -1,6 +1,6 @@
{
"id": "ruby",
"version": "1.1.0",
"version": "1.1.1",
"name": "Ruby (via rvm)",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/ruby",
"description": "Installs Ruby, rvm, rbenv, common Ruby utilities, and needed dependencies.",

View file

@ -177,9 +177,11 @@ fi
find_version_from_git_tags RUBY_VERSION "https://github.com/ruby/ruby" "tags/v" "_"
# Just install Ruby if RVM already installed
if [ $(rvm --version) != "" ]; then
if rvm --version > /dev/null; then
echo "Ruby Version Manager already exists."
if [ "${RUBY_VERSION}" != "none" ]; then
if [[ "$(ruby -v)" = *"${RUBY_VERSION}"* ]]; then
echo "(!) Ruby is already installed with version ${RUBY_VERSION}. Skipping..."
elif [ "${RUBY_VERSION}" != "none" ]; then
echo "Installing specified Ruby version."
su ${USERNAME} -c "rvm install ruby ${RUBY_VERSION}"
fi
@ -191,6 +193,9 @@ else
# Determine appropriate settings for rvm installer
if [ "${RUBY_VERSION}" = "none" ]; then
RVM_INSTALL_ARGS=""
elif [[ "$(ruby -v)" = *"${RUBY_VERSION}"* ]]; then
echo "(!) Ruby is already installed with version ${RUBY_VERSION}. Skipping..."
RVM_INSTALL_ARGS=""
else
if [ "${RUBY_VERSION}" = "latest" ] || [ "${RUBY_VERSION}" = "current" ] || [ "${RUBY_VERSION}" = "lts" ]; then
RVM_INSTALL_ARGS="--ruby"
@ -273,8 +278,11 @@ if [ "${SKIP_RBENV_RBUILD}" != "true" ]; then
ln -s /usr/local/share/ruby-build /home/${USERNAME}/.rbenv/plugins/ruby-build
fi
ln -s /usr/local/rvm/rubies/default/bin/ruby /usr/local/rvm/gems/default/bin
# Oryx expects ruby to be installed in this specific path, else it breaks the oryx magic for ruby projects.
if [ ! -f /usr/local/rvm/gems/default/bin/ruby ]; then
ln -s /usr/local/rvm/rubies/default/bin/ruby /usr/local/rvm/gems/default/bin
fi
chown -R "${USERNAME}:rvm" "/home/${USERNAME}/.rbenv/"
chmod -R g+r+w "/home/${USERNAME}/.rbenv"
find "/home/${USERNAME}/.rbenv" -type d | xargs -n 1 chmod g+s

View file

@ -23,7 +23,6 @@ Installs Rust, common Rust utilities, and their required dependencies
### VS Code Extensions
- `vadimcn.vscode-lldb`
- `mutantdino.resourcemonitor`
- `rust-lang.rust-analyzer`
- `tamasfe.even-better-toml`
- `serayuzgur.crates`

View file

@ -1,6 +1,6 @@
{
"id": "rust",
"version": "1.0.12",
"version": "1.1.0",
"name": "Rust",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/rust",
"description": "Installs Rust, common Rust utilities, and their required dependencies",
@ -39,7 +39,6 @@
"vscode": {
"extensions": [
"vadimcn.vscode-lldb",
"mutantdino.resourcemonitor",
"rust-lang.rust-analyzer",
"tamasfe.even-better-toml",
"serayuzgur.crates"

View file

@ -1,6 +1,6 @@
{
"id": "terraform",
"version": "1.3.3",
"version": "1.3.4",
"name": "Terraform, tflint, and TFGrunt",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/terraform",
"description": "Installs the Terraform CLI and optionally TFLint and Terragrunt. Auto-detects latest version and installs needed dependencies.",

View file

@ -165,7 +165,8 @@ ensure_cosign() {
if ! type cosign > /dev/null 2>&1; then
echo "Installing cosign..."
local LATEST_COSIGN_VERSION=$(curl https://api.github.com/repos/sigstore/cosign/releases/latest | grep tag_name | cut -d : -f2 | tr -d "v\", ")
LATEST_COSIGN_VERSION="latest"
find_version_from_git_tags LATEST_COSIGN_VERSION 'https://github.com/sigstore/cosign'
curl -L "https://github.com/sigstore/cosign/releases/latest/download/cosign_${LATEST_COSIGN_VERSION}_${architecture}.deb" -o /tmp/cosign_${LATEST_COSIGN_VERSION}_${architecture}.deb
dpkg -i /tmp/cosign_${LATEST_COSIGN_VERSION}_${architecture}.deb

View file

@ -0,0 +1,14 @@
#!/bin/bash
set -e
# Import test library for `check` command
source dev-container-features-test-lib
# Check to make sure the user is vscode
check "user is vscode" whoami | grep vscode
check "version" az --version
# Report result
reportResults

View file

@ -28,5 +28,15 @@
"installBicep": true
}
}
},
"install_with_python": {
"image": "mcr.microsoft.com/devcontainers/base:jammy",
"user": "vscode",
"features": {
"azure-cli": {
"version": "latest",
"installUsingPython": true
}
}
}
}

View file

@ -0,0 +1,13 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Definition specific tests
check "alpine default shell zsh" \
bash -c "getent passwd $(whoami) | awk -F : '{ print $7 }' | grep '/bin/zsh'"
# Report result
reportResults

View file

@ -9,6 +9,7 @@ source dev-container-features-test-lib
. /etc/os-release
check "non-root user" test "$(whoami)" = "devcontainer"
check "distro" test "${VERSION_ID}" = "7"
check "jq" jq --version
# Report result
reportResults

View file

@ -7,6 +7,8 @@ source dev-container-features-test-lib
# Definition specific tests
check "default-shell-is-zsh" bash -c "getent passwd $(whoami) | awk -F: '{ print $7 }' | grep '/bin/zsh'"
# check it overrides the ~/.zshrc with default dev containers template
check "default-zshrc-is-dev-container-template" bash -c "cat ~/.zshrc | grep ZSH_THEME | grep devcontainers"
# Report result
reportResults

View file

@ -0,0 +1,12 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Definition specific tests
check "default-zsh-with-no-zshrc" bash -c "[ ! -e ~/.zshrc ]"
# Report result
reportResults

View file

@ -0,0 +1,14 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Definition specific tests
function file_not_overridden() {
cat $1 | grep 'alias fnomockalias=' | grep testingmock
}
check "default-zsh-with-no-zshrc" file_not_overridden /home/devcontainer/.zshrc
# Report result
reportResults

View file

@ -9,6 +9,7 @@ source dev-container-features-test-lib
. /etc/os-release
check "non-root user" test "$(whoami)" = "devcontainer"
check "distro" test "${ID}" = "fedora"
check "jq" jq --version
# Report result
reportResults

View file

@ -9,6 +9,7 @@ source dev-container-features-test-lib
. /etc/os-release
check "non-root user" test "$(whoami)" = "devcontainer"
check "distro" test "${ID}" = "mariner"
check "jq" jq --version
# Report result
reportResults

View file

@ -10,6 +10,7 @@ source dev-container-features-test-lib
check "non-root user" test "$(whoami)" = "devcontainer"
check "distro" test "${PLATFORM_ID}" = "platform:el8"
check "curl" curl --version
check "jq" jq --version
# Report result
reportResults

View file

@ -10,6 +10,7 @@ source dev-container-features-test-lib
check "non-root user" test "$(whoami)" = "devcontainer"
check "distro" test "${PLATFORM_ID}" = "platform:el9"
check "curl" curl --version
check "jq" jq --version
# Report result
reportResults

View file

@ -115,6 +115,27 @@
}
}
},
"configure_zsh_no_template_second_step": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"postCreateCommand": "echo alias fnomockalias=testingmock >> /home/devcontainer/.zshrc",
"remoteUser": "devcontainer",
"features": {
"common-utils": {
"installZsh": true,
"installOhMyZshConfig": false
}
}
},
"configure_zsh_no_template_first_step": {
"image": "debian:bullseye",
"remoteUser": "devcontainer",
"features": {
"common-utils": {
"installZsh": true,
"installOhMyZshConfig": false
}
}
},
"config-subdirectory": {
"image": "alpine",
"remoteUser": "devcontainer",
@ -143,6 +164,7 @@
"build": {
"dockerfile": "Dockerfile"
},
"remoteUser": "vscode",
"features": {
"common-utils": {
"username": "vscode",
@ -151,7 +173,15 @@
"upgradePackages": true,
"installZsh": true
}
},
"remoteUser": "vscode"
}
},
"alpine-base-zsh-default": {
"image": "mcr.microsoft.com/devcontainers/base:alpine",
"remoteUser": "vscode",
"features": {
"common-utils": {
"configureZshAsDefaultShell": true
}
}
}
}

View file

@ -0,0 +1,18 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Feature specific tests
check "version" docker --version
check "docker-ps" bash -c "docker ps"
check "docker-init-exists" bash -c "ls /usr/local/share/docker-init.sh"
check "log-exists" bash -c "ls /tmp/dockerd.log"
check "log-for-completion" bash -c "cat /tmp/dockerd.log | grep 'Daemon has completed initialization'"
check "log-contents" bash -c "cat /tmp/dockerd.log | grep 'API listen on /var/run/docker.sock'"
# Report result
reportResults

View file

@ -67,6 +67,14 @@
}
},
"remoteUser": "node"
},
// DO NOT REMOVE: This scenario is used by the docker-in-docker-stress-test workflow
"docker_with_on_create_command": {
"image": "mcr.microsoft.com/devcontainers/base:debian",
"features": {
"docker-in-docker": {}
},
"remoteUser": "vscode",
"onCreateCommand": "docker ps && sleep 5s && docker ps"
}
}

View file

@ -8,10 +8,10 @@ source dev-container-features-test-lib
# Feature specific tests
check "version" docker --version
check "docker-init-exists" bash -c "ls /usr/local/share/docker-init.sh"
check "docker-ps" bash -c "docker ps"
check "log-exists" bash -c "ls /tmp/dockerd.log"
check "log-for-completion" bash -c "cat /tmp/dockerd.log | grep 'Daemon has completed initialization'"
check "log-contents" bash -c "cat /tmp/dockerd.log | grep 'API listen on /var/run/docker.sock'"
check "docker-ps" bash -c "docker ps"
# Report result
reportResults

View file

@ -0,0 +1,4 @@
#!/bin/bash
export DOTNET_NOLOGO=true
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
export DOTNET_GENERATE_ASPNET_CERTIFICATE=false

View file

@ -0,0 +1,71 @@
#!/bin/bash
# Prints the latest dotnet version in the specified channel
# Usage: fetch_latest_version_in_channel <channel> [<runtime>]
# Example: fetch_latest_version_in_channel "LTS"
# Example: fetch_latest_version_in_channel "6.0" "dotnet"
# Example: fetch_latest_version_in_channel "6.0" "aspnetcore"
fetch_latest_version_in_channel() {
local channel="$1"
local runtime="$2"
if [ "$runtime" = "dotnet" ]; then
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Runtime/$channel/latest.version"
elif [ "$runtime" = "aspnetcore" ]; then
wget -qO- "https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$channel/latest.version"
else
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Sdk/$channel/latest.version"
fi
}
# Prints the latest dotnet version
# Usage: fetch_latest_version [<runtime>]
# Example: fetch_latest_version
# Example: fetch_latest_version "dotnet"
# Example: fetch_latest_version "aspnetcore"
fetch_latest_version() {
local runtime="$1"
local sts_version
local lts_version
sts_version=$(fetch_latest_version_in_channel "STS" "$runtime")
lts_version=$(fetch_latest_version_in_channel "LTS" "$runtime")
if [[ "$sts_version" > "$lts_version" ]]; then
echo "$sts_version"
else
echo "$lts_version"
fi
}
# Asserts that the specified .NET SDK version is installed
# Returns a non-zero exit code if the check fails
# Usage: is_dotnet_sdk_version_installed <version>
# Example: is_dotnet_sdk_version_installed "6.0"
# Example: is_dotnet_sdk_version_installed "6.0.412"
is_dotnet_sdk_version_installed() {
local expected="$1"
dotnet --list-sdks | grep --fixed-strings --silent "$expected"
return $?
}
# Asserts that the specified .NET Runtime version is installed
# Returns a non-zero exit code if the check fails
# Usage: is_dotnet_runtime_version_installed <version>
# Example: is_dotnet_runtime_version_installed "6.0"
# Example: is_dotnet_runtime_version_installed "6.0.412"
is_dotnet_runtime_version_installed() {
local expected="$1"
dotnet --list-runtimes | grep --fixed-strings --silent "Microsoft.NETCore.App $expected"
return $?
}
# Asserts that the specified ASP.NET Core Runtime version is installed
# Returns a non-zero exit code if the check fails
# Usage: is_aspnetcore_runtime_version_installed <version>
# Example: is_aspnetcore_runtime_version_installed "6.0"
# Example: is_aspnetcore_runtime_version_installed "6.0.412"
is_aspnetcore_runtime_version_installed() {
local expected="$1"
dotnet --list-runtimes | grep --fixed-strings --silent "Microsoft.AspNetCore.App $expected"
return $?
}

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet version 6.0.301 installed as default" bash -c "dotnet --version | grep 6.0.301"
check "dotnet version 5.0 installed" bash -c "ls -l /usr/local/dotnet | grep 5.0"
check "dotnet version 3.1.420 installed" bash -c "ls -l /usr/local/dotnet | grep 3.1.420"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

View file

@ -0,0 +1,27 @@
#!/bin/bash
set -e
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
expected=$(fetch_latest_version "aspnetcore")
check "Latest ASP.NET Core Runtime version installed" \
is_aspnetcore_runtime_version_installed "$expected"
# Expect this check to fail in November 2023 when .NET 8.0 becomes GA
check "It is a flavor of .NET 7.0" \
is_aspnetcore_runtime_version_installed "7.0"
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 3 is installed" bash -c "dotnet --list-sdks | grep '3\.[0-9]*\.[0-9]*'"
check "dotnet version 3 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '3\.[0-9]*\.[0-9]*'"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 6 is installed" bash -c "dotnet --list-sdks | grep '6\.[0-9]*\.[0-9]*'"
check "dotnet version 6 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '6\.[0-9]*\.[0-9]*'"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 6 is installed" bash -c "dotnet --list-sdks | grep '6\.[0-9]*\.[0-9]*'"
check "dotnet version 6 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '6\.[0-9]*\.[0-9]*'"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 6 is installed" bash -c "dotnet --list-sdks | grep '6\.[0-9]*\.[0-9]*'"
check "dotnet version 6 installed" bash -c "ls -l /usr/lib/dotnet/sdk | grep '6\.[0-9]*\.[0-9]*'"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 7 is installed" bash -c "dotnet --list-sdks | grep '7\.[0-9]*\.[0-9]*'"
check "dotnet version 7 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '7\.[0-9]*\.[0-9]*'"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 7 is installed" bash -c "dotnet --list-sdks | grep '7\.[0-9]*\.[0-9]*'"
check "dotnet version 7 installed" bash -c "ls -l /usr/lib/dotnet/sdk | grep '7\.[0-9]*\.[0-9]*'"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

View file

@ -0,0 +1,24 @@
#!/bin/bash
set -e
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
check ".NET SDK 8.0.100-preview.6.23330.14 installed" \
is_dotnet_sdk_version_installed "8.0.100-preview.6.23330.14"
check "Build and run example project" \
dotnet run --project projects/net8.0
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -0,0 +1,25 @@
#!/bin/bash
set -e
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
# From https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools
check "Install a .NET global tool" \
dotnet tool install --global dotnetsay
check "Run the tool" \
dotnetsay "$(dotnet --info)"
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 7 is installed" bash -c "dotnet --list-sdks | grep '7\.[0-9]*\.[0-9]*'"
check "dotnet version 7 installed" bash -c "ls -l /usr/lib/dotnet/sdk | grep '7\.[0-9]*\.[0-9]*'"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

View file

@ -0,0 +1,30 @@
#!/bin/bash
set -e
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
expected=$(fetch_latest_version)
check "Latest .NET SDK version installed" \
is_dotnet_sdk_version_installed "$expected"
# Expect this check to fail in November 2023 when .NET 8.0 becomes GA
check "It is a flavor of .NET 7.0" \
is_dotnet_sdk_version_installed "7.0"
check "Build and run example project" \
dotnet run --project projects/net7.0
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -2,16 +2,25 @@
set -e
# Optional: Import test library
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 6 is installed" bash -c "dotnet --list-sdks | grep '6\.[0-9]*\.[0-9]*'"
check "dotnet version 6 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '6\.[0-9]*\.[0-9]*'"
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
expected=$(fetch_latest_version_in_channel "LTS")
# Report result
reportResults
check "Latest LTS version installed" \
is_dotnet_sdk_version_installed "$expected"
check "Build and run example project" \
dotnet run --project projects/net6.0
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -0,0 +1,30 @@
#!/bin/bash
set -e
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
check ".NET SDK 8.0 installed" \
is_dotnet_sdk_version_installed "8.0"
check ".NET SDK 7.0 installed" \
is_dotnet_sdk_version_installed "7.0"
check ".NET SDK 6.0 installed" \
is_dotnet_sdk_version_installed "6.0"
check "Build example class library" \
dotnet build projects/multitargeting
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -0,0 +1,27 @@
#!/bin/bash
set -e
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
expected=$(fetch_latest_version "dotnet")
check "Latest .NET Runtime version installed" \
is_dotnet_runtime_version_installed "$expected"
# Expect this check to fail in November 2023 when .NET 8.0 becomes GA
check "It is a flavor of .NET 7.0" \
is_dotnet_runtime_version_installed "7.0"
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -0,0 +1,26 @@
#!/bin/bash
set -e
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
expected=$(fetch_latest_version_in_channel "3.1")
check ".NET Core SDK 3.1 installed" \
is_dotnet_sdk_version_installed "$expected"
check "Build and run example project" \
dotnet run --project projects/netcoreapp3.1
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -0,0 +1,24 @@
#!/bin/bash
set -e
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
check ".NET SDK 5.0.3xx installed" \
is_dotnet_sdk_version_installed "5.0.3"
check "Build and run example project" \
dotnet run --project projects/net5.0
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
check "dotnet sdks" dotnet --list-sdks
check "some major version of dotnet 7 is installed" bash -c "dotnet --list-sdks | grep '7\.[0-9]*\.[0-9]*'"
check "dotnet version 7 installed" bash -c "ls -l /usr/local/dotnet | grep '7\.[0-9]*\.[0-9]*'"
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
# Report result
reportResults

2
test/dotnet/projects/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
bin
obj

View file

@ -0,0 +1,4 @@
public class Class1
{
}

View file

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
string json = @"{
""Name"": ""Inception"",
""ReleaseDate"": ""2010-07-08T00:00:00"",
""Genres"": [
""Action"",
""Thriller""
]
}";
Movie? m = JsonConvert.DeserializeObject<Movie>(json);
if (m == default)
{
Console.WriteLine("Decoding failed!");
}
else
{
Console.WriteLine($"Movie name: {m.Name}");
Console.WriteLine($"Release Date: {m.ReleaseDate}");
Console.WriteLine($"Genres: {string.Join(", ", m.Genres)}");
}
class Movie
{
public string Name { get; set; } = "Default Name";
public DateTime ReleaseDate { get; set; }
public List<string> Genres { get; set; } = new List<string>();
}

View file

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,30 @@
using Newtonsoft.Json;
string json = @"{
""Name"": ""Inception"",
""ReleaseDate"": ""2010-07-08T00:00:00"",
""Genres"": [
""Action"",
""Thriller""
]
}";
Movie? m = JsonConvert.DeserializeObject<Movie>(json);
if (m == default)
{
Console.WriteLine("Decoding failed!");
}
else
{
Console.WriteLine($"Movie name: {m.Name}");
Console.WriteLine($"Release Date: {m.ReleaseDate}");
Console.WriteLine($"Genres: {string.Join(", ", m.Genres)}");
}
class Movie
{
public string Name { get; set; } = "Default Name";
public DateTime ReleaseDate { get; set; }
public List<string> Genres { get; set; } = new List<string>();
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,30 @@
using Newtonsoft.Json;
string json = @"{
""Name"": ""Inception"",
""ReleaseDate"": ""2010-07-08T00:00:00"",
""Genres"": [
""Action"",
""Thriller""
]
}";
Movie? m = JsonConvert.DeserializeObject<Movie>(json);
if (m == default)
{
Console.WriteLine("Decoding failed!");
}
else
{
Console.WriteLine($"Movie name: {m.Name}");
Console.WriteLine($"Release Date: {m.ReleaseDate}");
Console.WriteLine($"Genres: {string.Join(", ", m.Genres)}");
}
class Movie
{
public string Name { get; set; } = "Default Name";
public DateTime ReleaseDate { get; set; }
public List<string> Genres { get; set; } = new List<string>();
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,32 @@
using Newtonsoft.Json;
string json = """
{
"Name": "Inception",
"ReleaseDate": "2010-07-08T00:00:00",
"Genres": [
"Action",
"Thriller"
]
}
""";
Movie? m = JsonConvert.DeserializeObject<Movie>(json);
if (m == default)
{
Console.WriteLine("Decoding failed!");
}
else
{
Console.WriteLine($"Movie name: {m.Name}");
Console.WriteLine($"Release Date: {m.ReleaseDate}");
Console.WriteLine($"Genres: {string.Join(", ", m.Genres)}");
}
class Movie
{
public string Name { get; set; } = "Default Name";
public DateTime ReleaseDate { get; set; }
public List<string> Genres { get; set; } = new List<string>();
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
class Program
{
public static void Main()
{
string json = @"{
""Name"": ""Inception"",
""ReleaseDate"": ""2010-07-08T00:00:00"",
""Genres"": [
""Action"",
""Thriller""
]
}";
Movie? m = JsonConvert.DeserializeObject<Movie>(json);
if (m == default)
{
Console.WriteLine("Decoding failed!");
}
else
{
Console.WriteLine($"Movie name: {m.Name}");
Console.WriteLine($"Release Date: {m.ReleaseDate}");
Console.WriteLine($"Genres: {string.Join(", ", m.Genres)}");
}
}
}
class Movie
{
public string Name { get; set; } = "Default Name";
public DateTime ReleaseDate { get; set; }
public List<string> Genres { get; set; } = new List<string>();
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

View file

@ -1,83 +1,84 @@
{
"install_additional_dotnet": {
"image": "ubuntu:focal",
"features": {
"dotnet": {
"version": "6.0.301",
"additionalVersions": "5.0,3.1.420"
}
}
},
"install_dotnet_3": {
"image": "ubuntu:focal",
"features": {
"dotnet": {
"version": "3"
}
}
},
"install_dotnet_6_bullseye": {
"image": "debian:bullseye",
"features": {
"dotnet": {
"version": "6"
}
}
},
"install_dotnet_6_focal": {
"image": "ubuntu:focal",
"features": {
"dotnet": {
"version": "6"
}
}
},
"install_dotnet_7_bullseye": {
"image": "debian:bullseye",
"features": {
"dotnet": {
"version": "7"
}
}
},
"install_dotnet_7_jammy": {
"image": "ubuntu:jammy",
"features": {
"dotnet": {
"version": "7"
}
}
},
"install_dotnet_6_jammy": {
"image": "mcr.microsoft.com/devcontainers/base:jammy",
"features": {
"dotnet": {
"version": "6"
}
}
},
"install_dotnet_latest": {
"image": "ubuntu:jammy",
"features": {
"dotnet": {
"version": "latest"
}
}
},
"install_dotnet_lts": {
"image": "ubuntu:focal",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"remoteUser": "vscode",
"features": {
"dotnet": {
"version": "lts"
}
}
},
"install_wo_apt": {
"image": "ubuntu:jammy",
"install_dotnet_specific_release": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-20.04",
"remoteUser": "vscode",
"features": {
"dotnet": {
"version": "7",
"installUsingApt": false
"version": "3.1"
}
}
},
"install_dotnet_specific_release_and_feature_band": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-20.04",
"remoteUser": "vscode",
"features": {
"dotnet": {
"version": "5.0.3xx"
}
}
},
"install_dotnet_exact_version": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"remoteUser": "vscode",
"features": {
"dotnet": {
"version": "8.0.100-preview.6.23330.14"
}
}
},
"install_dotnet_multiple_versions": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"remoteUser": "vscode",
"features": {
"dotnet": {
"version": "8.0.100-preview.6.23330.14",
"additionalVersions": [
"7.0",
"6.0"
]
}
}
},
"install_dotnet_global_tool": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"remoteUser": "vscode",
"features": {
"dotnet": {}
}
},
"install_dotnet_latest_when_version_is_empty": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"remoteUser": "vscode",
"features": {
"dotnet": ""
}
},
"install_dotnet_runtime_only": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"remoteUser": "vscode",
"features": {
"dotnet": {
"version": "none",
"dotnetRuntimeVersions": "latest"
}
}
},
"install_aspnetcore_runtime_only": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"remoteUser": "vscode",
"features": {
"dotnet": {
"version": "none",
"aspnetcoreRuntimeVersions": "latest"
}
}
}

31
test/dotnet/test.sh Executable file → Normal file
View file

@ -2,20 +2,29 @@
set -e
# Optional: Import test library
# Optional: Import test library bundled with the devcontainer CLI
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
# Provides the 'check' and 'reportResults' commands.
source dev-container-features-test-lib
# Definition specific tests
check "dotnet" dotnet --info
check "sdks" dotnet --list-sdks
check "version" dotnet --version
# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
# check <LABEL> <cmd> [args...]
source dotnet_env.sh
source dotnet_helpers.sh
echo "Validating expected version present..."
check "some major version of dotnet (7/8) is installed" bash -c "dotnet --version | grep '[7-8]\.[0-9]*\.[0-9]*'"
expected=$(fetch_latest_version)
# Verify current symlink exists and works
check "current link dotnet" /usr/local/dotnet/current/dotnet --info
check "current link sdk" ls -l /usr/local/dotnet/current/sdk
check "Latest .NET SDK version installed" \
is_dotnet_sdk_version_installed "$expected"
# Report result
# Expect this check to fail in November 2023 when .NET 8.0 becomes GA
check "It is a flavor of .NET 7.0" \
is_dotnet_sdk_version_installed "7.0"
check "Build and run example project" \
dotnet run --project projects/net7.0
# Report results
# If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults

14
test/node/install_nvm_0.39.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Definition specific tests
check "version" bash -c "node --version"
check "pnpm" pnpm -v
check "nvm version" bash -c ". /usr/local/share/nvm/nvm.sh && nvm --version | grep 0.39"
# Report result
reportResults

View file

@ -17,6 +17,17 @@
}
}
},
"zsh_default": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"node": {
"version": "lts"
},
"common-utils": {
"configureZshAsDefaultShell": true
}
}
},
"version_none": {
"image": "mcr.microsoft.com/devcontainers/base",
"remoteUser": "vscode",
@ -26,15 +37,6 @@
}
}
},
"install_node_on_universal_image": {
"image": "mcr.microsoft.com/devcontainers/universal",
"remoteUser": "codespace",
"features": {
"node": {
"version": "19.1.0"
}
}
},
"install_node_16_on_bionic": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-18.04",
"features": {
@ -42,5 +44,13 @@
"version": "16"
}
}
},
"install_nvm_0.39": {
"image": "mcr.microsoft.com/devcontainers/base",
"features": {
"node": {
"nvmVersion": "0.39"
}
}
}
}

12
test/node/zsh_default.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Definition specific tests
check "nvm" bash -c ". /usr/local/share/nvm/nvm.sh && nvm install 10"
# Report result
reportResults