Skip to content

Change ruby feature to use mise by default #86

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Rails Dev Container Images & Features

This repository contains dev container images and features that can be used to create a convenient and consistent
This repository contains dev container images and features that can be used to create a convenient and consistent
development environment for working on Rails applications.

## What is a dev container?

A **dev container** is a running Docker container that provides a fully-featured development environment which can be
used to run an application, to separate tools, libraries, or runtimes needed for working with a codebase, and to aid in
A **dev container** is a running Docker container that provides a fully-featured development environment which can be
used to run an application, to separate tools, libraries, or runtimes needed for working with a codebase, and to aid in
continuous integration and testing. **Dev container features** are self-contained units of installation and configuration
that can be installed on top of a container image to provide additional functionality in a container. **Dev container
images** are prebuilt docker images based on dev container features. For more information on the dev container
Expand All @@ -30,8 +30,8 @@ would look like this:
}
```

This dev container uses the Ruby image, which includes an installation of Ruby (in this case version 3.3.0) and the RBenv
version manager, as well as other common utilities such as Git. It also uses the Active Storage feature, which installs
This dev container uses the Ruby image, which includes an installation of Ruby (in this case version 3.3.0) and a Ruby
version manager (mise by default, but configurable to use rbenv), as well as other common utilities such as Git. It also uses the Active Storage feature, which installs
dependencies needed for Active Storage.

The dev container can be initialized [by VSCode](https://code.visualstudio.com/docs/devcontainers/containers) or by using
Expand All @@ -50,9 +50,9 @@ This repository is open for contributions. See [the contributions guide](CONTRIB

You can create your own features, and images based on them.

The best place to start is the [feature starter repository](https://github.com/devcontainers/feature-starter) which is
The best place to start is the [feature starter repository](https://github.com/devcontainers/feature-starter) which is
maintained by the devcontainers org.

## License

The repository is released under the [MIT License](https://opensource.org/licenses/MIT).
The repository is released under the [MIT License](https://opensource.org/licenses/MIT).
20 changes: 20 additions & 0 deletions features/src/ruby/NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
## OS Support

This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.

## Changing the Ruby Version

```json
"features": {
"ghcr.io/rails/devcontainer/features/ruby:1": {
"version": "3.3.0"
}
}
```

## Changing the Version Manager

```json
"features": {
"ghcr.io/rails/devcontainer/features/ruby:1": {
"versionManager": "rbenv"
}
}
```
35 changes: 30 additions & 5 deletions features/src/ruby/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Ruby (via rbenv)
# Ruby

Installs Ruby, rbenv, and ruby-build as well as the dependencies needed to build Ruby.
Installs Ruby and a version manager (mise or rbenv) along with the dependencies needed to build Ruby.

## Example Usage

### Using mise (default)

```json
"features": {
"ghcr.io/rails/devcontainer/features/ruby:1": {
Expand All @@ -12,11 +14,34 @@ Installs Ruby, rbenv, and ruby-build as well as the dependencies needed to build
}
```

### Using rbenv

```json
"features": {
"ghcr.io/rails/devcontainer/features/ruby:1": {
"version": "3.3.0",
"versionManager": "rbenv"
}
}
```

### Using mise explicitly

```json
"features": {
"ghcr.io/rails/devcontainer/features/ruby:1": {
"version": "3.3.0",
"versionManager": "mise"
}
}
```

## Options

| Options Id | Description | Type |
|-----|-----|-----|
| version | The version of ruby to be installed | string |
| Options Id | Description | Type | Default Value |
|-----|-----|-----|-----|
| version | The version of ruby to be installed | string | 3.4.1 |
| versionManager | The version manager to use for Ruby (mise or rbenv) | string | mise |

## Customizations

Expand Down
18 changes: 12 additions & 6 deletions features/src/ruby/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
{
"id": "ruby",
"version": "1.1.3",
"name": "Ruby (via rbenv)",
"description": "Installs Ruby, rbenv, and ruby-build as well as the dependencies needed to build Ruby.",
"version": "2.0.0",
"name": "Ruby",
"description": "Installs Ruby and a version manager (mise or rbenv) along with libraries needed to build Ruby.",
"customizations": {
"vscode": {
"extensions": [
"shopify.ruby-lsp"
]
}
},
"containerEnv": {
"PATH": "/usr/local/share/rbenv/bin:${PATH}"
},
"installsAfter": [
"ghcr.io/devcontainers/features/common-utils"
],
Expand All @@ -21,6 +18,15 @@
"type": "string",
"default": "3.4.4",
"description": "The ruby version to be installed"
},
"versionManager": {
"type": "string",
"proposals": [
"mise",
"rbenv"
],
"default": "mise",
"description": "The version manager to use for Ruby (mise or rbenv)"
}
}
}
124 changes: 104 additions & 20 deletions features/src/ruby/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,119 @@
set -e

USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
VERSION_MANAGER="${VERSIONMANAGER:-"mise"}"

apt-get update -y
apt-get -y install --no-install-recommends git curl ca-certificates libssl-dev libreadline-dev zlib1g-dev autoconf bison build-essential \
libyaml-dev libncurses5-dev libffi-dev libgdbm-dev libxml2-dev rustc
# Function to install dependencies needed for building Ruby
install_dependencies() {
apt-get update -y
DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
git \
curl \
ca-certificates \
libssl-dev \
libreadline-dev \
zlib1g-dev \
autoconf \
bison \
build-essential \
libyaml-dev \
libncurses5-dev \
libffi-dev \
libgdbm-dev \
libxml2-dev \
rustc
}

git clone https://github.com/rbenv/rbenv.git /usr/local/share/rbenv
git clone https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build
# Function to add lines to shell initialization files
add_to_shell_init() {
_user="$1"
_bash_line="$2"
_zsh_line="${3:-$_bash_line}" # Use bash_line as default if zsh_line not provided

mkdir -p /root/.rbenv/plugins
ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build
if [ "$_user" = "root" ]; then
_home_dir="/root"
else
_home_dir="/home/$_user"
fi

echo "$_bash_line" >> "$_home_dir/.bashrc"

if [ -f "$_home_dir/.zshrc" ]; then
echo "$_zsh_line" >> "$_home_dir/.zshrc"
fi
}

# Function to setup rbenv
setup_rbenv() {
_user="$1"
_user_home="/home/$_user"

if [ "${USERNAME}" != "root" ]; then
user_home="/home/${USERNAME}"
mkdir -p "${user_home}/.rbenv/plugins"
ln -s /usr/local/share/ruby-build "${user_home}/.rbenv/plugins/ruby-build"
# Clone rbenv and ruby-build
git clone https://github.com/rbenv/rbenv.git /usr/local/share/rbenv
git clone https://github.com/rbenv/ruby-build.git /usr/local/share/ruby-build

chown -R "${USERNAME}" "${user_home}/.rbenv/"
chmod -R g+r+w "${user_home}/.rbenv"
# Setup plugins for root
mkdir -p /root/.rbenv/plugins
ln -s /usr/local/share/ruby-build /root/.rbenv/plugins/ruby-build

# Setup for non-root user if needed
if [ "$_user" != "root" ]; then
mkdir -p "$_user_home/.rbenv/plugins"
ln -s /usr/local/share/ruby-build "$_user_home/.rbenv/plugins/ruby-build"
chown -R "$_user" "$_user_home/.rbenv/"
chmod -R g+r+w "$_user_home/.rbenv"
fi

# shellcheck disable=SC2016
add_to_shell_init "$_user" 'export PATH="/usr/local/share/rbenv/bin:$PATH"'
# shellcheck disable=SC2016
echo 'eval "$(rbenv init -)"' >> "${user_home}/.bashrc"
add_to_shell_init "$_user" 'eval "$(rbenv init -)"'
}

# Function to install Ruby with rbenv
install_ruby_rbenv() {
_user="$1"
_version="$2"

su "$_user" -c "/usr/local/share/rbenv/bin/rbenv install $_version"
su "$_user" -c "/usr/local/share/rbenv/bin/rbenv global $_version"
}

if [ -f "${user_home}/.zshrc" ]; then
# shellcheck disable=SC2016
echo 'eval "$(rbenv init -)"' >> "${user_home}/.zshrc"
# Function to setup mise
setup_mise() {
_user="$1"

su "$_user" -c "curl https://mise.run | sh"

# shellcheck disable=SC2016
add_to_shell_init "$_user" 'eval "$(~/.local/bin/mise activate bash)"' 'eval "$(~/.local/bin/mise activate zsh)"'
}

# Function to install Ruby with mise
install_ruby_mise() {
_user="$1"
_version="$2"

if [ "$_user" = "root" ]; then
_home_dir="/root"
else
_home_dir="/home/$_user"
fi
fi

su "${USERNAME}" -c "/usr/local/share/rbenv/bin/rbenv install $VERSION"
su "${USERNAME}" -c "/usr/local/share/rbenv/bin/rbenv global $VERSION"
su "$_user" -c "$_home_dir/.local/bin/mise install ruby@$_version"
su "$_user" -c "$_home_dir/.local/bin/mise use -g ruby@$_version"
su "$_user" -c "$_home_dir/.local/bin/mise settings add idiomatic_version_file_enable_tools ruby"
}

install_dependencies

# Setup version manager and install Ruby based on user choice
if [ "$VERSION_MANAGER" = "rbenv" ]; then
setup_rbenv "$USERNAME"
install_ruby_rbenv "$USERNAME" "$VERSION"
else
setup_mise "$USERNAME"
install_ruby_mise "$USERNAME" "$VERSION"
fi

rm -rf /var/lib/apt/lists/*
8 changes: 8 additions & 0 deletions features/test/ruby/scenarios.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,13 @@
"version": "3.3.0"
}
}
},
"with_rbenv": {
"image": "mcr.microsoft.com/devcontainers/base:1-bookworm",
"features": {
"ruby": {
"versionManager": "rbenv"
}
}
}
}
9 changes: 4 additions & 5 deletions features/test/ruby/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ set -e
# shellcheck source=/dev/null
source dev-container-features-test-lib

check "PATH contains rbenv" bash -c "echo $PATH | grep rbenv"
check "rbenv is installed" bash -c "rbenv --version"
check "ruby-build is installed" bash -c "ls -l $HOME/.rbenv/plugins/ruby-build | grep '\-> /usr/local/share/ruby-build'"
eval "$(rbenv init -)"
check "mise is installed" bash -c "mise --version"
check "mise init is sourced in the bashrc" bash -c "grep 'eval \"\$(~/.local/bin/mise activate bash)\"' $HOME/.bashrc"
check "mise idiomatic version file is enabled for ruby" bash -c "mise settings | grep idiomatic_version_file_enable_tools | grep ruby"
check "Ruby is installed with YJIT" bash -c "RUBY_YJIT_ENABLE=1 ruby -v | grep +YJIT"
check "Ruby version is set to 3.4.4" bash -c "rbenv global | grep 3.4.4"
check "Ruby version is set to 3.4.4" bash -c "mise use -g ruby | grep 3.4.4"

reportResults
11 changes: 5 additions & 6 deletions features/test/ruby/version_3_3_0.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ set -e
# shellcheck source=/dev/null
source dev-container-features-test-lib

check "PATH contains rbenv" bash -c "echo $PATH | grep rbenv"
check "rbenv is installed" bash -c "rbenv --version"
check "ruby-build is installed" bash -c "ls -l $HOME/.rbenv/plugins/ruby-build | grep '\-> /usr/local/share/ruby-build'"
check "rbenv init is sourced in the bashrc" bash -c "grep 'eval \"\$(rbenv init -)\"' $HOME/.bashrc"
check "rbenv init is sourced in the zshrc" bash -c "grep 'eval \"\$(rbenv init -)\"' $HOME/.zshrc"
check "mise is installed" bash -c "mise --version"
check "mise init is sourced in the bashrc" bash -c "grep 'eval \"\$(~/.local/bin/mise activate bash)\"' $HOME/.bashrc"
check "mise init is sourced in the zshrc" bash -c "grep 'eval \"\$(~/.local/bin/mise activate zsh)\"' $HOME/.zshrc"
check "mise idiomatic version file is enabled for ruby" bash -c "mise settings | grep idiomatic_version_file_enable_tools | grep ruby"
check "Ruby is installed with YJIT" bash -c "RUBY_YJIT_ENABLE=1 ruby -v | grep +YJIT"
check "Ruby version is set to 3.3.0" bash -c "rbenv global | grep 3.3.0"
check "Ruby version is set to 3.3.0" bash -c "mise use -g ruby | grep 3.3.0"

reportResults
14 changes: 14 additions & 0 deletions features/test/ruby/with_rbenv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
set -e

# shellcheck source=/dev/null
source dev-container-features-test-lib

check "PATH contains rbenv" bash -c "echo $PATH | grep rbenv"
check "rbenv is installed" bash -c "rbenv --version"
check "ruby-build is installed" bash -c "ls -l $HOME/.rbenv/plugins/ruby-build | grep '\-> /usr/local/share/ruby-build'"
eval "$(rbenv init -)"
check "Ruby is installed with YJIT" bash -c "RUBY_YJIT_ENABLE=1 ruby -v | grep +YJIT"
check "Ruby version is set to 3.4.4" bash -c "rbenv global | grep 3.4.4"

reportResults
2 changes: 1 addition & 1 deletion images/ruby/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"ghcr.io/rails/devcontainer/features/ruby": {
"version": "${localEnv:RUBY_VERSION}"
},
}
},
// Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
Expand Down