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)
138 lines
3.6 KiB
Markdown
138 lines
3.6 KiB
Markdown
# 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
|