Skip to content
Draft
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
30 changes: 20 additions & 10 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
ARG IMAGE="ruby"

FROM ${IMAGE} AS build
FROM ubuntu:latest

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 @@ -27,21 +26,32 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
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/bin:$PATH

USER sentry

RUN curl https://mise.run | sh \
&& 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=""
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
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
8 changes: 2 additions & 6 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,20 @@ services:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
args:
IMAGE: ${IMAGE}
VERSION: ${VERSION}
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"
entrypoint: [".devcontainer/run"]
command: ["foreman", "start"]
ports:
- "${SENTRY_E2E_RAILS_APP_PORT}:4000"
Expand Down
110 changes: 36 additions & 74 deletions .devcontainer/run
Original file line number Diff line number Diff line change
@@ -1,92 +1,54 @@
#!/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"
# ---- 1. mise setup -----------------------------------------------------------

echo "🚀 Running setup for service: $service"
MISE_BIN="/home/sentry/.local/bin/mise"

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

echo "✅ Setup completed for service: $service"
}
if [[ ! -x "$MISE_BIN" ]]; then
echo "❌ mise not found at $MISE_BIN (it should be installed by the Dockerfile)"
exit 1
fi

# 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..."
# Activate mise for this shell so PATH/shims are resolved correctly.
eval "$("$MISE_BIN" activate bash)"

# Start foreman in background
foreman start &
FOREMAN_PID=$!
# Trust the workspace config so mise will use it without prompting.
"$MISE_BIN" trust /workspace/sentry >/dev/null

# 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
# ---- 2. Install Ruby (precompiled) -------------------------------------------

if [ $i -eq 30 ]; then
echo "❌ Services failed to start within timeout"
kill $FOREMAN_PID 2>/dev/null || true
exit 1
fi
# Default to the latest Ruby unless the caller pins a specific version.
RUBY_VERSION="${RUBY_VERSION:-latest}"

sleep 2
done
# Always pull a precompiled binary from jdx/ruby — never build from source.
export MISE_RUBY_COMPILE=0

# 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}"
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
20 changes: 3 additions & 17 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 @@ -139,22 +138,9 @@ class SetupScript
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
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
unless system("gem update --system --silent")
puts "❌ RubyGems update failed"
exit 1
end
end

Expand Down
54 changes: 18 additions & 36 deletions .github/workflows/build_images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ on:
- .github/workflows/build_images.yml

# Uncomment if you want to test things out in a PR
#
# pull_request:
# paths:
# - .devcontainer/**
# - .github/workflows/build_images.yml

pull_request:
paths:
- .devcontainer/**
- .github/workflows/build_images.yml

permissions:
contents: read
Expand All @@ -24,45 +24,28 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ruby_image:
- ruby:2.7.8-slim-bullseye
- ruby:3.0.7-slim-bullseye
- ruby:3.1.7-slim-bookworm
- ruby:3.2.9-slim-trixie
- ruby:3.3.10-slim-trixie
- ruby:3.4.8-slim-trixie
- ruby:4.0.0-slim-trixie
ruby_version:
- "2.7.8"
- "3.0.7"
- "3.1.7"
- "3.2.9"
- "3.3.10"
- "3.4.8"
- "4.0.0"

steps:
- name: Check out current commit
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Generate short image name and extract version
- name: Generate short image name
id: image_name
run: |
ruby_image="${{ matrix.ruby_image }}"

# Extract full version for GEM_HOME (e.g., ruby:3.4.5-slim-bookworm -> 3.4.5)
if [[ "$ruby_image" == ruby:* ]]; then
full_version=$(echo "$ruby_image" | cut -d: -f2 | cut -d- -f1)
version=$(echo "$ruby_image" | cut -d: -f2 | cut -d. -f1,2)
short_name="sentry-ruby-devcontainer-${version}"
elif [[ "$ruby_image" == jruby:latest ]]; then
full_version="latest"
short_name="sentry-ruby-devcontainer-jruby-latest"
elif [[ "$ruby_image" == jruby:* ]]; then
full_version=$(echo "$ruby_image" | cut -d: -f2 | cut -d- -f1)
version=$(echo "$ruby_image" | cut -d: -f2 | cut -d. -f1,2)
short_name="sentry-ruby-devcontainer-jruby-${version}"
else
full_version="latest"
short_name="sentry-ruby-devcontainer-${ruby_image}"
fi
ruby_version="${{ matrix.ruby_version }}"
version=$(echo "$ruby_version" | cut -d. -f1,2)
short_name="sentry-ruby-devcontainer-${version}"

echo "short_name=${short_name}" >> $GITHUB_OUTPUT
echo "full_version=${full_version}" >> $GITHUB_OUTPUT
echo "Generated short image name: ${short_name}"
echo "Extracted full version: ${full_version}"

- name: Build and push devcontainer image
id: build
Expand All @@ -73,8 +56,7 @@ jobs:
ghcr: true
publish_on_pr: true
build_args: |
IMAGE=${{ matrix.ruby_image }}
VERSION=${{ steps.image_name.outputs.full_version }}
RUBY_VERSION=${{ matrix.ruby_version }}

- name: Use outputs
run: |
Expand Down
2 changes: 2 additions & 0 deletions .mise.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tools]
ruby = "latest"
Loading