diff --git a/.devcontainer/.env.example b/.devcontainer/.env.example index 873527bf3..2060b8bae 100644 --- a/.devcontainer/.env.example +++ b/.devcontainer/.env.example @@ -1,22 +1,20 @@ # Devcontainer configuration -RUBY_VERSION="3.4.9" + +RUBY_VERSION=3.4.9 # E2E testing -SENTRY_DSN="http://user:pass@sentry.localhost/project/42" -# SENTRY_DSN_JS="http://user:pass@sentry-js.localhost/project/43" -SENTRY_DSN_JS="" +SENTRY_DSN=http://user:pass@sentry.localhost/project/42 +# SENTRY_DSN_JS=http://user:pass@sentry-js.localhost/project/43 +SENTRY_DSN_JS= SENTRY_E2E_RAILS_APP_PORT=4000 SENTRY_E2E_SVELTE_APP_PORT=4001 -SENTRY_E2E_RAILS_APP_URL="http://localhost:4000" -SENTRY_E2E_SVELTE_APP_URL="http://localhost:4001" +SENTRY_E2E_RAILS_APP_URL=http://localhost:4000 +SENTRY_E2E_SVELTE_APP_URL=http://localhost:4001 # ActiveJob queue adapter under test: async | inline | sidekiq | resque | delayed_job -SENTRY_E2E_ACTIVE_JOB_ADAPTER="async" - -# Redis for the sidekiq/resque adapters (the Compose service is named "redis") -REDIS_URL="redis://redis:6379" +SENTRY_E2E_ACTIVE_JOB_ADAPTER=async -# Faster builds with compose -COMPOSE_BAKE=true +# Redis for the sidekiq/resque adapters +REDIS_URL=redis://localhost:6379 diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 0ba375621..590f51c29 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -35,14 +35,14 @@ RUN userdel -r ubuntu 2>/dev/null || true \ && groupadd --gid 1000 sentry \ && useradd --uid 1000 --gid sentry --shell /bin/bash --create-home sentry -WORKDIR /workspace/sentry +WORKDIR /workspaces/sentry-ruby -RUN chown -R sentry:sentry /workspace/sentry +RUN chown -R sentry:sentry /workspaces/sentry-ruby ENV LANG=C.UTF-8 \ BUNDLE_JOBS=4 \ BUNDLE_RETRY=3 \ - REDIS_HOST=redis \ + REDIS_HOST=localhost \ PATH=/home/sentry/.local/share/mise/shims:/home/sentry/.local/bin:$PATH USER sentry @@ -52,32 +52,6 @@ USER sentry # 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 - -# Pre-install Ruby at build time so the container starts immediately without -# downloading it at runtime. Switching Ruby versions requires a rebuild. -ARG RUBY_VERSION=latest - -# 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 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}" - -# 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 -# Playwright lays out the binary under chrome-linux/ on arm64 and chrome-linux64/ -# on x86_64 (since Playwright 1.57), so the glob has to match both. -RUN bash -c 'ln -sf /home/sentry/.cache/ms-playwright/chromium-*/chrome-linux*/chrome /home/sentry/.local/bin/chromium' +# Chromium, ChromeDriver, mise, and the toolchain (Java, Ruby, Node) are +# installed by the local `./features/tools` dev container feature, which runs +# after this Dockerfile — see devcontainer.json. diff --git a/.devcontainer/VERSION b/.devcontainer/VERSION index 9084fa2f7..276cbf9e2 100644 --- a/.devcontainer/VERSION +++ b/.devcontainer/VERSION @@ -1 +1 @@ -1.1.0 +2.3.0 diff --git a/.devcontainer/ci-run b/.devcontainer/ci-run new file mode 100755 index 000000000..e9fd92b46 --- /dev/null +++ b/.devcontainer/ci-run @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -euo pipefail + +readonly WORKSPACE=/workspaces/sentry-ruby + +sudo chown -R sentry:sentry "$WORKSPACE" + +cd "$WORKSPACE" +mise trust "$WORKSPACE" >/dev/null + +exec "$@" diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json index 81236b5bc..06b03ee0e 100644 --- a/.devcontainer/devcontainer-lock.json +++ b/.devcontainer/devcontainer-lock.json @@ -1,25 +1,15 @@ { "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/git:latest": { - "version": "1.3.5", - "resolved": "ghcr.io/devcontainers/features/git@sha256:27905dc196c01f77d6ba8709cb82eeaf330b3b108772e2f02d1cd0d826de1251", - "integrity": "sha256:27905dc196c01f77d6ba8709cb82eeaf330b3b108772e2f02d1cd0d826de1251" + "version": "1.3.8", + "resolved": "ghcr.io/devcontainers/features/git@sha256:fd75977de13a9979000e0e78baf949adb0ca71d2398995fa22e0a36d7e7e7fe2", + "integrity": "sha256:fd75977de13a9979000e0e78baf949adb0ca71d2398995fa22e0a36d7e7e7fe2" }, "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", diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 287243c71..3d65485fd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,8 +1,30 @@ { "name": "sentry-ruby", - "dockerComposeFile": "docker-compose.yml", - "service": "sentry-dev", - "workspaceFolder": "/workspace/sentry", + "build": { + "dockerfile": "Dockerfile", + "context": "..", + "args": { + "BASE_IMAGE": "${localEnv:BASE_IMAGE:ubuntu:24.04}" + } + }, + "runArgs": ["--init"], + "mounts": [ + "source=sentry-ruby-bundle,target=/home/sentry/bundle,type=volume" + ], + "forwardPorts": [4000, 4001, 6379], + "containerEnv": { + "BUNDLE_PATH": "/home/sentry/bundle", + "SENTRY_DSN": "http://user:pass@sentry.localhost/project/42", + "SENTRY_DSN_JS": "", + "SENTRY_E2E_RAILS_APP_PORT": "4000", + "SENTRY_E2E_SVELTE_APP_PORT": "4001", + "SENTRY_E2E_RAILS_APP_URL": "http://localhost:4000", + "SENTRY_E2E_SVELTE_APP_URL": "http://localhost:4001", + "SENTRY_E2E_ACTIVE_JOB_ADAPTER": "async", + "REDIS_URL": "redis://localhost:6379" + }, + "postCreateCommand": "mise trust /workspaces/sentry-ruby", + "postStartCommand": "mise run services:redis", "features": { "ghcr.io/devcontainers/features/git:latest": { "ppa": false, @@ -10,10 +32,11 @@ }, "ghcr.io/devcontainers/features/github-cli:latest": {}, "ghcr.io/nils-geistmann/devcontainers-features/zsh:latest": {}, - "ghcr.io/devcontainers/features/node:latest": {}, - "ghcr.io/devcontainers-extra/features/npm-packages:latest": {}, + "./features/tools": { + "rubyVersion": "${localEnv:RUBY_VERSION:4.0}" + }, "ghcr.io/rocker-org/devcontainer-features/apt-packages:latest": { - "packages": "inotify-tools,tzdata" + "packages": "inotify-tools,tzdata,redis-server" } }, "customizations": { diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml deleted file mode 100644 index e9831a9f9..000000000 --- a/.devcontainer/docker-compose.yml +++ /dev/null @@ -1,51 +0,0 @@ -services: - sentry-build: &sentry-build - image: ${DOCKER_IMAGE:-sentry-ruby-devcontainer}:${DOCKER_TAG:-latest} - build: - context: .. - dockerfile: .devcontainer/Dockerfile - args: - BASE_IMAGE: ${BASE_IMAGE:-ubuntu:24.04} - RUBY_VERSION: ${RUBY_VERSION:-latest} - volumes: - - ..:/workspace/sentry:cached - working_dir: /workspace/sentry - env_file: [".env"] - - sentry-dev: - <<: *sentry-build - entrypoint: [".devcontainer/run"] - depends_on: - - redis - - sentry-test: - <<: *sentry-build - profiles: ["e2e"] - entrypoint: [".devcontainer/run"] - command: ["mise", "run", "e2e:serve"] - environment: - BUNDLE_PATH: /home/sentry/bundle - depends_on: - redis: - condition: service_healthy - volumes: - - ..:/workspace/sentry:cached - - bundle-gems:/home/sentry/bundle - ports: - - "${SENTRY_E2E_RAILS_APP_PORT}:4000" - - "${SENTRY_E2E_SVELTE_APP_PORT}:4001" - - redis: - image: redis:latest - environment: - - ALLOW_EMPTY_PASSWORD=yes - ports: - - "6379:6379" - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 2s - timeout: 3s - retries: 10 - -volumes: - bundle-gems: diff --git a/.devcontainer/features/tools/devcontainer-feature.json b/.devcontainer/features/tools/devcontainer-feature.json new file mode 100644 index 000000000..fbf63f2a2 --- /dev/null +++ b/.devcontainer/features/tools/devcontainer-feature.json @@ -0,0 +1,19 @@ +{ + "name": "sentry-ruby toolchain", + "id": "tools", + "version": "1.0.0", + "description": "Installs development dependencies required by the Ruby SDK to run all tests", + "installsAfter": [ + "ghcr.io/devcontainers/features/git", + "ghcr.io/devcontainers/features/github-cli", + "ghcr.io/nils-geistmann/devcontainers-features/zsh", + "ghcr.io/rocker-org/devcontainer-features/apt-packages" + ], + "options": { + "rubyVersion": { + "type": "string", + "default": "latest", + "description": "Ruby version to pre-install. Switching versions requires an image rebuild." + } + } +} diff --git a/.devcontainer/features/tools/install.sh b/.devcontainer/features/tools/install.sh new file mode 100755 index 000000000..798d71c63 --- /dev/null +++ b/.devcontainer/features/tools/install.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# +# Installs mise, the sentry-ruby toolchain, and Chromium with ChromeDriver. +# +set -euo pipefail + +RUBY_VERSION="${RUBYVERSION:-latest}" +USERNAME="${_REMOTE_USER:-sentry}" +USER_HOME="${_REMOTE_USER_HOME:-/home/${USERNAME}}" + +echo "📦 Installing Chromium and ChromeDriver..." +echo "deb http://deb.debian.org/debian sid main" > /etc/apt/sources.list.d/debian.list +wget -qO- https://ftp-master.debian.org/keys/archive-key-12.asc \ + | gpg --dearmor > /etc/apt/trusted.gpg.d/debian-archive-keyring.gpg +wget -qO- https://ftp-master.debian.org/keys/archive-key-12-security.asc \ + | gpg --dearmor > /etc/apt/trusted.gpg.d/debian-archive-security-keyring.gpg +for directory in bin lib lib32 lib64 libo32 libx32 sbin; do + dpkg-divert --package base-files --no-rename --remove "/${directory}" +done +apt-get update +apt-get install -y --no-install-recommends chromium chromium-driver +rm -rf /var/lib/apt/lists/* /var/cache/apt/* /etc/apt/sources.list.d/debian.list + +# Install mise system-wide via the official installer. This downloads a prebuilt +# binary from mise's CDN rather than the GitHub API, avoiding the API rate +# limits the gh-release-based community feature hits on shared CI runners. +echo "📦 Installing mise..." +export MISE_INSTALL_PATH=/usr/local/bin/mise +curl https://mise.run | sh +MISE_BIN=/usr/local/bin/mise +"$MISE_BIN" --version + +# Activate mise for the remote user's interactive shells. +echo "eval \"\$(${MISE_BIN} activate bash)\"" >> "${USER_HOME}/.bashrc" +echo "eval \"\$(${MISE_BIN} activate zsh)\"" >> "${USER_HOME}/.zshenv" +chown "${USERNAME}:${USERNAME}" "${USER_HOME}/.bashrc" "${USER_HOME}/.zshenv" + +# Feature installers run as root, but the toolchain belongs to the remote user. +as_user() { + sudo -u "${USERNAME}" -H env "PATH=${USER_HOME}/.local/bin:/usr/local/bin:/usr/bin:/bin" "$@" +} + +echo "📦 Pre-installing toolchain..." +as_user env MISE_RUBY_COMPILE=0 "$MISE_BIN" install \ + "java@temurin-21" \ + "ruby@${RUBY_VERSION}" \ + "node@lts" + +echo "✅ Toolchain pre-install completed!" diff --git a/.devcontainer/run b/.devcontainer/run deleted file mode 100755 index caf752a83..000000000 --- a/.devcontainer/run +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# -# Container entrypoint. Ruby and other toolchains are pre-installed in the -# image; this script only handles per-run setup (ownership, mise activation) -# and hands off to whatever docker-compose passes as `command`. -# -set -euo pipefail - -cd /workspace/sentry - -# 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" - -# Git also refuses to operate in directories owned by a different user. -git config --global --add safe.directory /workspace/sentry 2>/dev/null || true - -if [[ ! -x "$MISE_BIN" ]]; then - echo "❌ mise not found at $MISE_BIN (it should be installed by the Dockerfile)" - exit 1 -fi - -# Activate mise for this shell so PATH/shims are resolved correctly. -eval "$("$MISE_BIN" activate bash)" - -# Trust the workspace config so mise will use it without prompting. -"$MISE_BIN" trust /workspace/sentry >/dev/null - -if [[ $# -eq 0 ]]; then - exec sleep infinity -else - exec "$@" -fi diff --git a/.devcontainer/setup b/.devcontainer/setup index 408f7d8de..c608e0da6 100755 --- a/.devcontainer/setup +++ b/.devcontainer/setup @@ -25,7 +25,7 @@ class SetupScript only_npm: false, with_foreman: false } - @workspace_root = '/workspace/sentry' + @workspace_root = '/workspaces/sentry-ruby' end def run(args) diff --git a/.github/workflows/build_images.yml b/.github/workflows/build_images.yml index ffc4bd624..dee8fb2f2 100644 --- a/.github/workflows/build_images.yml +++ b/.github/workflows/build_images.yml @@ -55,15 +55,19 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + # Build with the dev container CLI (not a plain `docker build`) so the dev + # container features — including the local `tools` feature that bakes the + # Ruby/Node/Java toolchain and browser — are applied to the pushed image. + # BASE_IMAGE and RUBY_VERSION are consumed via ${localEnv:...} in + # devcontainer.json, so they are passed as env vars to the CLI here. - name: Build and push devcontainer image - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 + uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3.1900000450 + env: + BASE_IMAGE: ${{ matrix.base_image }} + RUBY_VERSION: ${{ matrix.ruby_version }} with: - context: . - file: .devcontainer/Dockerfile - push: true - tags: | - ghcr.io/getsentry/sentry-ruby-devcontainer-${{ matrix.flavor }}:${{ steps.version.outputs.version }} - ${{ github.ref == 'refs/heads/master' && format('ghcr.io/getsentry/sentry-ruby-devcontainer-{0}:latest', matrix.flavor) || '' }} - build-args: | - BASE_IMAGE=${{ matrix.base_image }} - RUBY_VERSION=${{ matrix.ruby_version }} + subFolder: . + configFile: .devcontainer/devcontainer.json + imageName: ghcr.io/getsentry/sentry-ruby-devcontainer-${{ matrix.flavor }} + imageTag: ${{ github.ref == 'refs/heads/master' && format('{0},latest', steps.version.outputs.version) || steps.version.outputs.version }} + push: always diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 018db5c5c..548389581 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -48,9 +48,6 @@ jobs: run: | cd .devcontainer cp .env.example .env - echo "RUBY_VERSION=${{ matrix.ruby.version }}" >> .env - echo "DOCKER_IMAGE=ghcr.io/getsentry/sentry-ruby-devcontainer-${{ matrix.ruby.flavor }}" >> .env - echo "DOCKER_TAG=${{ steps.devcontainer-version.outputs.version }}" >> .env echo "SENTRY_E2E_ACTIVE_JOB_ADAPTER=${{ matrix.adapter }}" >> .env - name: Log in to GHCR @@ -63,6 +60,16 @@ jobs: - name: Pull test container image run: docker pull ghcr.io/getsentry/sentry-ruby-devcontainer-${{ matrix.ruby.flavor }}:${{ steps.devcontainer-version.outputs.version }} + - name: Prepare docker resources + run: | + bundle_volume="sentry-ruby-e2e-bundle-${{ github.run_id }}-${{ matrix.ruby.flavor }}-${{ matrix.adapter }}" + test_container="sentry-ruby-e2e-test-${{ github.run_id }}-${{ matrix.ruby.flavor }}-${{ matrix.adapter }}" + + echo "E2E_BUNDLE_VOLUME=${bundle_volume}" >> "$GITHUB_ENV" + echo "E2E_TEST_CONTAINER=${test_container}" >> "$GITHUB_ENV" + + docker volume create "${bundle_volume}" + - name: Restore node_modules cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: @@ -73,49 +80,75 @@ jobs: - name: Set up test container run: | - docker compose \ - --file .devcontainer/docker-compose.yml \ + docker run --rm \ --env-file .devcontainer/.env \ - --profile e2e \ - run --rm sentry-test \ - .devcontainer/setup --only .,spec/apps/rails-mini + --env BUNDLE_PATH=/home/sentry/bundle \ + --env MISE_RUBY_VERSION=${{ matrix.ruby.version }} \ + --volume "${PWD}:/workspaces/sentry-ruby" \ + --volume "${E2E_BUNDLE_VOLUME}:/home/sentry/bundle" \ + "ghcr.io/getsentry/sentry-ruby-devcontainer-${{ matrix.ruby.flavor }}:${{ steps.devcontainer-version.outputs.version }}" \ + .devcontainer/ci-run .devcontainer/setup --only .,spec/apps/rails-mini - name: Start test services run: | - docker compose \ - --file .devcontainer/docker-compose.yml \ + docker run -d \ + --name "${E2E_TEST_CONTAINER}" \ + --publish 4000:4000 \ + --publish 4001:4001 \ --env-file .devcontainer/.env \ - --profile e2e \ - up -d --no-build sentry-test - + --env BUNDLE_PATH=/home/sentry/bundle \ + --env MISE_RUBY_VERSION=${{ matrix.ruby.version }} \ + --volume "${PWD}:/workspaces/sentry-ruby" \ + --volume "${E2E_BUNDLE_VOLUME}:/home/sentry/bundle" \ + "ghcr.io/getsentry/sentry-ruby-devcontainer-${{ matrix.ruby.flavor }}:${{ steps.devcontainer-version.outputs.version }}" \ + .devcontainer/ci-run mise run e2e:serve + + # Poll from the runner host, not a container action: the apps' ports are + # published to the host (`--publish`), so `localhost` here reaches them, + # whereas a Docker container action's `localhost` is its own container. - name: "Wait for rails-mini app to be ready" - uses: nev7n/wait_for_response@8bfc0523300e46e24e1b42d6783680aa921ee6cc # v1.2.0 - with: - url: 'http://localhost:4000/health' - responseCode: 200 - timeout: 90000 - interval: 500 + run: | + for _ in $(seq 1 180); do + if curl -sf http://localhost:4000/health >/dev/null; then + echo "rails-mini is ready" + exit 0 + fi + sleep 1 + done + echo "❌ rails-mini did not become ready in time" >&2 + docker logs "${E2E_TEST_CONTAINER}" 2>&1 | tail -n 200 || true + exit 1 - name: "Wait for svelte-mini app to be ready" - uses: nev7n/wait_for_response@8bfc0523300e46e24e1b42d6783680aa921ee6cc # v1.2.0 - with: - url: 'http://localhost:4001/health' - responseCode: 200 - timeout: 90000 - interval: 500 + run: | + for _ in $(seq 1 180); do + if curl -sf http://localhost:4001/health >/dev/null; then + echo "svelte-mini is ready" + exit 0 + fi + sleep 1 + done + echo "❌ svelte-mini did not become ready in time" >&2 + docker logs "${E2E_TEST_CONTAINER}" 2>&1 | tail -n 200 || true + exit 1 - name: Run e2e tests via sentry-test run: | - docker compose \ - --file .devcontainer/docker-compose.yml \ - --env-file .devcontainer/.env \ - --profile e2e \ - exec sentry-test \ - bundle exec rake + docker exec "${E2E_TEST_CONTAINER}" bundle exec rake + + - name: Dump service logs + if: failure() + run: | + echo "===== docker ps -a =====" + docker ps -a + echo "===== test container logs =====" + docker logs "${E2E_TEST_CONTAINER}" 2>&1 || true - name: Stop e2e services if: always() - run: docker compose --file .devcontainer/docker-compose.yml --profile e2e down + run: | + docker rm -f "${E2E_TEST_CONTAINER}" 2>/dev/null || true + docker volume rm "${E2E_BUNDLE_VOLUME}" 2>/dev/null || true - name: Upload test artifacts if: failure() diff --git a/.gitignore b/.gitignore index 6457c76c3..302e83806 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ node_modules mise.toml .devcontainer/.env + vendor/gems sentry-rails/Gemfile-*.lock diff --git a/.mise.toml b/.mise.toml index 6744ccf6f..da978f252 100644 --- a/.mise.toml +++ b/.mise.toml @@ -24,8 +24,22 @@ run = [ "bundle exec rubocop -a" ] +[tasks."services:redis"] +description = "Start a local Redis server for specs and e2e apps; waits until ready, no-op if already running" +run = """ +redis-cli ping >/dev/null 2>&1 && exit 0 +redis-server --daemonize yes --save '' --dir /tmp --pidfile /tmp/redis.pid +for _ in $(seq 1 30); do + redis-cli ping >/dev/null 2>&1 && exit 0 + sleep 0.2 +done +echo 'redis did not become ready' >&2 +exit 1 +""" + [tasks."e2e:rails"] description = "Start the rails-mini e2e app" +depends = ["services:redis"] run = "cd spec/apps/rails-mini && bundle exec ruby app.rb" [tasks."e2e:svelte"] @@ -34,6 +48,7 @@ run = "cd spec/apps/svelte-mini && npm run dev" [tasks."e2e:worker"] description = "Start the rails-mini ActiveJob worker (sidekiq/resque/delayed_job; idles for async/inline)" +depends = ["services:redis"] run = "cd spec/apps/rails-mini && bundle exec ruby worker.rb" [tasks."e2e:serve"] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92e2fcbd2..e4474e2ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,7 @@ The devcontainer is configured with `.devcontainer/.env` file, that you need to cp .devcontainer/.env.example .devcontainer/.env ``` -This file defines which specific image and Ruby version will be used to run the code. Edit it whenever you need to use a different image or Ruby version. +This file defines runtime settings for local e2e apps and devcontainer workflows. ## Contribute To Individual Gems diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0124a6e67..64e314ec4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -31,13 +31,12 @@ options.add_argument("--disable-gpu") options.add_argument("--temp-profile") - # Use custom chromium binary if available - chromium_path = "/home/sentry/.local/bin/chromium" + chromium_path = ENV.fetch("SENTRY_E2E_CHROME", "/usr/bin/chromium") options.binary = chromium_path if File.exist?(chromium_path) # Use a local chromedriver if provided, bypassing Selenium Manager's # download (which only ships an x86 driver and fails on arm64). - chromedriver_path = ENV["SENTRY_E2E_CHROMEDRIVER"] || "/home/sentry/.local/bin/chromedriver" + chromedriver_path = ENV.fetch("SENTRY_E2E_CHROMEDRIVER", "/usr/bin/chromedriver") service = File.exist?(chromedriver_path) ? Selenium::WebDriver::Service.chrome(path: chromedriver_path) : nil Capybara::Selenium::Driver.new(app, browser: :chrome, options: options, service: service)