@eldrforge/kodrdriv 1.2.24 → 1.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MONOREPO-PUBLISH-IMPROVEMENTS.md +281 -0
- package/SUBMODULE-LOCK-FIX.md +132 -0
- package/dist/commands/tree.js +151 -45
- package/dist/commands/tree.js.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/execution/DynamicTaskPool.js +112 -16
- package/dist/execution/DynamicTaskPool.js.map +1 -1
- package/dist/execution/RecoveryManager.js +6 -2
- package/dist/execution/RecoveryManager.js.map +1 -1
- package/dist/execution/TreeExecutionAdapter.js +45 -10
- package/dist/execution/TreeExecutionAdapter.js.map +1 -1
- package/dist/ui/ProgressFormatter.js +22 -2
- package/dist/ui/ProgressFormatter.js.map +1 -1
- package/dist/util/fileLock.js +40 -3
- package/dist/util/fileLock.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Kodrdriv Monorepo Publish Workflow Improvements
|
|
2
|
+
|
|
3
|
+
## Implementation Summary
|
|
4
|
+
|
|
5
|
+
This document summarizes the improvements made to the `kodrdriv tree publish --parallel` workflow based on real-world usage feedback with the Fjell monorepo (16 packages).
|
|
6
|
+
|
|
7
|
+
## Completed Improvements
|
|
8
|
+
|
|
9
|
+
### 1. ✅ Fixed Recovery Mode to Actually Continue Execution (#2 - High Priority)
|
|
10
|
+
|
|
11
|
+
**Problem:** When using `--continue --mark-completed`, the system would apply recovery options but then exit immediately without continuing execution.
|
|
12
|
+
|
|
13
|
+
**Root Cause:** The sequential execution context loading was overwriting the `runConfig`, removing the `--parallel` flag, causing the system to skip parallel execution entirely.
|
|
14
|
+
|
|
15
|
+
**Solution:**
|
|
16
|
+
- Modified `src/commands/tree.ts` to detect parallel mode and skip sequential context loading
|
|
17
|
+
- Parallel execution now properly continues after recovery options are applied
|
|
18
|
+
- Recovery is now atomic: apply recovery + continue execution in one step
|
|
19
|
+
|
|
20
|
+
**Files Changed:**
|
|
21
|
+
- `src/commands/tree.ts` (lines 1093-1144)
|
|
22
|
+
|
|
23
|
+
### 2. ✅ Git Submodule Support (#3 - High Priority)
|
|
24
|
+
|
|
25
|
+
**Status:** Already implemented and tested in previous work.
|
|
26
|
+
|
|
27
|
+
**Implementation:** The file-based lock mechanism in `src/util/fileLock.ts` already handles both regular repositories and git submodules by:
|
|
28
|
+
- Detecting if `.git` is a file (submodule) vs directory (regular repo)
|
|
29
|
+
- Reading and parsing the `gitdir:` reference for submodules
|
|
30
|
+
- Creating lock files in the actual git directory
|
|
31
|
+
|
|
32
|
+
**Files:**
|
|
33
|
+
- `src/util/fileLock.ts`
|
|
34
|
+
- `tests/fileLock.test.ts` (comprehensive test coverage)
|
|
35
|
+
- `SUBMODULE-LOCK-FIX.md` (documentation)
|
|
36
|
+
|
|
37
|
+
### 3. ✅ Better Status Distinctions (#1/#4 - High Priority)
|
|
38
|
+
|
|
39
|
+
**Problem:** The system reported "Completed successfully" for packages that were skipped due to no code changes, making it impossible to tell what was actually published.
|
|
40
|
+
|
|
41
|
+
**Solution:**
|
|
42
|
+
- Added new `skippedNoChanges` field to `ExecutionState` and `ExecutionResult` types
|
|
43
|
+
- Modified `DynamicTaskPool` to track packages skipped due to no changes separately from those skipped due to failed dependencies
|
|
44
|
+
- Updated progress logger to show distinct icons and messages:
|
|
45
|
+
- ✅ Published (actually executed)
|
|
46
|
+
- ⊘ Skipped (no code changes)
|
|
47
|
+
- ⊘ Skipped (dependency failed)
|
|
48
|
+
- ❌ Failed
|
|
49
|
+
- Enhanced result summary to show detailed breakdown
|
|
50
|
+
|
|
51
|
+
**Files Changed:**
|
|
52
|
+
- `src/types/parallelExecution.ts` - Added `skippedNoChanges` to state and result types
|
|
53
|
+
- `src/execution/DynamicTaskPool.ts` - Track and report skip reasons
|
|
54
|
+
- `src/execution/TreeExecutionAdapter.ts` - Pass through skip status and format results
|
|
55
|
+
- `src/execution/RecoveryManager.ts` - Include skippedNoChanges in validation
|
|
56
|
+
- `src/commands/tree.ts` - Detect and return skip status from executePackage
|
|
57
|
+
|
|
58
|
+
**Example Output:**
|
|
59
|
+
```
|
|
60
|
+
📊 Execution Summary:
|
|
61
|
+
|
|
62
|
+
✅ Published: 3 package(s)
|
|
63
|
+
@fjell/common-config, @fjell/logging, @fjell/docs-template
|
|
64
|
+
|
|
65
|
+
⊘ Skipped (no code changes): 5 package(s)
|
|
66
|
+
@fjell/core, @fjell/http-api, @fjell/registry, @fjell/client-api, @fjell/lib
|
|
67
|
+
|
|
68
|
+
⊘ Skipped (dependency failed): 8 package(s)
|
|
69
|
+
@fjell/cache, @fjell/providers, @fjell/sample-app, ...
|
|
70
|
+
Blocked by: @fjell/core
|
|
71
|
+
|
|
72
|
+
❌ Failed: 0 package(s)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 4. ✅ Show Actual Errors Inline (#9 - High Priority)
|
|
76
|
+
|
|
77
|
+
**Problem:** When packages failed, only generic error messages were shown. The actual error (test failure, build error, merge conflict) was buried in log files.
|
|
78
|
+
|
|
79
|
+
**Solution:**
|
|
80
|
+
- Added `errorDetails` field to `FailedPackageSnapshot` type with structured error information
|
|
81
|
+
- Implemented `extractErrorDetails()` method in `DynamicTaskPool` to parse errors and extract:
|
|
82
|
+
- Error type (test_coverage, build_error, merge_conflict, test_failure, timeout, unknown)
|
|
83
|
+
- Context (specific details about the error)
|
|
84
|
+
- Log file location
|
|
85
|
+
- Suggested fix command
|
|
86
|
+
- Enhanced `ProgressFormatter.createErrorSummary()` to display detailed error information
|
|
87
|
+
|
|
88
|
+
**Files Changed:**
|
|
89
|
+
- `src/types/parallelExecution.ts` - Added errorDetails to FailedPackageSnapshot
|
|
90
|
+
- `src/execution/DynamicTaskPool.ts` - Extract and attach error details
|
|
91
|
+
- `src/ui/ProgressFormatter.ts` - Display detailed error information
|
|
92
|
+
|
|
93
|
+
**Example Output:**
|
|
94
|
+
```
|
|
95
|
+
❌ Failure Summary:
|
|
96
|
+
|
|
97
|
+
@fjell/core:
|
|
98
|
+
Type: Test Coverage
|
|
99
|
+
Details: Lines: 89.5% (threshold: 90%)
|
|
100
|
+
Log: /path/to/core/output/kodrdriv/publish_*.log
|
|
101
|
+
💡 Suggestion: cd /path/to/core && npm test -- --coverage
|
|
102
|
+
Blocked: @fjell/cache, @fjell/providers +6 more
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 5. ✅ Add Dry-Run Mode (#6 - Medium Priority)
|
|
106
|
+
|
|
107
|
+
**Problem:** No way to preview what will happen without actually executing.
|
|
108
|
+
|
|
109
|
+
**Solution:**
|
|
110
|
+
- Added `generateDryRunPreview()` function that analyzes the dependency graph and shows:
|
|
111
|
+
- Build order grouped by dependency level
|
|
112
|
+
- Status for each package (will publish, will skip, etc.)
|
|
113
|
+
- For publish commands, checks git diff to determine if packages have code changes
|
|
114
|
+
- Summary statistics
|
|
115
|
+
- Integrated with parallel execution to show preview before executing
|
|
116
|
+
|
|
117
|
+
**Files Changed:**
|
|
118
|
+
- `src/commands/tree.ts` - Added generateDryRunPreview() and integrated with parallel execution
|
|
119
|
+
|
|
120
|
+
**Example Output:**
|
|
121
|
+
```
|
|
122
|
+
🔍 DRY RUN MODE - No changes will be made
|
|
123
|
+
|
|
124
|
+
Build order determined:
|
|
125
|
+
|
|
126
|
+
Level 1: (1 package)
|
|
127
|
+
@fjell/common-config
|
|
128
|
+
Status: 📝 Has changes (23 files), will publish
|
|
129
|
+
Path: /path/to/common-config
|
|
130
|
+
|
|
131
|
+
Level 2: (1 package)
|
|
132
|
+
@fjell/logging
|
|
133
|
+
Status: ⊘ Only version bump, will skip
|
|
134
|
+
Path: /path/to/logging
|
|
135
|
+
|
|
136
|
+
...
|
|
137
|
+
|
|
138
|
+
Summary:
|
|
139
|
+
Total packages: 16
|
|
140
|
+
Dependency levels: 6
|
|
141
|
+
Command: kodrdriv publish
|
|
142
|
+
Max concurrency: 8
|
|
143
|
+
|
|
144
|
+
To execute for real, run the same command without --dry-run
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Not Yet Implemented (Lower Priority)
|
|
148
|
+
|
|
149
|
+
The following improvements were identified but not implemented in this session:
|
|
150
|
+
|
|
151
|
+
### 5. Progress Indicators for Long-Running Operations
|
|
152
|
+
- Show sub-step progress during PR checks
|
|
153
|
+
- Display which checks are passing/failing
|
|
154
|
+
- Estimate completion time
|
|
155
|
+
|
|
156
|
+
### 7. Better Checkpoint Management
|
|
157
|
+
- Add `kodrdriv tree --status` command
|
|
158
|
+
- Add `kodrdriv tree --reset` command
|
|
159
|
+
- Auto-detect and prompt when checkpoint exists
|
|
160
|
+
|
|
161
|
+
### 8. Fix Concurrency Recommendation Inconsistency
|
|
162
|
+
- Use recommended concurrency by default or explain why not
|
|
163
|
+
|
|
164
|
+
### 10. Interactive Conflict Resolution
|
|
165
|
+
- Offer to auto-resolve common conflicts (package.json versions, lockfiles)
|
|
166
|
+
- Interactive prompts for manual resolution
|
|
167
|
+
|
|
168
|
+
### 11. Smart Dependency Updating
|
|
169
|
+
- Auto-update dependent packages when a package is published
|
|
170
|
+
- `kodrdriv tree update-deps --package "@fjell/core@4.4.72"`
|
|
171
|
+
|
|
172
|
+
### 12. Publish Groups/Profiles
|
|
173
|
+
- Define groups of packages to publish together
|
|
174
|
+
- `kodrdriv tree publish --group core`
|
|
175
|
+
|
|
176
|
+
### 13. Better npm Registry Integration
|
|
177
|
+
- Check npm for latest versions before publishing
|
|
178
|
+
- Warn about version conflicts
|
|
179
|
+
|
|
180
|
+
### 14. Automatic Changelog Generation
|
|
181
|
+
- Generate changelogs based on commits since last release
|
|
182
|
+
- Include in release notes automatically
|
|
183
|
+
|
|
184
|
+
## Testing
|
|
185
|
+
|
|
186
|
+
### Manual Testing Recommended
|
|
187
|
+
|
|
188
|
+
1. **Recovery Mode:**
|
|
189
|
+
```bash
|
|
190
|
+
# Start a publish
|
|
191
|
+
kodrdriv tree publish --parallel
|
|
192
|
+
|
|
193
|
+
# If it fails, mark packages as completed and continue
|
|
194
|
+
kodrdriv tree publish --parallel --continue --mark-completed "pkg1,pkg2"
|
|
195
|
+
|
|
196
|
+
# Verify it actually continues execution (not just exits)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
2. **Status Distinctions:**
|
|
200
|
+
```bash
|
|
201
|
+
# Publish a monorepo where some packages have no changes
|
|
202
|
+
kodrdriv tree publish --parallel
|
|
203
|
+
|
|
204
|
+
# Verify the summary shows:
|
|
205
|
+
# - ✅ Published: X packages
|
|
206
|
+
# - ⊘ Skipped (no changes): Y packages
|
|
207
|
+
# - ⊘ Skipped (dependency failed): Z packages
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
3. **Error Details:**
|
|
211
|
+
```bash
|
|
212
|
+
# Cause a test failure in one package
|
|
213
|
+
# Run publish and verify the error summary shows:
|
|
214
|
+
# - Error type
|
|
215
|
+
# - Specific details
|
|
216
|
+
# - Log file location
|
|
217
|
+
# - Suggested fix
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
4. **Dry Run:**
|
|
221
|
+
```bash
|
|
222
|
+
kodrdriv tree publish --parallel --dry-run
|
|
223
|
+
|
|
224
|
+
# Verify it shows:
|
|
225
|
+
# - Build order by level
|
|
226
|
+
# - Status for each package
|
|
227
|
+
# - Summary statistics
|
|
228
|
+
# - Does not actually execute
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Unit Tests
|
|
232
|
+
|
|
233
|
+
The following test files should be updated to cover the new functionality:
|
|
234
|
+
|
|
235
|
+
- `tests/execution/DynamicTaskPool.test.ts` - Test skippedNoChanges tracking
|
|
236
|
+
- `tests/execution/TreeExecutionAdapter.test.ts` - Test result formatting
|
|
237
|
+
- `tests/execution/RecoveryManager.test.ts` - Test validation with skippedNoChanges
|
|
238
|
+
- `tests/commands/tree.test.ts` - Test dry-run preview and recovery continuation
|
|
239
|
+
|
|
240
|
+
## Migration Notes
|
|
241
|
+
|
|
242
|
+
### Breaking Changes
|
|
243
|
+
|
|
244
|
+
None. All changes are backward compatible.
|
|
245
|
+
|
|
246
|
+
### API Changes
|
|
247
|
+
|
|
248
|
+
- `ExecutionState` now includes `skippedNoChanges: string[]`
|
|
249
|
+
- `ExecutionResult` now includes `skippedNoChanges: string[]`
|
|
250
|
+
- `PackageResult` now includes optional `skippedNoChanges?: boolean`
|
|
251
|
+
- `FailedPackageSnapshot` now includes optional `errorDetails?: { type, context, logFile, suggestion }`
|
|
252
|
+
- `executePackage()` return type now includes optional `skippedNoChanges?: boolean`
|
|
253
|
+
|
|
254
|
+
### Configuration Changes
|
|
255
|
+
|
|
256
|
+
None required. All new features work with existing configurations.
|
|
257
|
+
|
|
258
|
+
## Performance Impact
|
|
259
|
+
|
|
260
|
+
Minimal. The changes primarily affect:
|
|
261
|
+
- Error handling (extracting details from error messages)
|
|
262
|
+
- Status tracking (additional array in state)
|
|
263
|
+
- Dry-run preview (only runs when --dry-run is specified)
|
|
264
|
+
|
|
265
|
+
## Documentation Updates Needed
|
|
266
|
+
|
|
267
|
+
- Update `docs/public/commands/tree.md` with:
|
|
268
|
+
- New status distinctions
|
|
269
|
+
- Dry-run mode usage
|
|
270
|
+
- Enhanced error reporting
|
|
271
|
+
- Recovery mode improvements
|
|
272
|
+
- Update examples to show new output format
|
|
273
|
+
|
|
274
|
+
## Related Issues/PRs
|
|
275
|
+
|
|
276
|
+
This implementation addresses the feedback document "Kodrdriv Monorepo Publish Workflow Improvements" which identified 14 pain points based on real-world usage with the Fjell monorepo.
|
|
277
|
+
|
|
278
|
+
## Contributors
|
|
279
|
+
|
|
280
|
+
Implementation based on detailed feedback from production usage of kodrdriv with a 16-package monorepo.
|
|
281
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Git Submodule Lock File Fix
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
The file-based lock mechanism used to prevent concurrent git operations was failing when used with git submodules. The issue occurred because:
|
|
6
|
+
|
|
7
|
+
1. In regular git repositories, `.git` is a directory
|
|
8
|
+
2. In git submodules, `.git` is a file containing a `gitdir:` reference pointing to the actual git directory
|
|
9
|
+
3. The code assumed `.git` was always a directory and tried to create lock files in `.git/kodrdriv.lock`
|
|
10
|
+
4. This caused `ENOTDIR` errors when operating on submodules
|
|
11
|
+
|
|
12
|
+
## Example Submodule Structure
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
my-submodule/
|
|
16
|
+
├── .git # FILE (not directory) containing: "gitdir: ../.git/modules/my-submodule"
|
|
17
|
+
├── src/
|
|
18
|
+
└── package.json
|
|
19
|
+
|
|
20
|
+
parent-repo/
|
|
21
|
+
└── .git/
|
|
22
|
+
└── modules/
|
|
23
|
+
└── my-submodule/ # Actual git directory for the submodule
|
|
24
|
+
├── HEAD
|
|
25
|
+
├── refs/
|
|
26
|
+
└── objects/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Solution
|
|
30
|
+
|
|
31
|
+
Modified `src/util/fileLock.ts` to handle both regular repositories and submodules:
|
|
32
|
+
|
|
33
|
+
### Key Changes
|
|
34
|
+
|
|
35
|
+
1. **Added `resolveGitDirectory()` method** that:
|
|
36
|
+
- Checks if `.git` is a directory (regular repo) or file (submodule)
|
|
37
|
+
- If it's a file, reads and parses the `gitdir:` reference
|
|
38
|
+
- Resolves the gitdir path (handles both relative and absolute paths)
|
|
39
|
+
- Returns the actual git directory path where locks can be created
|
|
40
|
+
|
|
41
|
+
2. **Updated `getRepositoryLock()` method** to:
|
|
42
|
+
- Use `resolveGitDirectory()` instead of assuming `.git` is a directory
|
|
43
|
+
- Create lock files in the resolved git directory
|
|
44
|
+
- Log the actual lock path for debugging
|
|
45
|
+
|
|
46
|
+
### Code Implementation
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
private resolveGitDirectory(repoPath: string): string {
|
|
50
|
+
const gitPath = path.join(repoPath, '.git');
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const stat = fs.statSync(gitPath);
|
|
54
|
+
|
|
55
|
+
if (stat.isDirectory()) {
|
|
56
|
+
// Regular git repository
|
|
57
|
+
return gitPath;
|
|
58
|
+
} else if (stat.isFile()) {
|
|
59
|
+
// Git submodule - .git is a file with format: gitdir: <path>
|
|
60
|
+
const gitFileContent = fs.readFileSync(gitPath, 'utf-8').trim();
|
|
61
|
+
const match = gitFileContent.match(/^gitdir:\s*(.+)$/);
|
|
62
|
+
|
|
63
|
+
if (match && match[1]) {
|
|
64
|
+
// Resolve the gitdir path (it's relative to the repo path)
|
|
65
|
+
const gitDirPath = path.resolve(repoPath, match[1]);
|
|
66
|
+
this.logger.debug(`Resolved submodule gitdir: ${gitDirPath}`);
|
|
67
|
+
|
|
68
|
+
// Ensure the git directory exists
|
|
69
|
+
if (!fs.existsSync(gitDirPath)) {
|
|
70
|
+
throw new Error(`Submodule git directory does not exist: ${gitDirPath}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return gitDirPath;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
throw new Error(`Invalid .git file format in ${gitPath}: ${gitFileContent}`);
|
|
77
|
+
}
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
// Check if error is from statSync (file doesn't exist)
|
|
80
|
+
if (error.code === 'ENOENT') {
|
|
81
|
+
throw new Error(`No .git directory or file found in ${repoPath}`);
|
|
82
|
+
}
|
|
83
|
+
throw new Error(`Failed to resolve git directory for ${repoPath}: ${error.message}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
throw new Error(`No .git directory or file found in ${repoPath}`);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Testing
|
|
91
|
+
|
|
92
|
+
Comprehensive test suite added in `tests/fileLock.test.ts` covering:
|
|
93
|
+
|
|
94
|
+
1. **Basic lock operations**
|
|
95
|
+
- Acquire and release locks
|
|
96
|
+
- Block concurrent lock acquisition
|
|
97
|
+
- Handle stale locks
|
|
98
|
+
|
|
99
|
+
2. **Regular repository support**
|
|
100
|
+
- Create locks in `.git` directory
|
|
101
|
+
|
|
102
|
+
3. **Submodule support** (NEW)
|
|
103
|
+
- Handle `.git` file with `gitdir:` reference
|
|
104
|
+
- Resolve relative gitdir paths
|
|
105
|
+
- Create locks in the actual git directory
|
|
106
|
+
- Proper error handling for missing submodule directories
|
|
107
|
+
- Proper error handling for invalid `.git` file format
|
|
108
|
+
|
|
109
|
+
4. **Lock manager functionality**
|
|
110
|
+
- Execute operations under lock
|
|
111
|
+
- Release locks on operation failure
|
|
112
|
+
- Serialize multiple operations on same repo
|
|
113
|
+
|
|
114
|
+
All 12 tests pass successfully with 86%+ coverage on the fileLock module.
|
|
115
|
+
|
|
116
|
+
## Impact
|
|
117
|
+
|
|
118
|
+
This fix enables kodrdriv to work correctly in monorepo setups where packages are organized as git submodules, such as:
|
|
119
|
+
|
|
120
|
+
- Multi-repository projects using git submodules for shared libraries
|
|
121
|
+
- Projects with external dependencies included as submodules
|
|
122
|
+
- Monorepos with complex submodule hierarchies
|
|
123
|
+
|
|
124
|
+
The fix maintains backward compatibility with regular git repositories while adding robust support for submodules.
|
|
125
|
+
|
|
126
|
+
## Related Files
|
|
127
|
+
|
|
128
|
+
- `src/util/fileLock.ts` - Core fix implementation
|
|
129
|
+
- `tests/fileLock.test.ts` - Comprehensive test suite
|
|
130
|
+
- `src/util/gitMutex.ts` - Uses RepositoryFileLockManager
|
|
131
|
+
- `src/commands/publish.ts` - Uses git locks during publish operations
|
|
132
|
+
|