feat(cli): Implement complete command-line interface
Provides a user-friendly CLI for all GitLab Inbox operations. src/cli/mod.rs - Clap command definitions: - Global --config flag for alternate config path - Subcommands: init, auth-test, doctor, version, backup, reset, migrate, sync-status, ingest, list, count, show - Ingest supports --type (issues/merge_requests), --project filter, --force lock override, --full resync - List supports rich filtering: --state, --author, --assignee, --label, --milestone, --since, --due-before, --has-due-date - List supports --sort (updated/created/iid), --order (asc/desc) - List supports --open to launch browser, --json for scripting src/cli/commands/ - Command implementations: init.rs: Interactive configuration wizard - Prompts for GitLab URL, token env var, projects to track - Creates config file and initializes database - Supports --force overwrite and --non-interactive mode auth_test.rs: Verify GitLab authentication - Calls /api/v4/user to validate token - Displays username and GitLab instance URL doctor.rs: Environment health check - Validates config file exists and parses correctly - Checks database connectivity and migration state - Verifies GitLab authentication - Reports token environment variable status - Supports --json output for CI integration ingest.rs: Data synchronization from GitLab - Acquires sync lock with stale detection - Shows progress bars for issues and discussions - Reports sync statistics on completion - Supports --full flag to reset cursors and refetch all data list.rs: Query local database - Formatted table output with comfy-table - Filters build dynamic SQL with parameterized queries - Username filters normalize @ prefix automatically - --open flag uses 'open' crate for cross-platform browser launch - --json outputs array of issue objects show.rs: Detailed entity view - Displays issue metadata in structured format - Shows full description with markdown - Lists labels, assignees, milestone - Shows discussion threads with notes count.rs: Entity statistics - Counts issues, discussions, or notes - Supports --type filter for discussions/notes sync_status.rs: Display sync watermarks - Shows last sync time per project - Displays cursor positions for debugging src/main.rs - Application entry point: - Initializes tracing subscriber with env-filter - Parses CLI arguments via clap - Dispatches to appropriate command handler - Consistent error formatting for all failure modes src/lib.rs - Library entry point: - Exports cli, core, gitlab, ingestion modules - Re-exports Config, GiError, Result for convenience Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
168
src/cli/mod.rs
Normal file
168
src/cli/mod.rs
Normal file
@@ -0,0 +1,168 @@
|
||||
//! CLI module with clap command definitions.
|
||||
|
||||
pub mod commands;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
/// GitLab Inbox - Unified notification management
|
||||
#[derive(Parser)]
|
||||
#[command(name = "gi")]
|
||||
#[command(version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
/// Path to config file
|
||||
#[arg(short, long, global = true)]
|
||||
pub config: Option<String>,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands {
|
||||
/// Initialize configuration and database
|
||||
Init {
|
||||
/// Skip overwrite confirmation
|
||||
#[arg(long)]
|
||||
force: bool,
|
||||
|
||||
/// Fail if prompts would be shown
|
||||
#[arg(long)]
|
||||
non_interactive: bool,
|
||||
},
|
||||
|
||||
/// Verify GitLab authentication
|
||||
AuthTest,
|
||||
|
||||
/// Check environment health
|
||||
Doctor {
|
||||
/// Output as JSON
|
||||
#[arg(long)]
|
||||
json: bool,
|
||||
},
|
||||
|
||||
/// Show version information
|
||||
Version,
|
||||
|
||||
/// Create timestamped database backup
|
||||
Backup,
|
||||
|
||||
/// Delete database and reset all state
|
||||
Reset {
|
||||
/// Skip confirmation prompt
|
||||
#[arg(long)]
|
||||
confirm: bool,
|
||||
},
|
||||
|
||||
/// Run pending database migrations
|
||||
Migrate,
|
||||
|
||||
/// Show sync state
|
||||
SyncStatus,
|
||||
|
||||
/// Ingest data from GitLab
|
||||
Ingest {
|
||||
/// Resource type to ingest
|
||||
#[arg(long, value_parser = ["issues", "merge_requests"])]
|
||||
r#type: String,
|
||||
|
||||
/// Filter to single project
|
||||
#[arg(long)]
|
||||
project: Option<String>,
|
||||
|
||||
/// Override stale sync lock
|
||||
#[arg(long)]
|
||||
force: bool,
|
||||
|
||||
/// Full re-sync: reset cursors and fetch all data from scratch
|
||||
#[arg(long)]
|
||||
full: bool,
|
||||
},
|
||||
|
||||
/// List issues or MRs from local database
|
||||
List {
|
||||
/// Entity type to list
|
||||
#[arg(value_parser = ["issues", "mrs"])]
|
||||
entity: String,
|
||||
|
||||
/// Maximum results
|
||||
#[arg(long, default_value = "50")]
|
||||
limit: usize,
|
||||
|
||||
/// Filter by project path
|
||||
#[arg(long)]
|
||||
project: Option<String>,
|
||||
|
||||
/// Filter by state
|
||||
#[arg(long, value_parser = ["opened", "closed", "all"])]
|
||||
state: Option<String>,
|
||||
|
||||
/// Filter by author username
|
||||
#[arg(long)]
|
||||
author: Option<String>,
|
||||
|
||||
/// Filter by assignee username
|
||||
#[arg(long)]
|
||||
assignee: Option<String>,
|
||||
|
||||
/// Filter by label (repeatable, AND logic)
|
||||
#[arg(long)]
|
||||
label: Option<Vec<String>>,
|
||||
|
||||
/// Filter by milestone title
|
||||
#[arg(long)]
|
||||
milestone: Option<String>,
|
||||
|
||||
/// Filter by time (7d, 2w, 1m, or YYYY-MM-DD)
|
||||
#[arg(long)]
|
||||
since: Option<String>,
|
||||
|
||||
/// Filter by due date (before this date, YYYY-MM-DD)
|
||||
#[arg(long)]
|
||||
due_before: Option<String>,
|
||||
|
||||
/// Show only issues with a due date
|
||||
#[arg(long)]
|
||||
has_due_date: bool,
|
||||
|
||||
/// Sort field
|
||||
#[arg(long, value_parser = ["updated", "created", "iid"], default_value = "updated")]
|
||||
sort: String,
|
||||
|
||||
/// Sort order
|
||||
#[arg(long, value_parser = ["desc", "asc"], default_value = "desc")]
|
||||
order: String,
|
||||
|
||||
/// Open first matching issue in browser
|
||||
#[arg(long)]
|
||||
open: bool,
|
||||
|
||||
/// Output as JSON
|
||||
#[arg(long)]
|
||||
json: bool,
|
||||
},
|
||||
|
||||
/// Count entities in local database
|
||||
Count {
|
||||
/// Entity type to count
|
||||
#[arg(value_parser = ["issues", "mrs", "discussions", "notes"])]
|
||||
entity: String,
|
||||
|
||||
/// Filter by noteable type (for discussions/notes)
|
||||
#[arg(long, value_parser = ["issue", "mr"])]
|
||||
r#type: Option<String>,
|
||||
},
|
||||
|
||||
/// Show detailed entity information
|
||||
Show {
|
||||
/// Entity type to show
|
||||
#[arg(value_parser = ["issue", "mr"])]
|
||||
entity: String,
|
||||
|
||||
/// Entity IID
|
||||
iid: i64,
|
||||
|
||||
/// Filter by project path (required if iid is ambiguous)
|
||||
#[arg(long)]
|
||||
project: Option<String>,
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user