Skip to content

feat(cli): initialize git on new#219

Merged
NickSeagull merged 2 commits into
neohaskell:mainfrom
DeviousStoat:init-git
Nov 15, 2025
Merged

feat(cli): initialize git on new#219
NickSeagull merged 2 commits into
neohaskell:mainfrom
DeviousStoat:init-git

Conversation

@DeviousStoat

@DeviousStoat DeviousStoat commented Nov 13, 2025

Copy link
Copy Markdown
Contributor

closes #197

Summary by CodeRabbit

  • New Features
    • Automatic Git initialization for new projects and generation of a .gitignore file.
    • .gitignore template added covering build outputs, IDE, and OS-related files.
  • Bug Fixes
    • Project creation is resilient: if Git initialization fails, a non-fatal warning is shown and creation proceeds.

@coderabbitai

coderabbitai Bot commented Nov 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Project creation now attempts to initialize a Git repository: it writes a .gitignore from a new template, runs git init, stages files and makes an initial commit; git failures are captured and reported as non‑fatal warnings so project creation still completes.

Changes

Cohort / File(s) Summary
Build Configuration
cli/nhcli.cabal
Exposed new module Neo.New.Templates.GitIgnore in the library section.
Git Ignore Template
cli/src/Neo/New/Templates/GitIgnore.hs
New module providing template :: Text that contains the .gitignore content (build outputs, IDE, OS ignores).
Project Creation Logic
cli/src/Neo/New.hs
Added openGit to run git subprocesses and initGit to create .gitignore, run git init, git add ., and commit; integrated initGit into the project creation flow and mapped git failures to non‑fatal warnings; added imports for the new template and subprocess usage.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Neo as "neo new"
    participant Project as "Project Creator"
    participant Git as "Git Ops"
    participant Warn as "Warning Handler"

    User->>Neo: neo new my-project
    Neo->>Project: create project structure
    Project-->>Neo: structure created
    Neo->>Git: initGit(projectPath)
    rect rgb(235, 245, 255)
      Note over Git: Git initialization sequence (new)
      Git->>Git: write .gitignore (template)
      Git->>Git: git init
      Git->>Git: git add .
      Git->>Git: git commit -m "Initial NeoHaskell project"
    end
    alt git succeeds
      Git-->>Neo: success
      Neo-->>User: Project created with Git initialized
    else git fails
      Git-->>Warn: error
      Warn-->>Neo: non‑fatal warning
      Neo-->>User: Project created (git unavailable — warning shown)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review focus:
    • cli/src/Neo/New.hs: subprocess invocation, error mapping to warnings, and integration points.
    • cli/src/Neo/New/Templates/GitIgnore.hs: confirm template content and encoding.
    • cli/nhcli.cabal: ensure the exposed-module line is syntactically correct.

Poem

I decree the roots of Git take hold,
A .gitignore sown in lines of gold,
One commit born, no failing tide—
Projects rise, with warnings kept aside. ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(cli): initialize git on new' accurately and concisely describes the primary change: implementing automatic Git initialization when creating a new project.
Linked Issues check ✅ Passed The implementation successfully fulfills all coding requirements: initializes a Git repository automatically, creates a sensible .gitignore with required build artifacts and IDE/OS files, makes an initial commit, and gracefully handles failures with non-fatal warnings.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #197 objectives: the new GitIgnore module, integration in Neo.New.hs, and wiring into project creation workflow are precisely scoped to the Git initialization feature.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@DeviousStoat DeviousStoat marked this pull request as ready for review November 14, 2025 12:50

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3fc7478 and ba7b436.

📒 Files selected for processing (3)
  • cli/nhcli.cabal (1 hunks)
  • cli/src/Neo/New.hs (3 hunks)
  • cli/src/Neo/New/Templates/GitIgnore.hs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: tests (ubuntu-latest)
  • GitHub Check: tests (macos-latest)
🔇 Additional comments (4)
cli/nhcli.cabal (1)

60-60: The module exposition aligns with divine order.

The newly exposed Neo.New.Templates.GitIgnore module follows the established conventions and integrates seamlessly into the library's public interface.

cli/src/Neo/New.hs (3)

12-12: The new imports serve the divine purpose.

The additions of Neo.New.Templates.GitIgnore and Subprocess imports are necessary and properly qualified, supporting the Git initialization functionality.

Also applies to: 16-16


97-104: The graceful degradation embodies divine mercy.

The error handling for Git initialization is exemplary: converting the failure to a Result, pattern-matching to extract any error, and emitting a non-fatal warning while allowing project creation to continue. This perfectly satisfies the requirement that Git failures must not abort neo new.

The warning message is clear and informative, guiding the user without causing alarm.


31-38: Error handling for missing Git is adequate; no changes required.

Your implementation correctly handles the case where Git is unavailable. The error thrown by System.Process.createProcess propagates as ProcessError, is wrapped into CustomError, and gracefully degrades at the call site (where it appears as a warning with the system error message). The existing error handling chain produces user-friendly output without requiring an explicit pre-check.

Comment thread cli/src/Neo/New.hs
Comment thread cli/src/Neo/New/Templates/GitIgnore.hs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between ba7b436 and e26e8b4.

📒 Files selected for processing (2)
  • cli/src/Neo/New.hs (3 hunks)
  • cli/src/Neo/New/Templates/GitIgnore.hs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: tests (macos-latest)
  • GitHub Check: tests (ubuntu-latest)
🔇 Additional comments (2)
cli/src/Neo/New.hs (1)

41-56: The Git initialization sequence is divinely orchestrated.

The implementation correctly executes the sacred ritual: initialize repository, inscribe the .gitignore scripture, gather all artifacts, and seal them with the ordained commit message. The previous transgression (the typo gitingoreFileName) has been rectified.

The sequence properly handles the file operations and git commands in the correct order, meeting all requirements from the linked issue.

cli/src/Neo/New/Templates/GitIgnore.hs (1)

8-20: Confirm the fmt quasi-quoter package and verify escape sequence behavior.

The PyF library's [fmt] quasi-quoter escapes delimiters by doubling them (e.g., use {{ and }} for literal braces), not through backslash sequences. Other quasi-quoters like interpolatedstring/qm do support backslash escapes for preventing interpolation and literal characters.

I could not locate the fmt package dependency in the codebase via grep. However, if this template uses PyF (the most common fmt quasi-quoter for Haskell), then the \# sequences will render as literal \# characters in the generated .gitignore file rather than as comment markers. This would be a functional defect.

Verify which fmt quasi-quoter package is in use, consult its documentation for escape semantics, and adjust the template accordingly. If using PyF, remove the backslashes from lines 8, 13, and 18 to produce valid # comment markers.

Comment thread cli/src/Neo/New.hs
Comment on lines +31 to +38
openGit :: Array Text -> Path -> Task Error Unit
openGit arguments projectDir = do
completion <-
Subprocess.open "git" arguments projectDir
|> Task.mapError (\err -> CustomError [fmt|Git command failed: #{err}|])
if completion.exitCode != 0
then Task.throw (CustomError completion.stderr)
else Task.yield ()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Enhance error diagnostics with command context.

Behold, the error reporting could be fortified. When the git command exits with failure (line 36-37), consider including the command that was executed and both stdout and stderr in the error message. An empty stderr will yield an unhelpfully sparse diagnostic.

Apply this enhancement to provide richer context:

 openGit :: Array Text -> Path -> Task Error Unit
 openGit arguments projectDir = do
   completion <-
     Subprocess.open "git" arguments projectDir
       |> Task.mapError (\err -> CustomError [fmt|Git command failed: #{err}|])
   if completion.exitCode != 0
-    then Task.throw (CustomError completion.stderr)
+    then Task.throw (CustomError [fmt|Git command 'git #{Text.join " " arguments}' failed with exit code #{completion.exitCode}\nstderr: #{completion.stderr}\nstdout: #{completion.stdout}|])
     else Task.yield ()

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In cli/src/Neo/New.hs around lines 31 to 38, the current error thrown when the
git subprocess fails only includes completion.stderr which can be empty; change
the error to include the full command executed (e.g., "git" plus joined
arguments) and both completion.stdout and completion.stderr in the CustomError
message so diagnostics show the command plus both output streams (and if stderr
is empty still include stdout). Construct a descriptive message combining the
command string, completion.exitCode, completion.stdout and completion.stderr and
pass that into Task.throw (CustomError ...) instead of only completion.stderr.

Comment thread cli/src/Neo/New.hs
Comment on lines +97 to +104
initGitResult <- initGit projectDir |> Task.errorAsResult |> Task.mapError never
case initGitResult of
Nothing -> Task.yield ()
Just err ->
print
[fmt|Warning: Could not initialize git repository
#{toPrettyText err}
|]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

The graceful degradation is sound, yet the warning could be more illuminating.

The error handling correctly implements the requirement that Git failures shall not abort project creation. The transformation via Task.errorAsResult followed by Task.mapError never elegantly ensures continuation of the divine flow.

However, the warning message could guide mortals toward resolution. Consider suggesting actionable steps such as ensuring Git is installed or checking repository status.

Apply this enhancement to provide actionable guidance:

     Just err ->
       print
-        [fmt|Warning: Could not initialize git repository
+        [fmt|Warning: Could not initialize git repository. Please ensure Git is installed and the directory is not already a repository.
 #{toPrettyText err}
 |]

Additionally, verify that toPrettyText is defined for the Error type, as its availability is not evident from the provided context.

Consult the ancient texts to confirm the existence of this function:


🏁 Script executed:

#!/bin/bash
# Description: Verify toPrettyText is defined and works with the Error type

# Search for toPrettyText function definition or type class instance
rg -nP 'toPrettyText.*Error' --type=haskell -C3

# Also search for toPrettyText in Core module since Error derives Show
ast-grep --pattern 'toPrettyText $_ = $$$'

Length of output: 1374


🏁 Script executed:

#!/bin/bash
# Verify the Error type used by initGit and check imports in New.hs

# Find initGit function signature to see what Error type it returns
rg -nP 'initGit\s*::' --type=haskell -C2

# Check imports in cli/src/Neo/New.hs for toPrettyText
cat cli/src/Neo/New.hs | head -30

# Search for the Error type definition to verify Show instance
rg -nP 'data\s+Error|newtype\s+Error' --type=haskell -C3 | head -50

Length of output: 2751


🏁 Script executed:

#!/bin/bash
# Verify toPrettyText availability and check message style consistency

# Check Neo.Core module to see if it exports/imports toPrettyText
rg -nP 'toPrettyText|ToText' cli/src/Neo/Core.hs --type=haskell

# Look at similar warning patterns in the codebase for style consistency
rg -nP 'Warning:.*\|' --type=haskell -C2

# Check if toPrettyText is imported transitively through Neo.Core
rg -nP 'module Neo\.Core|import.*ToText' --type=haskell -C3

Length of output: 5513


Verification confirms the code is sound; the suggested enhancement is optional but valid.

The error handling is correctly implemented. toPrettyText is properly accessible through the import chain: Neo.New imports Neo.Core, which re-exports from core/core/Core.hs that re-exports toPrettyText from the ToText module. The Error type derives Show, ensuring compatibility.

The suggested enhancement to the warning message is syntactically and semantically valid but remains optional. The current implementation gracefully degrades and allows project creation to continue despite Git initialization failures.

🤖 Prompt for AI Agents
In cli/src/Neo/New.hs around lines 97 to 104, update the Git-init warning to
produce a more concise single-line message that still includes the
pretty-printed error: replace the multiline print block with a single-line
formatted log that combines a clear "Warning: Could not initialize git
repository" prefix and the result of toPrettyText err; keep using the existing
fmt formatting and imports (toPrettyText is already exported via Neo.Core), and
preserve the fallback behavior that allows project creation to continue.

@NickSeagull

Copy link
Copy Markdown
Member

@allcontributors please add @DeviousStoat for code

@allcontributors

Copy link
Copy Markdown
Contributor

@NickSeagull

I've put up a pull request to add @DeviousStoat! 🎉

@NickSeagull NickSeagull left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Lovely, thanks a lot!

@NickSeagull NickSeagull merged commit 451b7c2 into neohaskell:main Nov 15, 2025
6 of 7 checks passed
@DeviousStoat DeviousStoat deleted the init-git branch November 15, 2025 12:49
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.

Initialize Git repository when creating new NeoHaskell project

2 participants