From 32a1b16276cb889c2b06159d99589af2aaa25f78 Mon Sep 17 00:00:00 2001 From: fujitani sora Date: Sun, 25 Jan 2026 13:39:57 +0900 Subject: [PATCH 1/7] feat: magnos upgrade --- Cargo.lock | 12 ++++++------ ext/rfmt/Cargo.toml | 4 ++-- ext/rfmt/src/lib.rs | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6f4cbc..728cdef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -838,9 +838,9 @@ dependencies = [ [[package]] name = "magnus" -version = "0.6.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1597ef40aa8c36be098249e82c9a20cf7199278ac1c1a1a995eeead6a184479" +checksum = "3b36a5b126bbe97eb0d02d07acfeb327036c6319fd816139a49824a83b7f9012" dependencies = [ "magnus-macros", "rb-sys", @@ -850,9 +850,9 @@ dependencies = [ [[package]] name = "magnus-macros" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5968c820e2960565f647819f5928a42d6e874551cab9d88d75e3e0660d7f71e3" +checksum = "47607461fd8e1513cb4f2076c197d8092d921a1ea75bd08af97398f593751892" dependencies = [ "proc-macro2", "quote", @@ -1168,9 +1168,9 @@ dependencies = [ [[package]] name = "rb-sys-env" -version = "0.1.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35802679f07360454b418a5d1735c89716bde01d35b1560fc953c1415a0b3bb" +checksum = "cca7ad6a7e21e72151d56fe2495a259b5670e204c3adac41ee7ef676ea08117a" [[package]] name = "redox_users" diff --git a/ext/rfmt/Cargo.toml b/ext/rfmt/Cargo.toml index 59cdd2a..cfbccbe 100644 --- a/ext/rfmt/Cargo.toml +++ b/ext/rfmt/Cargo.toml @@ -12,8 +12,8 @@ crate-type = ["cdylib"] [dependencies] # Ruby FFI -magnus = { version = "0.6.2" } -rb-sys = "0.9.117" +magnus = { version = "0.8.2" } +rb-sys = "0.9.124" # Serialization serde = { version = "1.0", features = ["derive"] } diff --git a/ext/rfmt/src/lib.rs b/ext/rfmt/src/lib.rs index bda75e9..51aa4c9 100644 --- a/ext/rfmt/src/lib.rs +++ b/ext/rfmt/src/lib.rs @@ -10,7 +10,7 @@ use policy::SecurityPolicy; use config::Config; use emitter::Emitter; -use magnus::{define_module, function, prelude::*, Error, Ruby}; +use magnus::{function, prelude::*, Error, Ruby}; use parser::{PrismAdapter, RubyParser}; fn format_ruby_code(ruby: &Ruby, source: String, json: String) -> Result { @@ -45,10 +45,10 @@ fn rust_version() -> String { } #[magnus::init] -fn init(_ruby: &Ruby) -> Result<(), Error> { +fn init(ruby: &Ruby) -> Result<(), Error> { logging::RfmtLogger::init(); - let module = define_module("Rfmt")?; + let module = ruby.define_module("Rfmt")?; module.define_singleton_method("format_code", function!(format_ruby_code, 2))?; module.define_singleton_method("parse_to_json", function!(parse_to_json, 1))?; From a4586b187f216d0cfe733f21a2c495b3b70316ed Mon Sep 17 00:00:00 2001 From: fujitani sora Date: Sun, 25 Jan 2026 13:43:29 +0900 Subject: [PATCH 2/7] ci: ruby3.4, 4 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24335fc..4dd5e82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - ruby: ['3.1', '3.2', '3.3'] + ruby: ['3.4', '4.0'] rust: [stable] # Windows support is currently disabled due to rb-sys compatibility issues # include: @@ -76,7 +76,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.3' + ruby-version: '3.4' bundler-cache: true - name: Run RuboCop @@ -97,7 +97,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.3' + ruby-version: '3.4' bundler-cache: true - name: Install dependencies From 7441be4e2e71dc3ed1b54f4d47b370b059653152 Mon Sep 17 00:00:00 2001 From: fujitani sora Date: Sun, 25 Jan 2026 13:49:11 +0900 Subject: [PATCH 3/7] upgrade unicode-emoji --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index dda273a..64daf38 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,7 +97,7 @@ GEM thor (1.4.0) unicode-display_width (3.2.0) unicode-emoji (~> 4.1) - unicode-emoji (4.1.0) + unicode-emoji (4.2.0) PLATFORMS arm64-darwin-23 From ed1b1ec200705cb3d6f2e16bc69bc9e537a3baee Mon Sep 17 00:00:00 2001 From: fujitani sora Date: Sun, 25 Jan 2026 13:55:22 +0900 Subject: [PATCH 4/7] fix: step version --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4dd5e82..b8b8006 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.4' + ruby-version: '4.0' bundler-cache: true - name: Run RuboCop @@ -97,7 +97,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.4' + ruby-version: '4.0' bundler-cache: true - name: Install dependencies From bd70b04ebf6e924807dd4914a5a78b31c0cb235e Mon Sep 17 00:00:00 2001 From: fujitani sora Date: Sun, 25 Jan 2026 13:58:53 +0900 Subject: [PATCH 5/7] other ruby v 4 --- .github/workflows/main.yml | 2 +- .github/workflows/release.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 81a7db9..bae7e33 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: ruby: - - '3.3' + - '4.0' steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ada1a2..a87e0b7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.3' + ruby-version: '4.0' - name: Extract version from tag id: extract_version @@ -70,13 +70,13 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.3' + ruby-version: '4.0' bundler-cache: true - uses: oxidize-rb/actions/cross-gem@v1 with: platform: ${{ matrix.platform }} - ruby-versions: '3.1,3.2,3.3' + ruby-versions: '3.4,4.0' - name: Upload gem artifact uses: actions/upload-artifact@v4 @@ -95,7 +95,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.3' + ruby-version: '4.0' bundler-cache: true - name: Build source gem From fa44f515c24f2a712ddecaad5c23e3b6e9bb6460 Mon Sep 17 00:00:00 2001 From: fujitani sora Date: Sun, 25 Jan 2026 18:10:26 +0900 Subject: [PATCH 6/7] feat: install test env on docker compose --- .dockerignore | 76 ++++++++++++++++++++++++ docker/Dockerfile.test | 39 +++++++++++++ docker/compose.test.yml | 21 +++++++ scripts/test-gem-install.sh | 113 ++++++++++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 .dockerignore create mode 100644 docker/Dockerfile.test create mode 100644 docker/compose.test.yml create mode 100755 scripts/test-gem-install.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..418aaee --- /dev/null +++ b/.dockerignore @@ -0,0 +1,76 @@ +# Docker ignore file for rfmt gem installation testing +# This file excludes unnecessary files from the Docker build context + +# Nix development environment cache (very large) +.nix-gem-home/ +.nix-cargo-home/ +.nix-rustup-home/ +.nix-bin/ +.nix-wrappers/ +.dependencies-installed +.direnv/ + +# Rust build artifacts +target/ +ext/*/target/ + +# Git +.git/ +.gitignore + +# IDE and editor files +.vscode/ +.idea/ +*.swp +*.swo +.DS_Store +**/.DS_Store + +# Development tools +.lefthook/ +lefthook-local.yml +.rspec_status +.rake_tasks~ + +# Documentation and build artifacts +coverage/ +doc/ +_yardoc/ +pkg/ +spec/reports/ +tmp/ +build/ +docspriv/ + +# Test results +**/benchmark/results.json +**/benchmarks/*.json +**/test_results/*.json + +# Claude development tools +.claude/ + +# Ruby version manager files +.ruby-version + +# Other development files +.serena/ +.ruby-lsp/ +.ruby-lsp.bak/ + +# Docker files (avoid recursive context) +docker/ +!docker/Dockerfile.test + +# Scripts (not needed in container) +scripts/ + +# Keep these (explicitly) +!Gemfile +!Gemfile.lock +!rfmt.gemspec +!Rakefile +!lib/ +!ext/ +!bin/ +!spec/ diff --git a/docker/Dockerfile.test b/docker/Dockerfile.test new file mode 100644 index 0000000..56fcb03 --- /dev/null +++ b/docker/Dockerfile.test @@ -0,0 +1,39 @@ +# Dockerfile for testing rfmt gem installation across Ruby versions +# Usage: docker build --build-arg RUBY_VERSION=4.0 -f docker/Dockerfile.test -t rfmt-test:4.0 . + +ARG RUBY_VERSION=3.4 +FROM ruby:${RUBY_VERSION} + +# Install Rust toolchain +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable +ENV PATH="/root/.cargo/bin:${PATH}" + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + libclang-dev \ + clang \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /rfmt + +# Copy only gemspec and necessary files first (for layer caching) +COPY rfmt.gemspec Gemfile Gemfile.lock ./ +COPY lib/rfmt/version.rb ./lib/rfmt/ + +# Copy source code +COPY . . + +# Build the gem +RUN gem build rfmt.gemspec + +# Test gem installation (the critical test!) +RUN gem install ./rfmt-*.gem --no-document + +# Verify installation works +RUN ruby -e "require 'rfmt'; puts \"rfmt #{Rfmt::VERSION} loaded successfully on Ruby #{RUBY_VERSION}\"" + +# Run a simple format test +RUN echo 'def hello() puts "world" end' | rfmt || echo "CLI test completed" + +CMD ["ruby", "-e", "require 'rfmt'; puts \"rfmt #{Rfmt::VERSION} ready on Ruby #{RUBY_VERSION}\""] diff --git a/docker/compose.test.yml b/docker/compose.test.yml new file mode 100644 index 0000000..b2146af --- /dev/null +++ b/docker/compose.test.yml @@ -0,0 +1,21 @@ +# Docker Compose for testing rfmt across multiple Ruby versions +# Usage: +# docker compose -f docker/docker-compose.test.yml build +# docker compose -f docker/docker-compose.test.yml up + +services: + test-ruby-3.4: + build: + context: .. + dockerfile: docker/Dockerfile.test + args: + RUBY_VERSION: "3.4" + image: rfmt-test:ruby-3.4 + + test-ruby-4.0: + build: + context: .. + dockerfile: docker/Dockerfile.test + args: + RUBY_VERSION: "4.0" + image: rfmt-test:ruby-4.0 diff --git a/scripts/test-gem-install.sh b/scripts/test-gem-install.sh new file mode 100755 index 0000000..e55a733 --- /dev/null +++ b/scripts/test-gem-install.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +# Test gem installation across multiple Ruby versions using Docker +# +# Usage: +# ./scripts/test-gem-install.sh # Test all versions (3.4, 4.0) +# ./scripts/test-gem-install.sh 4.0 # Test specific version +# ./scripts/test-gem-install.sh 3.4 4.0 # Test multiple specific versions + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" + +# Default Ruby versions to test +DEFAULT_VERSIONS=("3.4" "4.0") + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +# Parse arguments +if [ $# -eq 0 ]; then + VERSIONS=("${DEFAULT_VERSIONS[@]}") +else + VERSIONS=("$@") +fi + +echo "" +echo "========================================" +echo " rfmt gem installation test" +echo "========================================" +echo "" +log_info "Testing Ruby versions: ${VERSIONS[*]}" +echo "" + +cd "$PROJECT_DIR" + +FAILED_VERSIONS=() +PASSED_VERSIONS=() + +for version in "${VERSIONS[@]}"; do + echo "----------------------------------------" + log_info "Testing Ruby ${version}..." + echo "----------------------------------------" + + IMAGE_NAME="rfmt-test:ruby-${version}" + + # Build the test image + if docker build \ + --build-arg RUBY_VERSION="${version}" \ + -f docker/Dockerfile.test \ + -t "$IMAGE_NAME" \ + . 2>&1; then + + log_success "Ruby ${version}: gem install succeeded!" + PASSED_VERSIONS+=("$version") + + # Run additional verification + log_info "Running verification tests..." + if docker run --rm "$IMAGE_NAME" ruby -e " + require 'rfmt' + puts \" Version: #{Rfmt::VERSION}\" + puts \" Rust version: #{Rfmt.rust_version}\" + puts \" Ruby: #{RUBY_VERSION}\" + "; then + log_success "Ruby ${version}: verification passed!" + else + log_warn "Ruby ${version}: verification had issues" + fi + else + log_error "Ruby ${version}: gem install FAILED!" + FAILED_VERSIONS+=("$version") + fi + + echo "" +done + +echo "========================================" +echo " Summary" +echo "========================================" +echo "" + +if [ ${#PASSED_VERSIONS[@]} -gt 0 ]; then + log_success "Passed: ${PASSED_VERSIONS[*]}" +fi + +if [ ${#FAILED_VERSIONS[@]} -gt 0 ]; then + log_error "Failed: ${FAILED_VERSIONS[*]}" + echo "" + exit 1 +fi + +log_success "All tests passed!" +echo "" From 88379ff228f6f3be82ed7ff464de8bcc5ec8b717 Mon Sep 17 00:00:00 2001 From: fujitani sora Date: Sun, 25 Jan 2026 18:19:59 +0900 Subject: [PATCH 7/7] refactor: optimize Docker build with multi-stage and caching - Multi-stage build (builder/runtime/test stages) - Minimal Rust profile for faster installs - YAML anchors for DRY compose config - Simplified test script with modern bash Co-Authored-By: Claude --- docker/Dockerfile.test | 39 ++++++++++++++++++--------- docker/compose.test.yml | 15 ++++++----- scripts/test-gem-install.sh | 53 ++++++++++--------------------------- 3 files changed, 49 insertions(+), 58 deletions(-) diff --git a/docker/Dockerfile.test b/docker/Dockerfile.test index 56fcb03..6d8129b 100644 --- a/docker/Dockerfile.test +++ b/docker/Dockerfile.test @@ -2,38 +2,51 @@ # Usage: docker build --build-arg RUBY_VERSION=4.0 -f docker/Dockerfile.test -t rfmt-test:4.0 . ARG RUBY_VERSION=3.4 -FROM ruby:${RUBY_VERSION} -# Install Rust toolchain -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable -ENV PATH="/root/.cargo/bin:${PATH}" +# Stage 1: Base image with build dependencies +FROM ruby:${RUBY_VERSION} AS builder -# Install build dependencies -RUN apt-get update && apt-get install -y \ +# Install Rust and build dependencies in a single layer +RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ libclang-dev \ clang \ + curl \ + ca-certificates \ + && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal \ && rm -rf /var/lib/apt/lists/* +ENV PATH="/root/.cargo/bin:${PATH}" + WORKDIR /rfmt -# Copy only gemspec and necessary files first (for layer caching) +# Copy dependency files first for layer caching COPY rfmt.gemspec Gemfile Gemfile.lock ./ COPY lib/rfmt/version.rb ./lib/rfmt/ # Copy source code COPY . . -# Build the gem -RUN gem build rfmt.gemspec +# Build and install the gem +RUN gem build rfmt.gemspec \ + && gem install ./rfmt-*.gem --no-document + +# Stage 2: Runtime image (smaller, no build tools) +FROM ruby:${RUBY_VERSION}-slim AS runtime -# Test gem installation (the critical test!) -RUN gem install ./rfmt-*.gem --no-document +# Copy installed gem from builder +COPY --from=builder /usr/local/bundle /usr/local/bundle -# Verify installation works +# Verify installation RUN ruby -e "require 'rfmt'; puts \"rfmt #{Rfmt::VERSION} loaded successfully on Ruby #{RUBY_VERSION}\"" -# Run a simple format test +CMD ["ruby", "-e", "require 'rfmt'; puts \"rfmt #{Rfmt::VERSION} ready on Ruby #{RUBY_VERSION}\""] + +# Stage 3: Test stage (includes verification) +FROM builder AS test + +# Run verification tests +RUN ruby -e "require 'rfmt'; puts \"rfmt #{Rfmt::VERSION} loaded successfully on Ruby #{RUBY_VERSION}\"" RUN echo 'def hello() puts "world" end' | rfmt || echo "CLI test completed" CMD ["ruby", "-e", "require 'rfmt'; puts \"rfmt #{Rfmt::VERSION} ready on Ruby #{RUBY_VERSION}\""] diff --git a/docker/compose.test.yml b/docker/compose.test.yml index b2146af..52b251c 100644 --- a/docker/compose.test.yml +++ b/docker/compose.test.yml @@ -1,21 +1,24 @@ # Docker Compose for testing rfmt across multiple Ruby versions # Usage: -# docker compose -f docker/docker-compose.test.yml build -# docker compose -f docker/docker-compose.test.yml up +# docker compose -f docker/compose.test.yml build +# docker compose -f docker/compose.test.yml up + +x-build-common: &build-common + context: .. + dockerfile: docker/Dockerfile.test + target: test services: test-ruby-3.4: build: - context: .. - dockerfile: docker/Dockerfile.test + <<: *build-common args: RUBY_VERSION: "3.4" image: rfmt-test:ruby-3.4 test-ruby-4.0: build: - context: .. - dockerfile: docker/Dockerfile.test + <<: *build-common args: RUBY_VERSION: "4.0" image: rfmt-test:ruby-4.0 diff --git a/scripts/test-gem-install.sh b/scripts/test-gem-install.sh index e55a733..e3bcfc3 100755 --- a/scripts/test-gem-install.sh +++ b/scripts/test-gem-install.sh @@ -8,37 +8,19 @@ set -euo pipefail -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_DIR="$(dirname "$SCRIPT_DIR")" - -# Default Ruby versions to test +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" DEFAULT_VERSIONS=("3.4" "4.0") -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -log_info() { - echo -e "${BLUE}[INFO]${NC} $1" -} - -log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly BLUE='\033[0;34m' +readonly NC='\033[0m' -log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} +log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } +log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } -log_warn() { - echo -e "${YELLOW}[WARN]${NC} $1" -} - -# Parse arguments -if [ $# -eq 0 ]; then +if [[ $# -eq 0 ]]; then VERSIONS=("${DEFAULT_VERSIONS[@]}") else VERSIONS=("$@") @@ -64,9 +46,9 @@ for version in "${VERSIONS[@]}"; do IMAGE_NAME="rfmt-test:ruby-${version}" - # Build the test image if docker build \ --build-arg RUBY_VERSION="${version}" \ + --target test \ -f docker/Dockerfile.test \ -t "$IMAGE_NAME" \ . 2>&1; then @@ -74,18 +56,13 @@ for version in "${VERSIONS[@]}"; do log_success "Ruby ${version}: gem install succeeded!" PASSED_VERSIONS+=("$version") - # Run additional verification log_info "Running verification tests..." - if docker run --rm "$IMAGE_NAME" ruby -e " + docker run --rm "$IMAGE_NAME" ruby -e " require 'rfmt' puts \" Version: #{Rfmt::VERSION}\" puts \" Rust version: #{Rfmt.rust_version}\" puts \" Ruby: #{RUBY_VERSION}\" - "; then - log_success "Ruby ${version}: verification passed!" - else - log_warn "Ruby ${version}: verification had issues" - fi + " && log_success "Ruby ${version}: verification passed!" else log_error "Ruby ${version}: gem install FAILED!" FAILED_VERSIONS+=("$version") @@ -99,11 +76,9 @@ echo " Summary" echo "========================================" echo "" -if [ ${#PASSED_VERSIONS[@]} -gt 0 ]; then - log_success "Passed: ${PASSED_VERSIONS[*]}" -fi +[[ ${#PASSED_VERSIONS[@]} -gt 0 ]] && log_success "Passed: ${PASSED_VERSIONS[*]}" -if [ ${#FAILED_VERSIONS[@]} -gt 0 ]; then +if [[ ${#FAILED_VERSIONS[@]} -gt 0 ]]; then log_error "Failed: ${FAILED_VERSIONS[*]}" echo "" exit 1