Skip to content

Commit 0cf0f20

Browse files
authored
feat: implement git vcs (#53)
- implement git vcs
1 parent 3d5782d commit 0cf0f20

File tree

17 files changed

+1168
-163
lines changed

17 files changed

+1168
-163
lines changed

.amazonq/rules/dev-workflow.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,45 @@ Before performing ANY coding task, **read `.dev/00-README.md`** for complete pro
2020
- Use `zerv::error::ZervError` for all custom errors
2121
- Implement proper error propagation with `?` operator
2222
- Include context in error messages for debugging
23+
- Use `io::Error::other()` instead of `io::Error::new(io::ErrorKind::Other, ...)`
24+
25+
**Error Standard Violations Check:**
26+
27+
When user mentions:
28+
29+
- "check error standards"
30+
- "find error violations"
31+
- "audit error handling"
32+
- "error compliance check"
33+
34+
→ Search codebase for violations:
35+
36+
- `io::Error::new(io::ErrorKind::Other` patterns
37+
- Missing `ZervError` usage in custom error cases
38+
- Direct `unwrap()` or `expect()` in production code
39+
- Error messages without context
40+
41+
## Code Reuse Standards
42+
43+
**ALWAYS check existing utilities first:**
44+
45+
- Check `src/test_utils/` before creating new test utilities
46+
- Reuse `TestDir`, `DockerGit`, and other existing infrastructure
47+
- Avoid duplicating code across different files
48+
- Look for existing helper functions before implementing new ones
49+
50+
**Code Reuse Violations Check:**
51+
52+
When user mentions:
53+
54+
- "check code reuse"
55+
- "find duplicated code"
56+
- "audit code duplication"
57+
- "redundant code check"
58+
59+
→ Search codebase for violations:
60+
61+
- Duplicated test setup patterns
62+
- Reimplemented utility functions
63+
- Similar helper functions across files
64+
- Unused existing utilities in `src/test_utils/`
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Testing Standards
2+
3+
## Docker Isolation for VCS Tests
4+
5+
**MANDATORY: Use Docker for VCS operations that modify state**
6+
7+
- Use Docker for all Git/VCS tests to avoid interfering with local machine state
8+
- Isolate test environment completely from host git config and repositories
9+
- Use `DockerGit` utility from `src/test_utils/git.rs` for git operations in tests
10+
11+
## Race Condition Prevention
12+
13+
**Atomic Operations Required:**
14+
15+
- Use single Docker commands with shell scripts instead of multiple separate commands
16+
- Combine git operations like `git init && git add . && git commit` in one Docker call
17+
- Avoid multi-step Docker operations that can cause filesystem race conditions
18+
19+
**Flaky Test Detection:**
20+
21+
When user mentions:
22+
23+
- "check for flaky tests"
24+
- "test stability"
25+
- "race condition"
26+
- "sometimes pass sometimes fail"
27+
28+
→ Run `make test` in a loop (default 10 iterations) to detect instability
29+
30+
## Test Stability Requirements
31+
32+
**Before committing:**
33+
34+
- All tests must pass consistently
35+
- Use `make test` multiple times to verify stability
36+
- Fix any intermittent failures before proceeding
37+
- Document any Docker or environment dependencies

.dev/02-docker-git-testing-bug.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Docker Git Testing Bug - Complete Fix Guide
2+
3+
## Bug Symptoms
4+
5+
- Tests pass locally but fail in GitHub Actions CI
6+
- Error: `fatal: not in a git directory`
7+
- Multiple git-related test failures (typically 11+ tests)
8+
- Docker commands work locally but not in CI environment
9+
10+
## Root Cause
11+
12+
**Docker Image Entrypoint Issue**: `alpine/git:latest` has `git` as the default entrypoint, not `sh`. This means:
13+
14+
- Local Docker might behave differently than CI
15+
- Commands like `docker run alpine/git:latest "git init"` try to execute `git "git init"` instead of `sh -c "git init"`
16+
17+
## Complete Fix Pattern
18+
19+
### 1. Use Correct Docker Image and Entrypoint
20+
21+
```rust
22+
// WRONG - Will fail in CI
23+
let output = Command::new("docker")
24+
.args(["run", "--rm", "-v", &mount, "alpine/git:latest", "git", "init"])
25+
.output()?;
26+
27+
// CORRECT - Works everywhere
28+
let output = Command::new("docker")
29+
.args([
30+
"run", "--rm", "-v", &mount,
31+
"--entrypoint", "sh",
32+
"alpine/git:latest",
33+
"-c", "git init"
34+
])
35+
.output()?;
36+
```
37+
38+
### 2. Git Commands After Init Need --git-dir Flag
39+
40+
```rust
41+
// WRONG - Will fail after git init
42+
let output = Command::new("docker")
43+
.args([
44+
"run", "--rm", "-v", &mount,
45+
"--entrypoint", "sh",
46+
"alpine/git:latest",
47+
"-c", "git add ."
48+
])
49+
.output()?;
50+
51+
// CORRECT - Include --git-dir=.git
52+
let output = Command::new("docker")
53+
.args([
54+
"run", "--rm", "-v", &mount,
55+
"--entrypoint", "sh",
56+
"alpine/git:latest",
57+
"-c", "git --git-dir=.git add ."
58+
])
59+
.output()?;
60+
```
61+
62+
### 3. Initial Commit Required for Tags
63+
64+
```rust
65+
// Git tags need HEAD reference, so init_repo must create initial commit
66+
pub fn init_repo(&self) -> Result<(), ZervError> {
67+
// 1. Git init
68+
self.run_git_command("git init")?;
69+
70+
// 2. Configure user (required for commits)
71+
self.run_git_command("git config user.name 'Test User'")?;
72+
self.run_git_command("git config user.email '[email protected]'")?;
73+
74+
// 3. Create initial commit (REQUIRED for tags)
75+
self.run_git_command("echo 'initial' > README.md")?;
76+
self.run_git_command("git --git-dir=.git add .")?;
77+
self.run_git_command("git --git-dir=.git commit -m 'Initial commit'")?;
78+
79+
Ok(())
80+
}
81+
```
82+
83+
## Complete Working Pattern
84+
85+
```rust
86+
fn run_git_command(&self, command: &str) -> Result<String, ZervError> {
87+
let mount = format!("{}:/repo", self.temp_dir.path().display());
88+
89+
let output = Command::new("docker")
90+
.args([
91+
"run", "--rm", "-v", &mount,
92+
"-w", "/repo",
93+
"--entrypoint", "sh",
94+
"alpine/git:latest",
95+
"-c", command
96+
])
97+
.output()
98+
.map_err(|e| ZervError::Io(io::Error::other(format!("Docker command failed: {}", e))))?;
99+
100+
if !output.status.success() {
101+
let stderr = String::from_utf8_lossy(&output.stderr);
102+
return Err(ZervError::Io(io::Error::other(format!(
103+
"Git command failed: {}\nCommand: {}", stderr, command
104+
))));
105+
}
106+
107+
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
108+
}
109+
```
110+
111+
## Debugging Steps
112+
113+
### 1. Test Docker Locally First
114+
115+
```bash
116+
# Test the exact Docker command
117+
docker run --rm -v $(pwd):/repo -w /repo --entrypoint sh alpine/git:latest -c "git init"
118+
```
119+
120+
### 2. Check CI Logs for Exact Error
121+
122+
- Look for "fatal: not in a git directory"
123+
- Check if Docker commands are being executed correctly
124+
- Verify mount paths and working directories
125+
126+
### 3. Verify Test Isolation
127+
128+
```bash
129+
# Run tests multiple times to check for race conditions
130+
make test
131+
make test
132+
make test
133+
```
134+
135+
## Prevention Checklist
136+
137+
- [ ] Use `--entrypoint sh` with `alpine/git:latest`
138+
- [ ] Include `--git-dir=.git` for git commands after init
139+
- [ ] Create initial commit in `init_repo()`
140+
- [ ] Test Docker commands locally before CI
141+
- [ ] Verify all git operations work in isolated containers
142+
- [ ] Check that temp directories are properly mounted
143+
144+
## Files to Update When Fixing
145+
146+
1. `src/test_utils/git.rs` - Docker git utility functions
147+
2. `src/vcs/git.rs` - Git VCS implementation test helpers
148+
3. Any other files using Docker git commands
149+
150+
## Testing Verification
151+
152+
```bash
153+
# Local test
154+
make test
155+
156+
# Check specific git tests
157+
cargo test git --include-ignored
158+
159+
# Verify CI will pass
160+
git push # Check GitHub Actions
161+
```
162+
163+
This bug has occurred multiple times - always refer to this guide when Docker git tests fail in CI but pass locally.

.dev/02-vcs-implementation.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# VCS Implementation Session Summary
2+
3+
## Overview
4+
5+
Implemented complete VCS (Version Control System) module for zerv project with Git integration, Docker-based testing infrastructure, and unified test utilities.
6+
7+
## Key Accomplishments
8+
9+
### 1. VCS Module Implementation
10+
11+
- **Core VCS trait** (`src/vcs/mod.rs`) - Defines interface for VCS operations
12+
- **VcsData structure** - Repository metadata container with commit hashes, timestamps, branch info, distance, and dirty state
13+
- **Git implementation** (`src/vcs/git.rs`) - Complete Git VCS with all required operations
14+
- **Utility functions** - VCS detection and root finding capabilities
15+
16+
### 2. Docker-Based Git Testing
17+
18+
- **DockerGit utility** (`src/test_utils/git.rs`) - Isolated Git operations using alpine/git Docker container
19+
- **Atomic operations** - Single Docker commands to prevent race conditions
20+
- **Race condition resolution** - Fixed flaky tests by implementing atomic Git operations
21+
- **Test stability** - Achieved 100% success rate across multiple test runs
22+
23+
### 3. Test Utilities Unification
24+
25+
- **Unified TestDir** (`src/test_utils/dir.rs`) - Single test directory utility using `tempfile::TempDir` internally
26+
- **Feature gating** - `test-utils` feature for making utilities available to integration tests
27+
- **Consistent API** - Standardized interface across all test utilities
28+
29+
### 4. Code Quality Improvements
30+
31+
- **Docker command refactoring** - Eliminated duplication with `run_docker_command` helper method
32+
- **Readable formatting** - Improved long command lines with array-based formatting
33+
- **Error handling** - Consistent error messages and proper error propagation
34+
- **Coverage improvement** - Increased from 97.36% to 97.39%
35+
36+
## Technical Details
37+
38+
### VCS Architecture
39+
40+
```rust
41+
pub trait Vcs {
42+
fn get_vcs_data(&self) -> Result<VcsData>;
43+
fn is_available(&self, path: &Path) -> bool;
44+
}
45+
46+
pub struct VcsData {
47+
pub commit_hash: String,
48+
pub commit_hash_short: String,
49+
pub commit_timestamp: i64,
50+
pub is_dirty: bool,
51+
pub current_branch: Option<String>,
52+
pub tag_version: Option<String>,
53+
pub tag_timestamp: Option<i64>,
54+
pub distance: u64,
55+
}
56+
```
57+
58+
### Git Implementation Features
59+
60+
- **Repository detection** - Finds `.git` directory or VCS root
61+
- **Commit information** - Full and short hashes, timestamps
62+
- **Branch detection** - Current branch with detached HEAD handling
63+
- **Tag operations** - Latest tag detection with distance calculation
64+
- **Working tree status** - Dirty state detection
65+
- **Shallow clone warning** - Alerts for inaccurate distance calculations
66+
67+
### Docker Testing Strategy
68+
69+
```rust
70+
fn run_docker_command(&self, test_dir: &TestDir, script: &str) -> io::Result<String> {
71+
Command::new("docker")
72+
.args([
73+
"run", "--rm", "--entrypoint", "sh", "-v",
74+
&format!("{}:/workspace", test_dir.path().display()),
75+
"-w", "/workspace", "alpine/git:latest", "-c", script,
76+
])
77+
.output()
78+
}
79+
```
80+
81+
### Test Infrastructure
82+
83+
- **Atomic Git setup** - Single Docker commands for repo initialization
84+
- **Race condition prevention** - Eliminated multi-step Docker operations
85+
- **Consistent test environment** - Isolated Git operations per test
86+
- **Feature-gated utilities** - Available for both unit and integration tests
87+
88+
## Files Modified/Created
89+
90+
### Core Implementation
91+
92+
- `src/vcs/mod.rs` - VCS trait and utilities
93+
- `src/vcs/git.rs` - Git VCS implementation
94+
- `src/lib.rs` - Module exports and feature gating
95+
96+
### Test Infrastructure
97+
98+
- `src/test_utils/mod.rs` - Unified test utilities module
99+
- `src/test_utils/dir.rs` - TestDir implementation
100+
- `src/test_utils/git.rs` - DockerGit implementation
101+
102+
### Configuration
103+
104+
- `Cargo.toml` - Added `tempfile` dependency with `test-utils` feature
105+
- `Makefile` - Updated test command to include feature flag
106+
107+
## Key Insights
108+
109+
### Race Condition Resolution
110+
111+
- **Root cause**: Multiple Docker container executions caused filesystem state inconsistencies
112+
- **Solution**: Atomic operations using single Docker commands with shell scripts
113+
- **Result**: 100% test stability across 20 consecutive runs
114+
115+
### Code Refactoring Benefits
116+
117+
- **Eliminated ~40 lines** of duplicated Docker setup code
118+
- **Centralized error handling** for Docker operations
119+
- **Improved maintainability** with single source of truth for Docker commands
120+
- **Better readability** with structured command formatting
121+
122+
### Testing Strategy
123+
124+
- **Docker isolation** prevents local Git configuration interference
125+
- **Atomic operations** ensure consistent test state
126+
- **Feature gating** allows utilities in both unit and integration tests
127+
- **Comprehensive coverage** of all Git operations and edge cases
128+
129+
## Test Results
130+
131+
- **All tests passing**: 1079 tests, 0 failures
132+
- **Coverage**: 97.39% (improved from 97.36%)
133+
- **Stability**: 100% success rate over multiple test runs
134+
- **Performance**: Consistent 10-11 second test execution time
135+
136+
## Next Steps
137+
138+
The VCS implementation is complete and stable. Future enhancements could include:
139+
140+
1. **Additional VCS support** - Mercurial, SVN implementations
141+
2. **Performance optimization** - Batched Git commands for large repositories
142+
3. **Advanced Git features** - Submodule support, worktree handling
143+
4. **Configuration options** - Custom tag patterns, branch filtering
144+
145+
## Session Outcome
146+
147+
Successfully implemented a robust, well-tested VCS module that provides comprehensive Git integration for the zerv dynamic versioning system. The implementation includes proper error handling, race condition prevention, and maintains high code quality standards.

0 commit comments

Comments
 (0)