Codex環境(クラウド)でbin/rails testを実行できる環境にする手順

に公開

概要

クラウド版のCodexは独自のコンテナ内で開発されるが、環境が特殊でほとんどの外部と接続できないため、bundlerで外部からライブラリ一式をもってこようとするとネットワーク周りで失敗する。そのため、rails testが実行できず、実装してもらったもののテストが通らず、対応が不完全なpull requestができてしまうことが多い。

解決策

解決策としてはbundle installをしなくて済むように、予め必要なGemをGitに含めてしまう。
ただし、その環境を用意するにはそれなりのコツがあるので下記手順に従う

手順

1. Codex環境のrubyのversionとbundlerのバージョンを調べる

Codexに下記依頼する。

ruby -v の結果と bundle -v の結果をversion.mdに保存して。

version.md(2025年10月6日現在)

ruby -v: ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux]
bundle -v: Bundler version 2.4.19

2. Testで必要な最低限のGemfileを作成する

Gem自体をGitで保存する必要があるため、全部保存してしまうとリポジトリが巨大になってしまうので、Testに必要な最低限のGemfileを作成。
テストに不要でもrequireによってテストが失敗するようであれば下記のようにアプリ側で必要な時だけloadするように修正。

def self.ensure_google_api_clients_loaded
  return if defined?(Google::Apis::SheetsV4::SheetsService)
  require 'google/apis/sheets_v4'
  require 'googleauth'
end

def sheets_service
  ensure_google_api_clients_loaded
  return @sheets_service if @sheets_service

  @sheets_service = Google::Apis::SheetsV4::SheetsService.new
  @sheets_service.authorization = authorizer
  @sheets_service
end

私の環境では下記をGemfile_ciとして保存している。

# frozen_string_literal: true
source 'https://rubygems.org'
gem 'rails', '~> 8.0.3'
# The modern asset pipeline for Rails [https://github.com/rails/propshaft]
gem 'propshaft'
gem 'sqlite3', '>= 2.1'
gem 'mission_control-jobs'
gem 'solid_cable'
gem 'solid_cache'
gem 'solid_queue'
gem 'bootsnap', require: false
gem 'letter_opener_web'
gem 'kaminari'
gem 'redcarpet'
gem 'tailwindcss-rails', '~> 4.3'

3. gemをvendor/bundle配下に保存

Codexの環境にあわせてamd64かつLinux(私はubuntu 24.04を使用)の環境を構築
Mac等のARM環境では駄目で、amd64のWindows上のwsl2やEC2やCompute Engineなどで下記を行う。
.gitignoreに下記を追加

/.bundle
vendor/bundle

その後Codexの環境にあわせてamd64かつLinux(私はubuntu 24.04を使用)の環境で下記を実行する

mv Gemfile Gemfile.orig
mv Gemfile.lock Gemfile.lock.orig
cp Gemfile_ci Gemfile
bundle install
bundle install --local --path vendor/bundle
# 動作確認
bin/rails test
# 後始末
mv Gemfile.lock Gemfile.lock_ci
mv Gemfile.orig Gemfile
mv Gemfile.lock.orig Gemfile.lock  
vi .bundle/config #BUNDLE_PATHの箇所を削除

4. vender/bundle以下を圧縮する

GitHubは大量のファイルおよび100Mb以上のファイルをうけつけないため、そのままではpushできない。
vender/bundle以下のファイルを圧縮しつつ、10Mb単位でファイルを分割するスクリプトを実行する。

#!/usr/bin/env bash
set -euo

BASE_DIR="vendor/bundle/ruby"
OUTPUT_DIR="vendor_bundle_split"
ARCHIVE_NAME="vendor_bundle.tar.gz"

mkdir -p "$OUTPUT_DIR"

echo "Compressing $BASE_DIR ..."
tar -C "$(dirname "$BASE_DIR")" -czf "$OUTPUT_DIR/$ARCHIVE_NAME" "$(basename "$BASE_DIR")"

echo "Splitting into 10MB parts..."
split -b 10M -d -a 4 "$OUTPUT_DIR/$ARCHIVE_NAME" "$OUTPUT_DIR/$ARCHIVE_NAME.part-"

echo "Done. Files are in $OUTPUT_DIR/"
sh ./compress_vendor.sh

5. vender/bundle以下を圧縮を展開するスクリプトを用意

Codexが使用する用の展開するスクリプトを用意。
またこのスクリプトでvender/bundle配下のGemを使うよう.bundle/configも書き換える。

#!/usr/bin/env bash
set -euo pipefail

OUTPUT_DIR="vendor_bundle_split"
ARCHIVE_NAME="vendor_bundle.tar.gz"
TARGET_DIR="vendor/bundle/ruby"

mkdir -p .bundle
echo -e "---\nBUNDLE_PATH: \"vendor/bundle\"\n" > .bundle/config
echo "Merging parts..."
cat "$OUTPUT_DIR/$ARCHIVE_NAME.part-"* > "$OUTPUT_DIR/$ARCHIVE_NAME"

echo "Extracting to $TARGET_DIR ..."
mkdir -p "$TARGET_DIR"
tar -C "$TARGET_DIR/.." -xzf "$OUTPUT_DIR/$ARCHIVE_NAME"

echo "Done. Restored to $TARGET_DIR/"

6. AGENTS.mdにTest環境構築の指示を追記する

クラウドのCodex環境以外のコーディングエージェントで実行されるといやなので、下記のように記載することで(他にruby 3.2.3が使われていない前提)Codexだけで実行されるようにしています。

#`ruby -v`が3.2.3だった場合の時のテスト準備 ※ ネットワークなし環境でテストを実行できるようbundle installしない
#それ以外の環境はbundle installする
---
mv Gemfile  Gemfile.orig
mv Gemfile.lock Gemfile.lock.orig
mv .ruby-version .ruby-version.orig
echo 3.2.3 > .ruby-version
cp Gemfile_ci Gemfile
cp Gemfile.lock_ci Gemfile.lock
./extract_vendor.sh
rm vendor_bundle_split/vendor_bundle.tar.gz
---

#実装後は下記の手順でテストしてください
---
bin/rails test
---

#commit前に`ruby -v`が3.2.3の場合の時の処理
#それ以外の環境は何もしない
---
mv Gemfile.orig  Gemfile
mv Gemfile.lock.orig Gemfile.lock
mv .ruby-version.orig .ruby-version
---

上記までの内容をcommitする。

git add .
git commit -m "codex環境でbin/rails testを実行できるようにする"

以降はcodexへの依頼すると、testを実行して通ったものだけをpull requestされるようになります。🎉

Codexへの依頼結果

弊社( https://joins.co.jp/ )は開発者が私だけなので、寝ている間も開発しないと追いつかないために編み出した技です。
企業向け無料生成AIによる課題解決ツール
https://corp.joins.co.jp/lisa

Discussion