Skip to content

fix(setup): generate .gitignore for new projects#180

Merged
frankbria merged 4 commits intomainfrom
feature/issue-174-setup-gitignore
Feb 17, 2026
Merged

fix(setup): generate .gitignore for new projects#180
frankbria merged 4 commits intomainfrom
feature/issue-174-setup-gitignore

Conversation

@frankbria
Copy link
Owner

@frankbria frankbria commented Feb 17, 2026

Summary

Implements #174: setup.sh does not generate .gitignore for new projects

  • Added templates/.gitignore with comprehensive Ralph runtime file patterns (extracted from create_files.sh)
  • Updated setup.sh to copy .gitignore template to new project root before git init
  • Updated lib/enable_core.sh to create .gitignore via safe_create_file() during ralph-enable, respecting --force flag
  • Added 8 tests covering creation, content validation, git tracking, template missing, force/skip behavior

Acceptance Criteria

  • New projects (ralph-setup my-project) get .gitignore at project root
  • Enabled projects (ralph enable) get .gitignore if none exists
  • ralph enable --force overwrites existing .gitignore
  • Existing .gitignore preserved without --force
  • Graceful handling when template is missing
  • .gitignore committed in initial git commit

Test Plan

  • 507/507 tests passing (499 existing + 5 setup.sh + 3 enable_core)
  • setup.sh: .gitignore created, content matches template, committed to git, graceful when template missing
  • enable_core: .gitignore created from template, skip when exists, force overwrite

Closes #174

Summary by CodeRabbit

  • New Features

    • Automatically populates a .gitignore from a project template during initialization; preserves an existing .gitignore unless explicitly forced; template copying now includes dotfiles.
  • Tests

    • Added unit and integration tests covering .gitignore creation, template presence/absence, overwrite behavior, and isolated test environments; test suite now reflects 510 tests.
  • Documentation

    • Updated test metrics and descriptions to match expanded suite.

setup.sh and ralph-enable now create a .gitignore that excludes
Ralph runtime files (.call_count, status.json, logs, etc.) from
git tracking. Uses a template in templates/.gitignore as the
single source of truth.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

No actionable comments were generated in the recent review. 🎉


Walkthrough

Adds a .gitignore template and logic to copy it into new projects (setup and enable flows), updates install behavior to include dotfiles, expands tests for .gitignore handling, and updates test counts and descriptions to reflect 510 total tests.

Changes

Cohort / File(s) Summary
Docs / Test counts
CLAUDE.md
Updated test total and test descriptions to reflect new .gitignore tests and the new 510-test total.
Templates
templates/.gitignore
New .gitignore template added with Ralph runtime, logs, generated docs, OS/IDE/build, and backup ignore patterns.
Setup & enable flows
setup.sh, lib/enable_core.sh, install.sh
Added logic to copy templates/.gitignore into project root when absent; install.sh now enables dotglob to include dotfiles during template copy; enable flow resolves templates dir and writes .gitignore (warns and continues if template missing).
Integration tests
tests/integration/test_project_setup.bats, tests/integration/test_installation.bats
Added integration tests verifying .gitignore is copied from template, content matches, is tracked in initial commit, and that install copies dotfile templates.
Unit tests
tests/unit/test_enable_core.bats
Added HOME isolation and unit tests for .gitignore creation, preservation, and FORCE overwrite; the new test block appears duplicated in the file.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as "ralph-setup / setup.sh"
    participant Enable as "lib/enable_core.sh"
    participant Templates as "templates/.gitignore"
    participant FS as "Project filesystem"
    participant Git as "git"

    CLI->>Enable: invoke enable_ralph_in_directory / setup flow
    Enable->>Templates: get_templates_dir -> read `.gitignore` (if exists)
    Templates-->>Enable: return `.gitignore` contents or missing
    Enable->>FS: write `.ralph/fix_plan.md`
    alt .gitignore template present and file absent
        Enable->>FS: write `.gitignore` to project root
        FS->>Git: (integration) add/commit `.gitignore`
    else template missing
        Enable->>FS: log warning, skip `.gitignore`
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐇 I hop through templates, tidy and spry,
I hide stray logs where commits won't pry,
A nibble, a copy, a quiet little trick,
.gitignore snug, neat and slick,
Hooray — clean repos, one small hop 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: generating .gitignore for new projects during setup, which is the primary objective of this PR.
Linked Issues check ✅ Passed The PR fully addresses issue #174 requirements: templates/.gitignore created with Ralph patterns, setup.sh copies template to new projects, enable_core.sh creates .gitignore with force/preserve logic, template-missing handled gracefully, and .gitignore included in git commits.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing issue #174: .gitignore template creation and deployment flows. The dotglob fix in install.sh is necessary for dotfile copying. CLAUDE.md updates and test additions are directly related to the implementation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/issue-174-setup-gitignore

Comment @coderabbitai help to get the list of available commands and usage tips.

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Feb 17, 2026

Generate a project-root .gitignore from the template during install, setup, and core enable flows for new projects

Add dotfile copying in install.sh using dotglob; create or overwrite .gitignore from templates/.gitignore in enable_core.enable_ralph_in_directory and setup.sh; add a .gitignore template and tests; update documented test counts.

📍Where to Start

Start with the .gitignore creation logic in enable_core.enable_ralph_in_directory in lib/enable_core.sh, then review the template copy in setup.sh and the dotfile handling in install.sh.


Macroscope summarized 28c955d.

@github-actions
Copy link

Code Review: fix(setup): generate .gitignore for new projects

This PR correctly addresses issue 174. The implementation is clean, consistent, and well-tested. Here are my observations:


What works well

Template-based approach — Extracting the hardcoded gitignore content from create_files.sh into templates/.gitignore is the right design. A single source of truth means future gitignore updates propagate to both ralph-setup and ralph-enable automatically.

Idempotency via safe_create_file — Reusing the existing safe_create_file() function in enable_core.sh ensures the --force flag behaviour is consistent with how all other Ralph files are managed. No custom skip/overwrite logic was needed.

Graceful degradation in setup.sh — The conditional if [[ -f "$TEMPLATES_DIR/.gitignore" ]] means a missing template is non-fatal, which matches how other optional template files are handled.

Consistent content — The template content in templates/.gitignore is a byte-for-byte match with the inline heredoc in create_files.sh, preserving parity between the two installation paths.


Observations and suggestions

1. enable_core.sh — WARN log fires for both missing-dir and missing-file cases

In enable_ralph_in_directory, the else branch fires when get_templates_dir returns nothing or when .gitignore is not present in the templates directory. Both cases emit ".gitignore template not found, skipping". This is acceptable, though more granular messaging (e.g. distinguishing "templates dir not found" from "templates dir found but .gitignore missing") would help with debugging. Not a blocker.

2. enable_core.sh|| true after subshell suppresses unexpected failures silently

templates_dir=$(get_templates_dir 2>/dev/null) || true

The || true prevents set -e from terminating the script if get_templates_dir returns exit code 1 (template dir not found), which is intentional. The 2>/dev/null also silences unexpected errors. Since get_templates_dir only does directory checks, this is safe in practice. Consistent with patterns elsewhere in the file.

3. setup.sh.gitignore copied before enable_core.sh is sourced (correct ordering)

The .gitignore copy (lines 50-53) happens before enable_core.sh is sourced (line 60). This is intentional — setup.sh uses a simple cp rather than safe_create_file, which is appropriate since a new project directory has no existing .gitignore to protect. The asymmetry between setup.sh (cp) and enable_core.sh (safe_create_file) is justified by the different contexts.

4. Test: "setup.sh .gitignore content matches template" — diff assertion

diff templates/.gitignore test-project/.gitignore

This passes because cp preserves content exactly. If the copy mechanism were ever changed to printf '%s\n' (as safe_create_file uses internally), the extra trailing newline could cause this diff to fail. Worth keeping in mind if setup.sh is later refactored to use the library function.

5. Missing test: enable_core.sh template-not-found path

The unit tests in test_enable_core.bats cover: template exists (create), file exists without force (skip), and file exists with force (overwrite). There is no test for the case where $HOME/.ralph/templates/.gitignore is absent while get_templates_dir still succeeds (i.e. the templates dir exists but contains no .gitignore). The graceful degradation in the else branch is not directly exercised. Consider adding a test asserting enable_ralph_in_directory succeeds when the templates directory exists but contains no .gitignore.

6. .ralphrc not excluded from .gitignore

.ralphrc is committed to the repo by design (it contains project configuration), so omitting it from the gitignore is correct. Confirming this is intentional rather than an oversight.

7. CLAUDE.md test count — Updated from 499 to 507 (8 net new tests: 5 in test_project_setup.bats + 3 in test_enable_core.bats). This matches the PR description.


Summary

The implementation is solid. The one actionable item is point 5 — a test for the "templates directory exists but .gitignore is missing" path in enable_core.sh. The existing tests cover the critical happy paths and force/skip behaviour. This is a clean, low-risk addition that closes a real usability gap for new projects.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
setup.sh (1)

50-53: Consider preserving an existing .gitignore on reruns.
Currently cp will overwrite a custom .gitignore if setup.sh is re-run in an existing directory. Skipping when the file already exists would avoid data loss while still meeting the creation requirement for new projects.

Suggested tweak
 if [[ -f "$TEMPLATES_DIR/.gitignore" ]]; then
-    cp "$TEMPLATES_DIR/.gitignore" .gitignore
+    if [[ -f ".gitignore" ]]; then
+        echo "ℹ️  .gitignore already exists; skipping"
+    else
+        cp "$TEMPLATES_DIR/.gitignore" .gitignore
+    fi
 fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@setup.sh` around lines 50 - 53, The current block unconditionally copies
"$TEMPLATES_DIR/.gitignore" to .gitignore which will overwrite an existing
custom .gitignore on reruns; update the logic in setup.sh to first check for the
presence of a local .gitignore and only copy the template if no .gitignore
exists (i.e., add a condition like [[ ! -f ".gitignore" ]] before cp or use cp
--no-clobber if available), referencing the existing TEMPLATES_DIR variable and
the target .gitignore so rerunning setup.sh preserves user changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/unit/test_enable_core.bats`:
- Around line 394-454: The tests mutate $HOME/.ralph/templates and leak state;
update the test suite to isolate HOME by saving original HOME, creating a
temporary TEST_DIR in setup(), exporting HOME="$TEST_DIR" (so
enable_ralph_in_directory writes under $HOME/.ralph/templates inside TEST_DIR),
and restoring the original HOME in teardown() while removing TEST_DIR; ensure
setup() creates the temp dir and teardown() cleans it up and restores any saved
env so tests that call enable_ralph_in_directory behave sandboxed and leave no
artifacts.

---

Nitpick comments:
In `@setup.sh`:
- Around line 50-53: The current block unconditionally copies
"$TEMPLATES_DIR/.gitignore" to .gitignore which will overwrite an existing
custom .gitignore on reruns; update the logic in setup.sh to first check for the
presence of a local .gitignore and only copy the template if no .gitignore
exists (i.e., add a condition like [[ ! -f ".gitignore" ]] before cp or use cp
--no-clobber if available), referencing the existing TEMPLATES_DIR variable and
the target .gitignore so rerunning setup.sh preserves user changes.

Address code review feedback:
- Override HOME to temp dir in test setup/teardown to prevent state
  leaking to developer's real home directory (CodeRabbit)
- Add test for graceful degradation when templates dir exists but
  .gitignore template is missing (Claude review)
@github-actions
Copy link

Review Summary

This PR successfully implements issue #174 with high-quality code and comprehensive test coverage. The implementation is clean and follows established patterns in the codebase.

✅ Addresses Previous Review Feedback

Test Isolation: The test suite now properly isolates using / hooks (). This prevents state leakage to the developer's real home directory.

Edge Case Coverage: Added test for graceful degradation when templates directory exists but template is missing ().

💡 Implementation Observations

Template-Based Design: Extracting gitignore patterns to is the right choice. This creates a single source of truth that automatically benefits both and .

Idempotency in enable_core: Using ensures consistent behavior with other Ralph files. The implementation correctly preserves existing unless explicitly overridden.

setup.sh Context: The current implementation unconditionally copies templates (lines 45-53), which is consistent with how all template files are handled. While a preservation check could prevent accidental overwrites on re-runs, setup.sh is designed for fresh project creation rather than idempotent re-execution.

✅ Acceptance Criteria Met

  • New projects get at project root
  • Enabled projects get if none exists
  • flag overwrites existing
  • Existing preserved without
  • Graceful handling when template is missing
  • All 507 tests passing

Recommendation

APPROVED - This PR is ready to merge. The code is well-tested, follows repository conventions, and all major concerns from prior reviews have been addressed. The setup.sh template copy behavior is consistent with existing patterns and appropriate for the script's intended use case (new project creation).

@github-actions
Copy link

Review Summary

This PR successfully implements issue #174 with high-quality code and comprehensive test coverage. The implementation is clean and follows established patterns in the codebase.

✅ Addresses Previous Review Feedback

Test Isolation: The test suite now properly isolates $HOME using setup()/teardown() hooks (tests/unit/test_enable_core.bats:12-33). This prevents state leakage to the developer's real home directory.

Edge Case Coverage: Added test for graceful degradation when templates directory exists but .gitignore template is missing (tests/unit/test_enable_core.bats:457-470).

💡 Implementation Observations

Template-Based Design: Extracting gitignore patterns to templates/.gitignore is the right choice. This creates a single source of truth that automatically benefits both ralph-setup and ralph-enable.

Idempotency in enable_core: Using safe_create_file() ensures consistent --force behavior with other Ralph files. The implementation correctly preserves existing .gitignore unless explicitly overridden.

setup.sh Context: The current implementation unconditionally copies templates (lines 45-53), which is consistent with how all template files are handled. While a preservation check could prevent accidental overwrites on re-runs, setup.sh is designed for fresh project creation rather than idempotent re-execution.

✅ Acceptance Criteria Met

  • New projects get .gitignore at project root
  • Enabled projects get .gitignore if none exists
  • --force flag overwrites existing .gitignore
  • Existing .gitignore preserved without --force
  • Graceful handling when template is missing
  • All 507 tests passing

Recommendation

APPROVED - This PR is ready to merge. The code is well-tested, follows repository conventions, and all major concerns from prior reviews have been addressed. The setup.sh template copy behavior is consistent with existing patterns and appropriate for the script's intended use case (new project creation).

@github-actions
Copy link

PR Review: fix(setup): generate .gitignore for new projects

This PR cleanly resolves issue No. 174 with well-structured changes across three layers (template, setup.sh, enable_core.sh) and solid test coverage. Below are my observations.


What Works Well

  • Correct use of safe_create_file() in enable_core.sh — respects ENABLE_FORCE and the skip/overwrite logic already in place without duplicating that logic.
  • Graceful degradation — both setup.sh and enable_core.sh treat a missing template as a soft warning rather than a hard failure, which is the right behavior for an optional file.
  • HOME isolation in tests — the setup() / teardown() pair that sets HOME="$TEST_DIR/home" is a good fix; it prevents test pollution and makes the enable_core tests genuinely hermetic.
  • install.sh compatibilitycp -r "$SCRIPT_DIR/templates/"* already copies hidden files on most Linux shells, so templates/.gitignore will be included in global installs without any change to install.sh. Worth a quick sanity check since glob expansion of * excludes dot-files in some shells/configurations (see note below).

Issues / Suggestions

1. Glob expansion of * may skip .gitignore during install

install.sh line 112 uses:

cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"

In bash with default settings, * does not match dot-files (files starting with .). So templates/.gitignore will be silently skipped during install.sh, causing the global installation to lack the template. This would break both ralph-setup and ralph-enable for globally installed users.

Consider one of:

# Option A: explicit shopt
shopt -s dotglob
cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"
shopt -u dotglob

# Option B: use find or rsync
rsync -a "$SCRIPT_DIR/templates/" "$RALPH_HOME/templates/"

# Option C: explicit copy alongside the wildcard
cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"
cp "$SCRIPT_DIR/templates/".gitignore "$RALPH_HOME/templates/" 2>/dev/null || true

This is the most impactful issue in the PR — without it, the feature silently fails for production installs.

2. enable_core.sh: warn log fires when templates dir itself is missing

templates_dir=$(get_templates_dir 2>/dev/null) || true
if [[ -n "$templates_dir" ]] && [[ -f "$templates_dir/.gitignore" ]]; then
    ...
else
    enable_log "WARN" ".gitignore template not found, skipping"
fi

The WARN message fires in two distinct situations: (a) the templates directory was found but has no .gitignore, or (b) get_templates_dir returned empty (Ralph not installed). Case (b) is expected in CI/Docker environments and may confuse users with a spurious warning. Consider splitting the branches:

if [[ -z "$templates_dir" ]]; then
    enable_log "INFO" "No templates directory found, skipping .gitignore"
elif [[ ! -f "$templates_dir/.gitignore" ]]; then
    enable_log "WARN" ".gitignore template not found in $templates_dir, skipping"
fi

3. Template content: *.log is broad

templates/.gitignore includes *.log as a general catch-all. This will silently exclude any project log file the developer might want to track (e.g., CHANGELOG.log, audit.log). The Ralph-specific paths are already scoped to .ralph/logs/*, so the project-root *.log entry adds questionable value and may surprise users. Worth a brief comment or removal.

4. Test: missing run wrapper on two assertions

In test_project_setup.bats:

@test "setup.sh .gitignore contains Ralph runtime patterns" {
    ...
    bash "$SETUP_SCRIPT" test-project

    grep -q ".ralph/.call_count" test-project/.gitignore      # bare grep — no `run`
    grep -q ".ralph/.circuit_breaker_state" test-project/.gitignore
}

These grep calls run without run, so bats cannot capture their exit status. If grep fails the test will still pass (or produce a confusing failure). The pattern should be:

run grep -q ".ralph/.call_count" test-project/.gitignore
assert_success

The same applies to setup.sh .gitignore content matches template which uses bare diff. This is a test-quality issue, not a blocker, but it limits the diagnostic value of test failures.

5. safe_create_file return value ignored

safe_create_file ".gitignore" "$gitignore_content"

safe_create_file returns 1 when the file is skipped and 2 on error. In the surrounding code, .ralph/PROMPT.md etc. are created without checking the return value either, so this is consistent with existing style. Just noting it for awareness — a future improvement might want to surface write errors.


Summary

The implementation is correct and well-tested for the happy path. The main actionable concern is the install.sh dotglob issue (point 1) — verify that templates/.gitignore is actually copied during ./install.sh before merging. The other items are lower-priority improvements.

@github-actions
Copy link

Review comment posted to PR #180.

New%20session%20-%202026-02-17T20%3A17%3A53.055Z
opencode session  |  github run

Skip copying .gitignore template when one already exists in the
project directory. Prevents overwriting user customizations when
setup.sh is re-run in an existing directory.
@github-actions
Copy link

Code Review: fix(setup): generate .gitignore for new projects

This PR successfully implements issue #174 with high-quality code and comprehensive test coverage. The implementation follows repository conventions and addresses most concerns from prior reviews.

✅ What Works Well

Test isolation fixed - The setup()/teardown() hooks in test_enable_core.bats now properly isolate /home/runner, preventing state leakage to the developer's real home directory (tests/unit/test_enable_core.bats:12-33).

Preserves existing .gitignore - setup.sh now checks for an existing .gitignore before copying (setup.sh:50-53), addressing the data loss concern raised in earlier reviews.

Edge case coverage - Added test for graceful degradation when templates directory exists but .gitignore is missing (test_enable_core.bats:457-470).

Graceful degradation - Both setup.sh and enable_core.sh treat a missing template as a soft warning rather than a hard failure, which is appropriate for an optional file.


⚠️ Critical Issue: install.sh dotglob

Line 112 in install.sh:

cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"

In bash with default settings, * does not match dot-files. This means templates/.gitignore will not be copied during ./install.sh, silently breaking the feature for all globally installed users.

Recommended fix:

# Enable dotglob temporarily
shopt -s dotglob
cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"
shopt -u dotglob

Or use rsync or cp -a templates/. to copy all files including dot-files.

This is the most impactful issue — without it, the feature silently fails in production installations.


🟡 Test Quality Issues

Missing run wrapper (test_project_setup.bats):

# Line 576-577: Should be wrapped in `run`
grep -q ".ralph/.call_count" test-project/.gitignore
grep -q ".ralph/.circuit_breaker_state" test-project/.gitignore

# Line 603: Should be wrapped in `run`
diff templates/.gitignore test-project/.gitignore

These assertions run without run, so bats cannot capture their exit status. If grep/diff fail, the test may still pass with confusing failure messages. The pattern should be:

run grep -q ".ralph/.call_count" test-project/.gitignore
assert_success

ℹ️ Minor Observations

WARN log granularity (enable_core.sh:788): The ".gitignore template not found, skipping" message fires whether the templates dir itself is missing OR when templates dir exists but has no .gitignore. Splitting these cases would improve debugging, though this is not a blocker.

Template content breadth (templates/.gitignore:20): *.log is a broad catch-all that will silently exclude any project log file developers might want to track (e.g., CHANGELOG.log). The Ralph-specific logs are already scoped to .ralph/logs/*, so the project-root *.log entry adds questionable value.


✅ Acceptance Criteria Met

  • New projects get .gitignore at project root
  • Enabled projects get .gitignore if none exists
  • --force flag overwrites existing .gitignore
  • Existing .gitignore preserved without --force
  • Graceful handling when template is missing
  • All 507 tests passing

Recommendation

REQUEST CHANGES - The install.sh dotglob issue is a production bug that will cause the feature to silently fail for globally installed users. This must be fixed before merging. The test quality issues are lower priority but should be addressed for maintainability.

@github-actions
Copy link

Review comment posted to PR #180.

New%20session%20-%202026-02-17T20%3A31%3A12.008Z
opencode session  |  github run

@github-actions
Copy link

Review: fix(setup): generate .gitignore for new projects

The implementation is correct and well-structured. I want to follow up specifically on the one outstanding issue from the previous review that hasn't been addressed yet.


Critical: install.sh dotglob issue still unresolved

The previous review flagged this as the most impactful concern, and it remains unaddressed in the current state of the PR.

Line 112 of install.sh:

cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"

In bash's default configuration, the glob * does not expand to dotfiles (files beginning with .). This means templates/.gitignore will be silently skipped during ./install.sh, and globally installed users will never receive the template. Both ralph-setup and ralph-enable will silently fall back to the "template not found" path for every new project.

The same pattern at line 115 for lib/ is not affected because none of the lib files are dotfiles.

A straightforward fix for install.sh:

# Option A: enable dotglob for the copy, then restore
shopt -s dotglob
cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"
shopt -u dotglob

# Option B: explicit separate copy for dotfiles
cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"
cp "$SCRIPT_DIR/templates/.gitignore" "$RALPH_HOME/templates/" 2>/dev/null || true

Option A is cleaner as it handles any future dotfile templates generically.


Everything else looks good

The core implementation in setup.sh and enable_core.sh is correct. Template content matches create_files.sh. The safe_create_file() usage in enable_core.sh correctly handles force/skip logic without duplicating it. The HOME isolation fix in the test setup/teardown hooks is the right approach.

The test count discrepancy (PR description says 507/507 passing, CLAUDE.md says 509) is minor — likely reflects the final count after the last test additions.


Summary

This PR is one fix away from being ready: update install.sh to copy dotfiles from the templates directory. Without that change, the feature works correctly only for users running Ralph from source, not for the globally installed workflow that ./install.sh supports.

Bash glob * skips dotfiles by default, so templates/.gitignore was
silently excluded during install.sh. Enable dotglob around the
templates copy to handle dotfile templates generically.
@github-actions
Copy link

Review: fix(setup): generate .gitignore for new projects (follow-up)

This is a follow-up to previous review comments on this PR. Here is a focused assessment of the current state.


Critical Issue Resolved

The install.sh dotglob issue — flagged as the most impactful concern in prior reviews — has been addressed:

shopt -s dotglob
cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"
shopt -u dotglob

This correctly ensures templates/.gitignore is included when copying to the global installation. The fix is minimal and reversible (dotglob is restored immediately after). A corresponding test in test_installation.bats was added to validate that dotfile templates like .gitignore are copied during install. This was the main blocker and it is now resolved.


Test Count Discrepancy

The PR description states 507/507 tests pass, but CLAUDE.md has been updated to reflect 510 tests. The test table breakdown adds up correctly: test_installation.bats went from 14 to 15 (+1), test_project_setup.bats from 44 to 50 (+6), and test_enable_core.bats from 32 to 36 (+4), for a net gain of 11 tests — yet the total only increased from 499 to 510 (+11). The PR description claiming 507 is stale and should be updated to match the CLAUDE.md count of 510. Minor, but it affects traceability.


Remaining Test Quality Issue

The bare grep and diff calls in test_project_setup.bats (from the prior review) remain in the diff:

# No 'run' wrapper — bats cannot capture exit status
grep -q ".ralph/.call_count" test-project/.gitignore
grep -q ".ralph/.circuit_breaker_state" test-project/.gitignore
diff templates/.gitignore test-project/.gitignore

These tests will pass even if the grep or diff fails, because bats only intercepts failures through the run wrapper. The fix is straightforward:

run grep -q ".ralph/.call_count" test-project/.gitignore
assert_success
run grep -q ".ralph/.circuit_breaker_state" test-project/.gitignore
assert_success

This is not a blocker for the feature itself, but it weakens the test safety net.


setup.sh Existing .gitignore Guard

The current diff now includes [[ ! -f ".gitignore" ]] in setup.sh:

if [[ -f "$TEMPLATES_DIR/.gitignore" ]] && [[ ! -f ".gitignore" ]]; then
    cp "$TEMPLATES_DIR/.gitignore" .gitignore
fi

This addresses the data-loss concern raised by CodeRabbitAI and is the correct behavior — preserving user-customized .gitignore files on re-runs.


Summary

The critical install.sh dotglob issue has been fixed. The implementation is solid and meets all acceptance criteria. The remaining items are:

  1. Test quality (non-blocking): Wrap bare grep and diff assertions in run + assert_success in test_project_setup.bats
  2. PR description (cosmetic): Update the stated test count from 507 to 510 to match CLAUDE.md

The core functionality is correct and well-tested. Happy to approve once the test wrapper issue is addressed, or if you prefer to merge as-is given the low severity.

@github-actions
Copy link

Review: fix(setup): generate .gitignore for new projects

This PR successfully addresses issue #174. All critical concerns from previous reviews have been addressed.

✅ Fixes Applied

install.sh dotglob issue (CRITICAL - FIXED)

  • Lines 112-114 now properly enable shopt -s dotglob before copying templates, ensuring .gitignore is included during global installs
  • Restores shopt -u dotglob after the copy to avoid side effects

Test isolation (FIXED)

  • test_enable_core.bats now properly isolates $HOME using setup()/teardown() hooks (lines 10, 18-19, 28-32)
  • Prevents state leakage to developer's real home directory

Existing .gitignore preservation (FIXED)

  • setup.sh (lines 51-53) now checks [[ ! -f ".gitignore" ]] before copying
  • Prevents accidental overwrites on re-runs

Edge case coverage (ADDED)

  • Added test for graceful degradation when templates directory exists but .gitignore is missing
  • Integration test verifies install.sh correctly copies dotfile templates

✅ Acceptance Criteria Met

  • New projects get .gitignore at project root
  • Enabled projects get .gitignore if none exists
  • --force flag overwrites existing .gitignore (via safe_create_file)
  • Existing .gitignore preserved without --force
  • Graceful handling when template is missing
  • .gitignore committed in initial git commit

ℹ️ Minor Observations

Test quality - Some assertions in test_project_setup.bats use bare grep/diff without the run wrapper (lines 576-577, 603, 627). This limits diagnostic value but doesn't affect test correctness. Not a blocker.

Template breadth - .gitignore includes *.log pattern (line 20) which is broad but reasonable as a default. Users can customize. Ralph-specific logs are already scoped to .ralph/logs/*.

Recommendation

APPROVED - This PR is ready to merge. The implementation is clean, well-tested, and all critical issues from previous reviews have been addressed.

@github-actions
Copy link

Review comment posted to PR #180.

New%20session%20-%202026-02-17T20%3A40%3A44.178Z
opencode session  |  github run

@frankbria frankbria merged commit f94557c into main Feb 17, 2026
7 checks passed
@frankbria frankbria deleted the feature/issue-174-setup-gitignore branch February 17, 2026 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

setup.sh does not generate .gitignore for new projects

1 participant