feat(init): add --refresh flag for project re-registration
When new projects are added to the config file, `lore sync` doesn't pick them up because project discovery only happens during `lore init`. Previously, users had to use `--force` to overwrite their entire config. The new `--refresh` flag reads the existing config and updates the database to match, without modifying the config file itself. Features: - Validates GitLab authentication before processing - Registers new projects from config into the database - Detects orphan projects (in DB but removed from config) - Interactive mode: prompts to delete orphans (default: No) - Robot mode: returns JSON with orphan info, no prompts Usage: lore init --refresh # Interactive lore --robot init --refresh # JSON output Improved UX: When running `lore init` with an existing config and no flags, the error message now suggests using `--refresh` to register new projects or `--force` to overwrite the config file. Implementation: - Added RefreshOptions and RefreshResult types to init module - Added run_init_refresh() for core refresh logic - Added delete_orphan_projects() helper for orphan cleanup - Added handle_init_refresh() in main.rs for CLI handling - Added JSON output types for robot mode - Registered --refresh in autocorrect.rs command flags registry - --refresh conflicts with --force (mutually exclusive)
This commit is contained in:
137
plans/init-refresh-flag.md
Normal file
137
plans/init-refresh-flag.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Plan: `lore init --refresh`
|
||||
|
||||
**Created:** 2026-03-02
|
||||
**Status:** Complete
|
||||
|
||||
## Problem
|
||||
|
||||
When new repos are added to the config file, `lore sync` doesn't pick them up because project discovery only happens during `lore init`. Currently, users must use `--force` to overwrite their config, which is awkward.
|
||||
|
||||
## Solution
|
||||
|
||||
Add `--refresh` flag to `lore init` that reads the existing config and updates the database to match, without overwriting the config file.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### 1. CLI Changes (`src/cli/mod.rs`)
|
||||
|
||||
Add to init subcommand:
|
||||
- `--refresh` flag (conflicts with `--force`)
|
||||
- Ensure `--robot` / `-J` propagates to init
|
||||
|
||||
### 2. Update `InitOptions` struct
|
||||
|
||||
```rust
|
||||
pub struct InitOptions {
|
||||
pub config_path: Option<String>,
|
||||
pub force: bool,
|
||||
pub non_interactive: bool,
|
||||
pub refresh: bool, // NEW
|
||||
pub robot_mode: bool, // NEW
|
||||
}
|
||||
```
|
||||
|
||||
### 3. New `RefreshResult` struct
|
||||
|
||||
```rust
|
||||
pub struct RefreshResult {
|
||||
pub user: UserInfo,
|
||||
pub projects_registered: Vec<ProjectInfo>,
|
||||
pub projects_failed: Vec<ProjectFailure>, // path + error message
|
||||
pub orphans_found: Vec<String>, // paths in DB but not config
|
||||
pub orphans_deleted: Vec<String>, // if user said yes
|
||||
}
|
||||
|
||||
pub struct ProjectFailure {
|
||||
pub path: String,
|
||||
pub error: String,
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Main logic: `run_init_refresh()` (new function)
|
||||
|
||||
```
|
||||
1. Load config via Config::load()
|
||||
2. Resolve token, call get_current_user() → validate auth
|
||||
3. For each project in config.projects:
|
||||
- Call client.get_project(path)
|
||||
- On success: collect for DB upsert
|
||||
- On failure: collect in projects_failed
|
||||
4. Query DB for all existing projects
|
||||
5. Compute orphans = DB projects - config projects
|
||||
6. If orphans exist:
|
||||
- Robot mode: include in output, no prompt, no delete
|
||||
- Interactive: prompt "Delete N orphan projects? [y/N]"
|
||||
- Default N → skip deletion
|
||||
- Y → delete from DB
|
||||
7. Upsert validated projects into DB
|
||||
8. Return RefreshResult
|
||||
```
|
||||
|
||||
### 5. Improve existing init error message
|
||||
|
||||
In `run_init()`, when config exists and neither `--refresh` nor `--force`:
|
||||
|
||||
**Current:**
|
||||
> Config file exists at ~/.config/lore/config.json. Use --force to overwrite.
|
||||
|
||||
**New:**
|
||||
> Config already exists at ~/.config/lore/config.json.
|
||||
> - Use `--refresh` to register new projects from config
|
||||
> - Use `--force` to overwrite the config file
|
||||
|
||||
### 6. Robot mode output
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"data": {
|
||||
"mode": "refresh",
|
||||
"user": { "username": "...", "name": "..." },
|
||||
"projects_registered": [...],
|
||||
"projects_failed": [...],
|
||||
"orphans_found": ["old/project"],
|
||||
"orphans_deleted": []
|
||||
},
|
||||
"meta": { "elapsed_ms": 123 }
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Human output
|
||||
|
||||
```
|
||||
✓ Authenticated as @username (Full Name)
|
||||
|
||||
Projects
|
||||
✓ group/project-a registered
|
||||
✓ group/project-b registered
|
||||
✗ group/nonexistent not found
|
||||
|
||||
Orphans
|
||||
• old/removed-project
|
||||
|
||||
Delete 1 orphan project from database? [y/N]: n
|
||||
|
||||
Registered 2 projects (1 failed, 1 orphan kept)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Files to Touch
|
||||
|
||||
1. **`src/cli/mod.rs`** — add `--refresh` and `--robot` to init subcommand args
|
||||
2. **`src/cli/commands/init.rs`** — add `RefreshResult`, `run_init_refresh()`, update error message
|
||||
3. **`src/main.rs`** (or CLI dispatch) — route `--refresh` to new function
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [x] `lore init --refresh` reads existing config and registers projects
|
||||
- [x] Validates GitLab auth before processing
|
||||
- [x] Orphan projects prompt with default N (interactive mode)
|
||||
- [x] Robot mode outputs JSON, no prompts, includes orphans in output
|
||||
- [x] Existing `lore init` (no flags) suggests `--refresh` when config exists
|
||||
- [x] `--refresh` and `--force` are mutually exclusive
|
||||
Reference in New Issue
Block a user