Skip to content

Step 2: Process spawning — the I/O foundation#2

Open
OctavianTocan wants to merge 2 commits intomainfrom
rust-mentor/step-2-process-spawning
Open

Step 2: Process spawning — the I/O foundation#2
OctavianTocan wants to merge 2 commits intomainfrom
rust-mentor/step-2-process-spawning

Conversation

@OctavianTocan
Copy link
Copy Markdown
Owner

@OctavianTocan OctavianTocan commented Apr 24, 2026

Learning step — doc only. Read lessons/02-process-spawning.md, implement the task in src/process.rs, make the tests pass.

Rust concepts: std::process::Command, Result<T,E>, the ? operator, String vs &str
Source: src/core/process.ts (79 lines)
What you'll build: The foundational I/O module that all git/shell operations use

When tests pass, merge this PR.

Summary by Sourcery

Documentation:

  • Introduce a new lesson explaining Rust process spawning, error handling with Result and ?, and the design of the foundational I/O module.

Copilot AI review requested due to automatic review settings April 24, 2026 15:32
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 24, 2026

Warning

Rate limit exceeded

@OctavianTocan has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 40 minutes and 46 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 40 minutes and 46 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fa3568c1-8c3b-442f-9478-56afe9748f62

📥 Commits

Reviewing files that changed from the base of the PR and between 76e3b7a and 8c423db.

📒 Files selected for processing (1)
  • lessons/02-process-spawning.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rust-mentor/step-2-process-spawning

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.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 24, 2026

Reviewer's Guide

Introduces the foundational process-spawning module in Rust, with options and result types for external commands, plus documentation for the learning step and wiring the module into main.

Sequence diagram for run_process and run_shell invocation flow

sequenceDiagram
    actor CLIUser
    participant Main
    participant ProcessModule
    participant OSProcess

    CLIUser->>Main: execute wt-cli
    Main->>ProcessModule: run_process("git", ["status", "--porcelain"], &options)
    ProcessModule->>OSProcess: Command::new("git").args(args).output()
    alt process_start_error
        OSProcess-->>ProcessModule: Err(io::Error)
        ProcessModule-->>Main: Err(String)
        Main-->>CLIUser: print error and exit
    else process_started
        OSProcess-->>ProcessModule: Ok(Output)
        ProcessModule->>ProcessModule: build ProcessResult
        alt non_zero_exit_and_not_allowed
            ProcessModule->>ProcessModule: format_failure(command, args, &result)
            ProcessModule-->>Main: Err(String)
            Main-->>CLIUser: print formatted failure
        else success_or_allowed_failure
            ProcessModule-->>Main: Ok(ProcessResult)
            Main-->>CLIUser: print stdout / continue
        end
    end

    CLIUser->>Main: execute shell command
    Main->>ProcessModule: run_shell("echo hello", &options)
    ProcessModule->>OSProcess: Command::new("sh").arg("-c").arg(command).output()
    OSProcess-->>ProcessModule: Ok(Output)
    ProcessModule-->>Main: Ok(ProcessResult)
    Main-->>CLIUser: print stdout
Loading

Updated class diagram for the new process module types

classDiagram
    class ProcessOptions {
        +Option~String~ cwd
        +bool allow_failure
        +Option~Vec~env
        +new() ProcessOptions
        +default() ProcessOptions
    }

    class ProcessResult {
        +String stdout
        +String stderr
        +i32 status
    }

    class ProcessModule {
        +run_process(command: &str, args: &[&str], options: &ProcessOptions) Result~ProcessResult, String~
        +run_shell(command: &str, options: &ProcessOptions) Result~ProcessResult, String~
        -format_failure(command: &str, args: &[&str], result: &ProcessResult) String
    }

    ProcessModule --> ProcessOptions : uses
    ProcessModule --> ProcessResult : returns
    ProcessOptions ..|> ProcessOptions : Default
Loading

File-Level Changes

Change Details Files
Add a process-spawning abstraction that wraps std::process::Command into run_process and run_shell with structured options and results.
  • Define ProcessOptions with cwd, allow_failure, and optional env and implement Default.
  • Define ProcessResult carrying stdout, stderr, and numeric exit status.
  • Implement run_process to execute commands with arguments, optional cwd/env, capturing output and mapping startup/exit failures into String errors, respecting allow_failure.
  • Implement run_shell to execute string commands via sh -c with the same error and option handling.
  • Add format_failure helper to build informative error messages including command, args, and process output.
  • Add unit tests covering success, cwd handling, failure vs allow_failure, shell execution, and Default semantics for ProcessOptions.
src/process.rs
Document the learning step and architecture of the process-spawning layer for the Rust rewrite.
  • Describe the architecture role of the process module and its relation to the original wt-cli TypeScript implementation.
  • Explain key Rust concepts used in this step: std::process::Command, Result and the ? operator, and String vs &str.
  • Specify the required API for ProcessOptions, ProcessResult, run_process, run_shell, and format_failure, plus the test skeleton and main module wiring.
lessons/02-process-spawning.md
src/main.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="lessons/02-process-spawning.md" line_range="43" />
<code_context>
+
+`Command::new("name")` creates a command builder. You chain methods to configure it (args, working directory, environment). `.output()` runs it and captures stdout/stderr. `.status()` runs it and returns just the exit code.
+
+**The key difference:** In Node, spawnSync returns synchronously. In Rust, `.output()` and `.status()` are also synchronous (they block the thread). If you need async, that's `.spawn()` + tokio — but we don't need that here. wt-cli is a CLI tool, blocking is fine.
+
+**Common gotcha:** `.output()` returns `Result<Output, io::Error>`. You must handle the outer Result (did the process even start?) separately from the exit status (did the process succeed?). Two layers of "can go wrong."
</code_context>
<issue_to_address>
**nitpick (typo):** Consider capitalizing "Tokio" to match the usual project name capitalization.

Here it’s referring to the Tokio async runtime, which is conventionally capitalized in Rust documentation. Matching that convention will keep the docs consistent with the broader ecosystem.

```suggestion
**The key difference:** In Node, spawnSync returns synchronously. In Rust, `.output()` and `.status()` are also synchronous (they block the thread). If you need async, that's `.spawn()` + Tokio — but we don't need that here. wt-cli is a CLI tool, blocking is fine.
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


`Command::new("name")` creates a command builder. You chain methods to configure it (args, working directory, environment). `.output()` runs it and captures stdout/stderr. `.status()` runs it and returns just the exit code.

**The key difference:** In Node, spawnSync returns synchronously. In Rust, `.output()` and `.status()` are also synchronous (they block the thread). If you need async, that's `.spawn()` + tokio — but we don't need that here. wt-cli is a CLI tool, blocking is fine.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nitpick (typo): Consider capitalizing "Tokio" to match the usual project name capitalization.

Here it’s referring to the Tokio async runtime, which is conventionally capitalized in Rust documentation. Matching that convention will keep the docs consistent with the broader ecosystem.

Suggested change
**The key difference:** In Node, spawnSync returns synchronously. In Rust, `.output()` and `.status()` are also synchronous (they block the thread). If you need async, that's `.spawn()` + tokio — but we don't need that here. wt-cli is a CLI tool, blocking is fine.
**The key difference:** In Node, spawnSync returns synchronously. In Rust, `.output()` and `.status()` are also synchronous (they block the thread). If you need async, that's `.spawn()` + Tokio — but we don't need that here. wt-cli is a CLI tool, blocking is fine.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds the Step 2 lesson (“Process Spawning — the I/O foundation”) describing how to implement the foundational process execution layer in the Rust rewrite.

Changes:

  • Introduces a new lesson markdown for process spawning, error handling with Result, and std::process::Command.
  • Specifies the intended API (ProcessOptions, ProcessResult, run_process, run_shell) and a suggested test skeleton.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


Update `src/main.rs` to include the module:
```rust
mod types;
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

The snippet suggests adding mod types; in src/main.rs, but this repository currently doesn't have src/types.rs. Following these instructions as-is will cause a compile error. Either remove mod types; from the step-2 instructions or explicitly note that step 1 must be completed (and types.rs added) before making this change.

Suggested change
mod types;

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +82
Define a `ProcessOptions` struct:
- `cwd: Option<String>` — working directory (None = current dir)
- `allow_failure: bool` — if true, don't error on non-zero exit
- `env: Option<Vec<(String, String)>>` — extra environment variables

Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

ProcessOptions defines env, but the task steps for run_process/run_shell don't mention applying it to the Command builder. Add an explicit instruction to call .envs(...) / .env(...) when options.env is Some, otherwise implementers may ignore this option.

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +77
## Your Task

**File:** `src/process.rs` (create this file)

Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

PR description says to implement src/process.rs, update src/main.rs, and make tests pass, but this PR currently only adds the lesson markdown (no Rust code changes in src/). If this PR is meant to be doc-only, the description should be updated; otherwise the missing code/test changes need to be included before merge.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9dce02b9dc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +108 to +109
mod types;
mod process;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove mod types; from step instructions

The lesson tells learners to add mod types; in src/main.rs, but in this repo state there is no src/types.rs, so following the snippet verbatim triggers Rust module resolution error E0583 and prevents cargo test from running for the process-spawning task. Either omit that line in this step or explicitly state that Step 1 (creating types.rs) is a required prerequisite.

Useful? React with 👍 / 👎.

Comment on lines +79 to +81
- `cwd: Option<String>` — working directory (None = current dir)
- `allow_failure: bool` — if true, don't error on non-zero exit
- `env: Option<Vec<(String, String)>>` — extra environment variables
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Propagate env options into spawned commands

The task defines ProcessOptions.env as “extra environment variables,” but the implementation bullets for run_process and run_shell never require applying them to std::process::Command. As written, a learner can satisfy all instructions while silently ignoring caller-provided environment overrides, which makes the API misleading and breaks scenarios that depend on per-command env injection.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 274aee630d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

let output = cmd.output().map_err(|e| e.to_string())?;
let status = output.status.code().unwrap_or(0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle signal-terminated exits as failures

The suggested implementation let status = output.status.code().unwrap_or(0); converts signal-terminated children (code() == None) into exit status 0, and the next check (status != 0) then treats those runs as success when allow_failure is false. In practice, a subprocess killed by SIGTERM/SIGKILL would be reported as Ok(...), which can let later steps proceed on a failed command; please map None to a non-zero status (or read the signal) so these cases are surfaced as errors.

Useful? React with 👍 / 👎.

Rust concepts: std::process::Command, Result<T,E>, the ? operator, String vs &str
Source files: src/core/process.ts (79 lines)

This PR is documentation only — no Rust code to review.
Read the lesson, implement the task, make the tests pass.
Added the full original process.ts and a line-by-line translation
walkthrough explaining spawnSync→Command, throw→Result, shell:true→sh -c,
and Default trait vs empty object defaults.
@OctavianTocan OctavianTocan force-pushed the rust-mentor/step-2-process-spawning branch from 274aee6 to 8c423db Compare April 24, 2026 23:17
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8c423db9c0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- Otherwise return `Ok(ProcessResult { stdout, stderr, status })`

**`pub fn run_shell(command: &str, options: &ProcessOptions) -> Result<ProcessResult, String>`**
- Same as run_process but uses `Command::new("sh").arg("-c").arg(command)` to run through a shell
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use platform shell semantics for run_shell

This step requires Command::new("sh").arg("-c"), which only works on Unix-like systems and diverges from the source behavior (shell: true) that uses the OS default shell. On Windows environments where sh is absent, a learner can follow the instructions exactly and still get runtime Err(...) for shell commands, breaking the foundational process API for all later steps. Either mark the lesson as Unix-only or teach a cfg(target_os) split (for example cmd /C on Windows).

Useful? React with 👍 / 👎.

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.

2 participants