Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
43b4e70
refa(devcontainer): rework to use mise for fast switching
solnic May 11, 2026
7df491c
fix(ci): update workflows for mise-based devcontainer
solnic May 11, 2026
d6cd2e6
fix(e2e): use playwright-managed chromium
solnic May 11, 2026
ced5fca
refa(workflows): update build_images and e2e_tests for Ruby 4.0 and 3.4
solnic May 11, 2026
c157829
fix(devcontainer): set DEBIAN_FRONTEND to noninteractive for apt-get …
solnic May 11, 2026
2cd8c42
fix(devcontainer): correct mise command usage in entrypoint script
solnic May 11, 2026
fcca3ee
fix(devcontainer): remove unnecessary trust command from entrypoint s…
solnic May 11, 2026
d4888c1
fix(e2e): use dynamic IMAGE_TAG for Docker image in e2e tests
solnic May 11, 2026
4ba7828
fix(devcontainer): set DEBIAN_FRONTEND environment variable before ap…
solnic May 11, 2026
a184ffb
fix(devcontainer): comment out pull_request trigger in build_images.yml
solnic May 11, 2026
3f0330c
fix(devcontainer): update base image and Ruby version in .env.example
solnic May 11, 2026
9929d92
fix(devcontainer): versioned containers
solnic May 11, 2026
5406008
fix(devcontainer): enable manual workflow dispatch and clean up comments
solnic May 11, 2026
b6e5dbd
fix(devcontainer): update image tagging to use version from .devconta…
solnic May 11, 2026
d4b3958
fix(devcontainer): add comments for triggering workflow in topic bran…
solnic May 11, 2026
7b423cd
fix(devcontainer): update BASE_IMAGE to use Ubuntu 24.04
solnic May 11, 2026
7b6ef3a
fix(devcontainer): clean up .env.example by removing legacy comments …
solnic May 11, 2026
c5e368a
fix(devcontainer): add e2e profile to sentry-test service and update …
solnic May 11, 2026
f1827bc
fix(devcontainer): pre-install Java 21 in Dockerfile for JRuby support
solnic May 11, 2026
8d20a8c
chore(mise): set ruby version to 'ruby@latest' and add java version t…
solnic May 11, 2026
26662b2
fix(devcontainer): pre-install precompiled Ruby version in Dockerfile
solnic May 11, 2026
9c27785
chore(devcontainer): remove dead method from setup
solnic May 11, 2026
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
7 changes: 2 additions & 5 deletions .devcontainer/.env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Official Ruby images
IMAGE="ruby:3.4.5-slim-bookworm"
VERSION="3.4.5"

# IMAGE="jruby:latest"
# Devcontainer configuration
RUBY_VERSION="3.4.9"

# E2E testing
SENTRY_DSN="http://user:pass@sentry.localhost/project/42"
Expand Down
55 changes: 46 additions & 9 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
ARG IMAGE="ruby"
ARG BASE_IMAGE=ubuntu:24.04
FROM ${BASE_IMAGE}

FROM ${IMAGE} AS build
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y --no-install-recommends \
sudo \
gnupg \
git \
curl \
wget \
ca-certificates \
build-essential \
pkg-config \
libssl-dev \
Expand All @@ -21,27 +23,62 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libgdbm-dev \
sqlite3 \
libsqlite3-dev \
tzdata \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN echo "sentry ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/sentry \
&& chmod 0440 /etc/sudoers.d/sentry

RUN groupadd --gid 1000 sentry \
RUN userdel -r ubuntu 2>/dev/null || true \
&& groupdel ubuntu 2>/dev/null || true \
&& groupadd --gid 1000 sentry \
&& useradd --uid 1000 --gid sentry --shell /bin/bash --create-home sentry

WORKDIR /workspace/sentry

RUN chown -R sentry:sentry /workspace/sentry

ARG VERSION
ARG GEM_HOME="/workspace/sentry/vendor/gems/${VERSION}"

ENV LANG=C.UTF-8 \
BUNDLE_JOBS=4 \
BUNDLE_RETRY=3 \
GEM_HOME=/workspace/sentry/vendor/gems/${VERSION} \
PATH=$PATH:${GEM_HOME}/bin \
REDIS_HOST=redis
REDIS_HOST=redis \
PATH=/home/sentry/.local/share/mise/shims:/home/sentry/.local/bin:$PATH

USER sentry

# Pre-create the bundle directory owned by sentry so that a Docker named volume
# mounted here is initialised with the correct ownership (Docker copies image
# directory content when a volume is first attached).
RUN mkdir -p /home/sentry/bundle

RUN curl https://mise.run | sh \
&& echo 'eval "$(/home/sentry/.local/bin/mise activate bash)"' >> /home/sentry/.bashrc \
&& echo 'eval "$(/home/sentry/.local/bin/mise activate zsh)"' >> /home/sentry/.zshenv

# When RUBY_VERSION is provided at build time, pre-install that Ruby so the
# container starts immediately without downloading it at runtime. When it is
# empty (local dev builds) Ruby is installed lazily by the `run` entrypoint.
ARG RUBY_VERSION=""

# Java is always installed (required for JRuby). It is listed in .mise.toml so
# it is available for all users regardless of which Ruby flavour they use.
RUN echo "📦 Pre-installing java@temurin-21..." && \
/home/sentry/.local/bin/mise install "java@temurin-21" && \
/home/sentry/.local/bin/mise use --global "java@temurin-21"

RUN if [ -n "${RUBY_VERSION}" ]; then \
echo "📦 Pre-installing ruby@${RUBY_VERSION} (precompiled)..." && \
MISE_RUBY_COMPILE=0 /home/sentry/.local/bin/mise install "ruby@${RUBY_VERSION}" && \
/home/sentry/.local/bin/mise use --global "ruby@${RUBY_VERSION}"; \
fi

# Node.js is always needed for the svelte-mini e2e app.
RUN echo "📦 Pre-installing node@lts..." && \
/home/sentry/.local/bin/mise install "node@lts" && \
/home/sentry/.local/bin/mise use --global "node@lts"

# Install headless Chromium via Playwright (includes all system dependencies).
# Symlink the binary into ~/.local/bin which is already on PATH.
RUN /home/sentry/.local/share/mise/shims/npx playwright install chromium --with-deps
RUN bash -c 'ln -sf /home/sentry/.cache/ms-playwright/chromium-*/chrome-linux/chrome /home/sentry/.local/bin/chromium'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chromium symlink broken on x86_64 Linux builds

High Severity

The symlink hardcodes chrome-linux/chrome, but Playwright ≥1.57 on Linux x64 installs Chromium under chrome-linux64/chrome. Since CI uses ubuntu-latest (x86_64) and npx playwright install chromium fetches the latest version, the glob resolves to a non-existent subdirectory, creating a broken symlink. File.exist? in spec_helper.rb then returns false, so options.binary is never set, and Selenium cannot locate the Chrome binary — breaking e2e tests on x64 runners. The path chrome-linux/chrome only works on ARM64, which appears to be where the author tested (PR description shows aarch64-linux).

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9c27785. Configure here.

1 change: 1 addition & 0 deletions .devcontainer/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
29 changes: 29 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"features": {
"ghcr.io/devcontainers-extra/features/npm-packages:latest": {
"version": "1.0.1",
"resolved": "ghcr.io/devcontainers-extra/features/npm-packages@sha256:0851cc312204f4044f22230986134026409565f9e632d8ab2b8c639e81cedd7c",
"integrity": "sha256:0851cc312204f4044f22230986134026409565f9e632d8ab2b8c639e81cedd7c"
},
"ghcr.io/devcontainers/features/github-cli:latest": {
"version": "1.1.0",
"resolved": "ghcr.io/devcontainers/features/github-cli@sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671",
"integrity": "sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671"
},
"ghcr.io/devcontainers/features/node:latest": {
"version": "2.0.0",
"resolved": "ghcr.io/devcontainers/features/node@sha256:fedd4c11f7adfb64283b578dddc7da906728daa25fa293351c9d913231acf12f",
"integrity": "sha256:fedd4c11f7adfb64283b578dddc7da906728daa25fa293351c9d913231acf12f"
},
"ghcr.io/nils-geistmann/devcontainers-features/zsh:latest": {
"version": "0.0.8",
"resolved": "ghcr.io/nils-geistmann/devcontainers-features/zsh@sha256:fd57a61a5187480b5e73f8041be5b67005be48f06503736df6cfdd8d0f38f3c4",
"integrity": "sha256:fd57a61a5187480b5e73f8041be5b67005be48f06503736df6cfdd8d0f38f3c4"
},
"ghcr.io/rocker-org/devcontainer-features/apt-packages:latest": {
"version": "1.0.2",
"resolved": "ghcr.io/rocker-org/devcontainer-features/apt-packages@sha256:87a4d7750a596a5db034ba8508782f31aebdc2ffe955c66aaecb33d9de2ecdae",
"integrity": "sha256:87a4d7750a596a5db034ba8508782f31aebdc2ffe955c66aaecb33d9de2ecdae"
}
}
}
3 changes: 1 addition & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
"workspaceFolder": "/workspace/sentry",
"features": {
"ghcr.io/devcontainers/features/github-cli:latest": {},
"ghcr.io/devcontainers-extra/features/mise:latest": {},
"ghcr.io/nils-geistmann/devcontainers-features/zsh:latest": {},
"ghcr.io/devcontainers/features/node:latest": {},
"ghcr.io/devcontainers-extra/features/npm-packages:latest": {},
"ghcr.io/rocker-org/devcontainer-features/apt-packages:latest": {
"packages": "inotify-tools"
"packages": "inotify-tools,tzdata"
}
},
"customizations": {
Expand Down
19 changes: 13 additions & 6 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@ services:
context: ..
dockerfile: .devcontainer/Dockerfile
args:
IMAGE: ${IMAGE}
VERSION: ${VERSION}
BASE_IMAGE: ${BASE_IMAGE:-ubuntu:24.04}
volumes:
- ..:/workspace/sentry:cached
working_dir: /workspace/sentry
env_file: [".env"]

sentry-dev:
<<: *sentry-build
entrypoint: ".devcontainer/run --service dev"
command: "sleep infinity"
entrypoint: [".devcontainer/run"]
depends_on:
- redis

sentry-test:
<<: *sentry-build
entrypoint: ".devcontainer/run --service test"
command: ["foreman", "start"]
profiles: ["e2e"]
entrypoint: [".devcontainer/run"]
command: ["mise", "run", "e2e:serve"]
environment:
BUNDLE_PATH: /home/sentry/bundle
volumes:
- ..:/workspace/sentry:cached
- bundle-gems:/home/sentry/bundle
ports:
- "${SENTRY_E2E_RAILS_APP_PORT}:4000"
- "${SENTRY_E2E_SVELTE_APP_PORT}:4001"
Expand All @@ -33,3 +37,6 @@ services:
- ALLOW_EMPTY_PASSWORD=yes
ports:
- "6379:6379"

volumes:
bundle-gems:
114 changes: 40 additions & 74 deletions .devcontainer/run
Original file line number Diff line number Diff line change
@@ -1,92 +1,58 @@
#!/bin/bash

set -e
#
# Container entrypoint.
#
# Order of operations:
# 1. Set up mise (the Ruby version manager) for this shell.
# 2. Ensure the desired Ruby is installed (precompiled, no source build).
# 3. Hand off to whatever docker-compose passes as `command`.
#
set -euo pipefail

cd /workspace/sentry

sudo mkdir -p vendor/gems
sudo chown -R sentry:sentry vendor/gems

# git config --global --replace-all safe.directory /workspace/sentry
# git config --global --replace-all safe.directory /workspace/sentry/vendor/gems/*

sudo chown -R sentry:sentry .

run_service_setup() {
local service="$1"
# In CI the workspace is checked out by the runner user (e.g. UID 1001) and
# then bind-mounted into the container where we run as sentry (UID 1000).
# Fix ownership once here so bundler, git, etc. can write freely.
sudo chown -R sentry:sentry /workspace/sentry 2>/dev/null || true
MISE_BIN="/home/sentry/.local/bin/mise"

echo "🚀 Running setup for service: $service"
# Git also refuses to operate in directories owned by a different user.
git config --global --add safe.directory /workspace/sentry 2>/dev/null || true

case "$service" in
"dev")
if ! .devcontainer/setup --with-foreman --only-bundle; then
echo "❌ Setup failed for service: $service"
exit 1
fi
;;
"test")
if ! .devcontainer/setup --with-foreman --only .,spec/apps/rails-mini; then
echo "❌ Setup failed for service: $service"
exit 1
fi
;;
*)
echo "❌ Unknown service: $service"
echo "Available services: dev, test"
exit 1
;;
esac
# ---- 1. mise setup -----------------------------------------------------------

echo "✅ Setup completed for service: $service"
}

# Function to start services in background
start_services_if_needed() {
# Check if we're running tests (bundle exec rake)
if [[ "$*" == *"bundle exec rake"* ]]; then
echo "🚀 Starting e2e services in background for test execution..."
if [[ ! -x "$MISE_BIN" ]]; then
echo "❌ mise not found at $MISE_BIN (it should be installed by the Dockerfile)"
exit 1
fi

# Start foreman in background
foreman start &
FOREMAN_PID=$!
# Activate mise for this shell so PATH/shims are resolved correctly.
eval "$("$MISE_BIN" activate bash)"

# Wait for services to be ready
echo "⏳ Waiting for services to start..."
for i in {1..30}; do
if curl -f http://localhost:4000/health >/dev/null 2>&1 && \
curl -f http://localhost:4001/health >/dev/null 2>&1; then
echo "✅ Services are ready!"
break
fi
# Trust the workspace config so mise will use it without prompting.
"$MISE_BIN" trust /workspace/sentry >/dev/null

if [ $i -eq 30 ]; then
echo "❌ Services failed to start within timeout"
kill $FOREMAN_PID 2>/dev/null || true
exit 1
fi
# ---- 2. Install Ruby (precompiled) -------------------------------------------

sleep 2
done
# Default to the latest Ruby unless the caller pins a specific version.
RUBY_VERSION="${RUBY_VERSION:-latest}"

# Set up cleanup trap
trap "echo '🧹 Stopping services...'; kill $FOREMAN_PID 2>/dev/null || true; wait $FOREMAN_PID 2>/dev/null || true" EXIT
fi
}
# Skip installation when the version is already present in the image (e.g. CI
# images built with the RUBY_VERSION build arg in the Dockerfile).
if "$MISE_BIN" list ruby 2>/dev/null | grep -qF "${RUBY_VERSION}"; then
echo "✅ ruby@${RUBY_VERSION} already installed, skipping download."
else
echo "📦 Installing ruby@${RUBY_VERSION} (precompiled)..."
"$MISE_BIN" install "ruby@${RUBY_VERSION}"
Comment on lines +43 to +47
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The check for an existing Ruby installation using mise list ruby | grep -qF "latest" always fails in local dev, causing mise install to run on every container start.
Severity: MEDIUM

Suggested Fix

Resolve the "latest" alias to a concrete version number before checking if it's installed. For example, run mise resolve ruby@latest to get the version string, store it in a variable, and then use that variable for both the grep check and the mise install command.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: .devcontainer/run#L43-L47

Potential issue: In local development environments where `RUBY_VERSION` is unset, it
defaults to `"latest"`. The script checks for an existing installation using `mise list
ruby | grep -qF "latest"`. This check always fails because `mise list` outputs the
resolved concrete version number (e.g., `4.0.3`), not the alias `"latest"`.
Consequently, `mise install ruby@latest` is executed on every container start, requiring
a network connection. Because the script uses `set -euo pipefail`, any network
interruption will cause the container to fail to start, even if the correct Ruby version
is already installed.

Did we get this right? 👍 / 👎 to inform future reviews.

fi

# Parse arguments
if [ "$1" = "--service" ] && [ -n "$2" ]; then
service="$2"
shift 2
"$MISE_BIN" use --global "ruby@${RUBY_VERSION}"

run_service_setup "$service"
# ---- 3. Hand off -------------------------------------------------------------

if [ $# -gt 0 ]; then
start_services_if_needed "$@"
exec "$@"
else
exec bash
fi
if [[ $# -eq 0 ]]; then
exec sleep infinity
else
start_services_if_needed "$@"
exec "$@"
fi
25 changes: 1 addition & 24 deletions .devcontainer/setup
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class SetupScript

if should_run_bundle?
cleanup_ruby_lsp_directories
update_rubygems_and_bundler
install_bundle_dependencies
install_foreman_gem if @options[:with_foreman]
end
Expand Down Expand Up @@ -123,7 +122,7 @@ class SetupScript
Dir.chdir(folder_path) do
puts " Installing dependencies for #{folder_path}..."

unless system("[ -f Gemfile.lock ] && rm Gemfile.lock; bundle install")
unless system("bundle install")
puts "❌ Bundle install failed for #{folder}"
exit 1
end
Expand All @@ -136,28 +135,6 @@ class SetupScript
end
end

def update_rubygems_and_bundler
puts "📦 Updating RubyGems and Bundler..."

if RUBY_VERSION >= "3.0"
unless system("sudo gem update --system --silent")
puts "❌ RubyGems update failed"
exit 1
Comment thread
cursor[bot] marked this conversation as resolved.
end
else
unless system("sudo gem update --silent --system 3.4.22")
puts "❌ RubyGems update failed"
exit 1
end

# sentry-sidekiq does not bundle with Bundler 2.5.x that ships with RubyGems 3.4.22
unless system("sudo gem install bundler -v 2.4.22")
puts "❌ Bundler installation failed"
exit 1
end
end
end

def install_foreman_gem
unless system('gem install foreman')
puts "❌ Foreman gem installation failed"
Expand Down
Loading
Loading