Skip to content
This repository was archived by the owner on Jul 20, 2026. It is now read-only.
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: 30 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Test

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['3.4.8', '4.0.1']
steps:
- uses: actions/checkout@v6
- name: Set Ruby version
run: echo "${{ matrix.ruby-version }}" > .ruby-version
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build test image
uses: docker/build-push-action@v6
with:
context: .
load: true
tags: drcheckr-test
cache-from: type=gha,scope=test-ruby-${{ matrix.ruby-version }}
cache-to: type=gha,mode=max,scope=test-ruby-${{ matrix.ruby-version }}
- name: Run tests
run: docker run --rm drcheckr-test
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ tmp

*.gem
.bundle
Gemfile.lock
vendor/bundle
external

Expand All @@ -21,4 +20,5 @@ node_modules

.idea/
.yardoc/
.claude/settings.local.json

50 changes: 50 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What is drcheckr

A Ruby gem that tracks dependencies across Docker images, checks for version updates, locks versions, and generates Dockerfiles from ERB templates. Configuration is YAML-driven (`drcheckr.yml` + `drcheckr-lock.yml`).

## Common Commands

```bash
# Run tests (preferred: via Docker)
docker build -t drcheckr-test . && docker run --rm drcheckr-test

# Run tests directly (requires Ruby 3.2+)
bundle install
bundle exec rake test

# Run a single test file
bundle exec ruby -Ilib test/bin/drcheckr_test.rb

# CLI usage
bin/drcheckr-cli check # Check if deps are up to date (exit 122 if outdated)
bin/drcheckr-cli update # Update versions in lock file
bin/drcheckr-cli gen # Generate Dockerfiles from templates
```

## Architecture

**Entry points:** `bin/drcheckr` (shell wrapper handling Ruby version managers) → `bin/drcheckr-cli` (Ruby entry point) → `Drcheckr::Cli`

**Core flow:** CLI parses args → `Checkrfile` loads YAML config/lock files → Commands execute:

- `Commands::UpdateChecker` — queries version APIs (GitHub releases/Atom, Chrome Version History, EndOfLife.date, fixed), compares with locked versions, updates lock file
- `Commands::GenDockerfile` — builds template context via `ContextData`/`VariableLoader`, renders ERB templates through `Generator::ContainerFileGenerator` (uses Tilt)
- `Commands::ExpressionEvaluator` — evaluates standalone ERB expressions with dependency context

**Key classes:**
- `Checkrfile` — loads and caches `drcheckr.yml` and `drcheckr-lock.yml`
- `ContextData` — assembles template binding from dependencies + variables (exposes `{dep}_version` as `VersionNumber` objects)
- `VersionNumber` — semantic version parser with `major`/`minor`/`patch` accessors, handles `v` prefix

## Conventions

- All files use `# frozen_string_literal: true`
- All classes nested under `Drcheckr` module; commands under `Drcheckr::Commands`
- Exit code 122 means "outdated dependencies"
- `CHECKRFILE` env var overrides default config file path
- No linter configured; no `.rubocop.yml`
- CI tests against Ruby 3.4 and 4.0 (`.github/workflows/test.yml`)
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Contributing

## Running tests

Tests run inside Docker. Build the image and run the suite with:

```sh
docker build -t drcheckr-test . && docker run --rm drcheckr-test
```
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM debian:trixie-slim

RUN apt-get update && apt-get install -y \
git curl build-essential libssl-dev libreadline-dev \
zlib1g-dev libyaml-dev libffi-dev autoconf && \
rm -rf /var/lib/apt/lists/*

# Install rbenv + ruby-build
RUN git clone https://github.com/rbenv/rbenv.git /root/.rbenv && \
git clone https://github.com/rbenv/ruby-build.git /root/.rbenv/plugins/ruby-build
ENV PATH="/root/.rbenv/shims:/root/.rbenv/bin:$PATH"

# Install Ruby version from .ruby-version
COPY .ruby-version /app/.ruby-version
WORKDIR /app
RUN rbenv install "$(cat .ruby-version)" && rbenv global "$(cat .ruby-version)"

# Install gems (layered for caching)
RUN gem install bundler
COPY Gemfile Gemfile.lock drcheckr.gemspec /app/
COPY lib/drcheckr/version.rb /app/lib/drcheckr/version.rb
RUN bundle install

# Copy full project
COPY . /app/

CMD ["bundle", "exec", "rake", "test"]
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ gemspec

gem 'nokogiri'
gem 'excon'
gem 'logger'
gem 'ostruct'
gem 'debug'
gem 'minitest'
gem 'rake'
gem 'cgi'
72 changes: 72 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
PATH
remote: .
specs:
drcheckr (0.1.0)
excon (~> 0.111)
tilt (~> 2.4)

GEM
remote: https://rubygems.org/
specs:
cgi (0.5.1)
date (3.5.1)
debug (1.11.1)
irb (~> 1.10)
reline (>= 0.3.8)
erb (6.0.1)
excon (0.112.0)
io-console (0.8.2)
irb (1.17.0)
pp (>= 0.6.0)
prism (>= 1.3.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
logger (1.7.0)
minitest (6.0.1)
prism (~> 1.5)
nokogiri (1.19.0-arm64-darwin)
racc (~> 1.4)
nokogiri (1.19.0-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.19.0-x86_64-linux-gnu)
racc (~> 1.4)
ostruct (0.6.3)
pp (0.6.3)
prettyprint
prettyprint (0.2.0)
prism (1.9.0)
psych (5.3.1)
date
stringio
racc (1.8.1)
rake (13.3.1)
rdoc (7.2.0)
erb
psych (>= 4.0.0)
tsort
reline (0.6.3)
io-console (~> 0.5)
stringio (3.2.0)
tilt (2.7.0)
tsort (0.2.0)

PLATFORMS
arm64-darwin-23
arm64-darwin-24
arm64-darwin-25
x86_64-darwin-22
x86_64-linux

DEPENDENCIES
cgi
debug
drcheckr!
excon
logger
minitest
nokogiri
ostruct
rake

BUNDLED WITH
4.0.6
10 changes: 10 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

require 'rake/testtask'

Rake::TestTask.new(:test) do |t|
t.libs << 'test'
t.test_files = FileList['test/**/*_test.rb']
end

task default: :test
59 changes: 51 additions & 8 deletions bin/drcheckr
Original file line number Diff line number Diff line change
@@ -1,11 +1,54 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#!/usr/bin/env sh
set -e

begin
lib_dir = File.expand_path("#{__dir__}/../lib")
$:.unshift(lib_dir)
end
# Resolve the real directory of this script, following symlinks.
SCRIPT="$0"
while [ -L "$SCRIPT" ]; do
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT")" && pwd)"
SCRIPT="$(readlink "$SCRIPT")"
case "$SCRIPT" in
/*) ;;
*) SCRIPT="$SCRIPT_DIR/$SCRIPT" ;;
esac
done
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT")" && pwd)"

require 'drcheckr'
# Locate a Ruby version manager and activate it so we get the right Ruby.
setup_ruby() {
# Try mise first (on PATH, then default install location).
if command -v mise >/dev/null 2>&1; then
eval "$(mise activate sh 2>/dev/null)" || true
eval "$(mise hook-env -s sh 2>/dev/null)" || true
return 0
elif [ -x "$HOME/.local/bin/mise" ]; then
eval "$("$HOME/.local/bin/mise" activate sh 2>/dev/null)" || true
eval "$("$HOME/.local/bin/mise" hook-env -s sh 2>/dev/null)" || true
return 0
fi

Drcheckr::Cli.start(ARGV)
# Try rbenv (on PATH, then default install location).
if command -v rbenv >/dev/null 2>&1; then
eval "$(rbenv init - sh 2>/dev/null)" || true
return 0
elif [ -x "$HOME/.rbenv/bin/rbenv" ]; then
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init - sh 2>/dev/null)" || true
return 0
fi

return 1
}

if ! setup_ruby; then
echo "drcheckr: error: no Ruby version manager found (tried mise, rbenv)." >&2
echo "Install mise (https://mise.jdx.dev) or rbenv (https://github.com/rbenv/rbenv) to manage Ruby." >&2
exit 1
fi

# Verify ruby is now available.
if ! command -v ruby >/dev/null 2>&1; then
echo "drcheckr: error: ruby not found after activating version manager. Ensure Ruby is installed." >&2
exit 1
fi

exec ruby "$SCRIPT_DIR/drcheckr-cli" "$@"
11 changes: 11 additions & 0 deletions bin/drcheckr-cli
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

begin
lib_dir = File.expand_path("#{__dir__}/../lib")
$:.unshift(lib_dir)
end

require 'drcheckr'

Drcheckr::Cli.start(ARGV)
17 changes: 17 additions & 0 deletions test/bin/drcheckr_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

require 'test_helper'

class DrcheckrBinTest < Minitest::Test
def test_binary_runs_successfully
output = `#{bin_path} --help 2>&1`

assert_equal 0, $?.exitstatus, "Expected bin/drcheckr to exit 0, got #{$?.exitstatus}.\nOutput:\n#{output}"
end

private

def bin_path
File.expand_path('../../bin/drcheckr', __dir__)
end
end
30 changes: 30 additions & 0 deletions test/commands/gen_dockerfile_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

require 'test_helper'
require 'drcheckr'
require 'tmpdir'
require 'fileutils'

class GenDockerfileTest < Minitest::Test
FIXTURE_DIR = File.expand_path('../fixtures/gen_dockerfile', __dir__)

def test_generates_dockerfile_from_template
Dir.mktmpdir do |tmpdir|
FileUtils.cp(File.join(FIXTURE_DIR, 'drcheckr.yml'), tmpdir)
FileUtils.cp(File.join(FIXTURE_DIR, 'drcheckr-lock.yml'), tmpdir)
FileUtils.mkdir_p(File.join(tmpdir, 'my_image'))
FileUtils.cp(File.join(FIXTURE_DIR, 'my_image', 'Dockerfile.erb'), File.join(tmpdir, 'my_image'))

Dir.chdir(tmpdir) do
checkrfile = Drcheckr::Checkrfile.new('drcheckr.yml')
cmd = Drcheckr::Commands::GenDockerfile.new(checkrfile, additional_vars: {})
cmd.run!

generated = File.read(File.join(tmpdir, 'my_image', 'Dockerfile'))
expected = File.read(File.join(FIXTURE_DIR, 'my_image', 'Dockerfile'))

assert_equal expected, generated
end
end
end
end
Loading