Skip to content

Commit 7f3b832

Browse files
committed
imp(cli): add cli commands/arguments
1 parent 1c457d1 commit 7f3b832

File tree

7 files changed

+253
-66
lines changed

7 files changed

+253
-66
lines changed

.github/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
We welcome any kind of contributions. Whether you are reporting a bug, coding a feature or correcting a typo. Every effort counts; and all contributions are greatly appreaciated.
44

5-
Another great way to contribute is to actually use for your Open Source or Commercial projects. If you do, make sure to open an issue with a link to your project.
5+
Another great way to contribute is to actually use codeinput for your Open Source or Commercial projects. If you do, make sure to open an issue with a link to your project.
66

77
### Testing Code
88

cli/src/lib.rs

Lines changed: 174 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
use clap::{CommandFactory, Parser, Subcommand};
2+
use clap_complete::{
3+
generate,
4+
shells::{Bash, Fish, Zsh},
5+
};
16
use std::path::PathBuf;
2-
use clap::{Parser, Subcommand, CommandFactory};
3-
use clap_complete::{generate, shells::{Bash, Fish, Zsh}};
47

5-
use core::commands;
8+
use core::{commands, types::OutputFormat};
69
use utils::app_config::AppConfig;
710
use utils::error::Result;
811
use utils::types::LogLevel;
912

10-
1113
#[derive(Parser, Debug)]
1214
#[command(
1315
name = "codeinput",
@@ -25,11 +27,16 @@ pub struct Cli {
2527
pub config: Option<PathBuf>,
2628

2729
/// Set a custom config file
28-
#[arg(name="debug", short, long="debug", value_name = "DEBUG")]
30+
#[arg(name = "debug", short, long = "debug", value_name = "DEBUG")]
2931
pub debug: Option<bool>,
3032

31-
/// Set Log Level
32-
#[arg(name="log_level", short, long="log-level", value_name = "LOG_LEVEL")]
33+
/// Set Log Level
34+
#[arg(
35+
name = "log_level",
36+
short,
37+
long = "log-level",
38+
value_name = "LOG_LEVEL"
39+
)]
3340
pub log_level: Option<LogLevel>,
3441

3542
/// Subcommands
@@ -40,26 +47,23 @@ pub struct Cli {
4047
#[derive(Subcommand, Debug)]
4148
enum Commands {
4249
#[clap(
43-
name = "hazard",
44-
about = "Generate a hazardous occurance",
45-
long_about = None,
50+
name = "codeowners",
51+
about = "Manage and analyze CODEOWNERS files",
52+
long_about = "Tools for parsing, validating and querying CODEOWNERS files"
4653
)]
47-
Hazard,
48-
#[clap(
49-
name = "error",
50-
about = "Simulate an error",
51-
long_about = None,
52-
)]
53-
Error,
54+
Codeowners {
55+
#[clap(subcommand)]
56+
subcommand: CodeownersSubcommand,
57+
},
5458
#[clap(
5559
name = "completion",
5660
about = "Generate completion scripts",
5761
long_about = None,
5862
)]
59-
Completion {
60-
#[clap(subcommand)]
61-
subcommand: CompletionSubcommand,
62-
},
63+
Completion {
64+
#[clap(subcommand)]
65+
subcommand: CompletionSubcommand,
66+
},
6367
#[clap(
6468
name = "config",
6569
about = "Show Configuration",
@@ -78,6 +82,102 @@ enum CompletionSubcommand {
7882
Fish,
7983
}
8084

85+
#[derive(Subcommand, PartialEq, Debug)]
86+
enum CodeownersSubcommand {
87+
#[clap(
88+
name = "parse",
89+
about = "Preprocess CODEOWNERS files and build ownership map"
90+
)]
91+
Parse {
92+
/// Directory path to analyze (default: current directory)
93+
#[arg(default_value = ".")]
94+
path: PathBuf,
95+
96+
/// Custom cache file location
97+
#[arg(long, value_name = "FILE")]
98+
cache_file: Option<PathBuf>,
99+
},
100+
101+
#[clap(
102+
name = "list-files",
103+
about = "Find and list files with their owners based on filter criteria"
104+
)]
105+
ListFiles {
106+
/// Directory path to analyze (default: current directory)
107+
#[arg(default_value = ".")]
108+
path: Option<PathBuf>,
109+
110+
/// Only show files with specified tags
111+
#[arg(long, value_name = "LIST")]
112+
tags: Option<String>,
113+
114+
/// Only show files owned by these owners
115+
#[arg(long, value_name = "LIST")]
116+
owners: Option<String>,
117+
118+
/// Show only unowned files
119+
#[arg(long)]
120+
unowned: bool,
121+
122+
/// Output format: text|json|bincode
123+
#[arg(long, value_name = "FORMAT", default_value = "text", value_parser = parse_output_format)]
124+
format: OutputFormat,
125+
},
126+
127+
#[clap(
128+
name = "list-owners",
129+
about = "Display aggregated owner statistics and associations"
130+
)]
131+
ListOwners {
132+
/// Comma-separated tags filter
133+
#[arg(long, value_name = "LIST")]
134+
filter_tags: Option<String>,
135+
136+
/// Display tags in output
137+
#[arg(long)]
138+
show_tags: bool,
139+
140+
/// Only show owners with >= NUM files
141+
#[arg(long, value_name = "NUM")]
142+
min_files: Option<u32>,
143+
144+
/// Output format: text|json|bincode
145+
#[arg(long, value_name = "FORMAT", default_value = "text", value_parser = parse_output_format)]
146+
format: OutputFormat,
147+
},
148+
#[clap(
149+
name = "list-tags",
150+
about = "Audit and analyze tag usage across CODEOWNERS files"
151+
)]
152+
ListTags {
153+
/// Warn if tags have fewer than NUM owners
154+
#[arg(long, value_name = "NUM")]
155+
verify_owners: Option<u32>,
156+
157+
/// Sort by: tag|count|owners
158+
#[arg(long, value_name = "FIELD", default_value = "tag")]
159+
sort: String,
160+
161+
/// Output format: text|json|bincode
162+
#[arg(long, value_name = "FORMAT", default_value = "text", value_parser = parse_output_format)]
163+
format: OutputFormat,
164+
},
165+
166+
#[clap(
167+
name = "validate",
168+
about = "Validate CODEOWNERS files for errors and potential issues"
169+
)]
170+
Validate {
171+
/// Treat warnings as errors
172+
#[arg(long)]
173+
strict: bool,
174+
175+
/// Output format: text|json|bincode
176+
#[arg(long, value_name = "FORMAT", default_value = "text", value_parser = parse_output_format)]
177+
output: OutputFormat,
178+
},
179+
}
180+
81181
pub fn cli_match() -> Result<()> {
82182
// Parse the command line arguments
83183
let cli = Cli::parse();
@@ -87,14 +187,13 @@ pub fn cli_match() -> Result<()> {
87187

88188
let app = Cli::command();
89189
let matches = app.get_matches();
90-
190+
91191
AppConfig::merge_args(matches)?;
92192

93193
// Execute the subcommand
94194
match &cli.command {
95-
Commands::Hazard => commands::hazard()?,
96-
Commands::Error => commands::simulate_error()?,
97-
Commands::Completion {subcommand} => {
195+
Commands::Codeowners { subcommand } => codeowners(subcommand)?,
196+
Commands::Completion { subcommand } => {
98197
let mut app = Cli::command();
99198
match subcommand {
100199
CompletionSubcommand::Bash => {
@@ -113,3 +212,53 @@ pub fn cli_match() -> Result<()> {
113212

114213
Ok(())
115214
}
215+
216+
/// Handle codeowners subcommands
217+
pub(crate) fn codeowners(subcommand: &CodeownersSubcommand) -> Result<()> {
218+
match subcommand {
219+
CodeownersSubcommand::Parse { path, cache_file } => {
220+
commands::codeowners_parse(path, cache_file.as_deref())
221+
}
222+
CodeownersSubcommand::ListFiles {
223+
path,
224+
tags,
225+
owners,
226+
unowned,
227+
format,
228+
} => commands::codeowners_list_files(
229+
path.as_deref(),
230+
tags.as_deref(),
231+
owners.as_deref(),
232+
*unowned,
233+
format,
234+
),
235+
CodeownersSubcommand::ListOwners {
236+
filter_tags,
237+
show_tags,
238+
min_files,
239+
format,
240+
} => commands::codeowners_list_owners(
241+
filter_tags.as_deref(),
242+
*show_tags,
243+
min_files.as_ref(),
244+
format,
245+
),
246+
CodeownersSubcommand::ListTags {
247+
verify_owners,
248+
sort,
249+
format,
250+
} => commands::codeowners_list_tags(verify_owners.as_ref(), sort, format),
251+
CodeownersSubcommand::Validate { strict, output } => {
252+
commands::codeowners_validate(*strict, output)
253+
}
254+
}
255+
}
256+
257+
fn parse_output_format(s: &str) -> std::result::Result<OutputFormat, String> {
258+
match s.to_lowercase().as_str() {
259+
"text" => Ok(OutputFormat::Text),
260+
"json" => Ok(OutputFormat::Json),
261+
"bincode" => Ok(OutputFormat::Bincode),
262+
_ => Err(format!("Invalid output format: {}", s)),
263+
}
264+
}

core/src/commands.rs

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,79 @@
1-
use super::error;
2-
use super::hazard;
1+
use crate::types::OutputFormat;
32

43
use utils::app_config::AppConfig;
54
use utils::error::Result;
65

76
/// Show the configuration file
8-
pub fn hazard() -> Result<()> {
9-
// Generate, randomly, True or False
10-
let random_hazard: bool = hazard::generate_hazard()?;
7+
pub fn config() -> Result<()> {
8+
let config = AppConfig::fetch()?;
9+
println!("{:#?}", config);
1110

12-
if random_hazard {
13-
println!("You got it right!");
14-
} else {
15-
println!("You got it wrong!");
16-
}
11+
Ok(())
12+
}
1713

14+
/// Preprocess CODEOWNERS files and build ownership map
15+
pub fn codeowners_parse(
16+
path: &std::path::Path, cache_file: Option<&std::path::Path>,
17+
) -> Result<()> {
18+
info!("Parsing CODEOWNERS files at {}", path.display());
19+
info!(
20+
"Cache file: {}",
21+
cache_file.map_or_else(
22+
|| ".codeinput-cache.json".into(),
23+
|p| p.display().to_string()
24+
)
25+
);
26+
println!("CODEOWNERS parsing completed successfully");
1827
Ok(())
1928
}
2029

21-
/// Show the configuration file
22-
pub fn config() -> Result<()> {
23-
let config = AppConfig::fetch()?;
24-
println!("{:#?}", config);
30+
/// Find and list files with their owners based on filter criteria
31+
pub fn codeowners_list_files(
32+
path: Option<&std::path::Path>, tags: Option<&str>, owners: Option<&str>, unowned: bool,
33+
format: &OutputFormat,
34+
) -> Result<()> {
35+
let path_str = path.map_or(".".into(), |p| p.display().to_string());
36+
info!("Listing files in {}", path_str);
37+
info!("Tags filter: {:?}", tags);
38+
info!("Owners filter: {:?}", owners);
39+
info!("Unowned only: {}", unowned);
40+
info!("Output format: {}", format);
41+
42+
println!("Files listing completed");
43+
Ok(())
44+
}
2545

46+
/// Display aggregated owner statistics and associations
47+
pub fn codeowners_list_owners(
48+
filter_tags: Option<&str>, show_tags: bool, min_files: Option<&u32>, format: &OutputFormat,
49+
) -> Result<()> {
50+
info!("Listing owners with filter_tags: {:?}", filter_tags);
51+
info!("Show tags: {}", show_tags);
52+
info!("Min files: {:?}", min_files);
53+
info!("Output format: {}", format);
54+
55+
println!("Owners listing completed");
2656
Ok(())
2757
}
2858

29-
/// Simulate an error
30-
pub fn simulate_error() -> Result<()> {
31-
// Log this Error simulation
32-
info!("We are simulating an error");
59+
/// Audit and analyze tag usage across CODEOWNERS files
60+
pub fn codeowners_list_tags(
61+
verify_owners: Option<&u32>, sort: &str, format: &OutputFormat,
62+
) -> Result<()> {
63+
info!("Listing tags with verify_owners: {:?}", verify_owners);
64+
info!("Sort by: {}", sort);
65+
info!("Output format: {}", format);
66+
67+
println!("Tags listing completed");
68+
Ok(())
69+
}
3370

34-
// Simulate an error
35-
error::simulate_error()?;
71+
/// Validate CODEOWNERS files for errors and potential issues
72+
pub fn codeowners_validate(strict: bool, output: &OutputFormat) -> Result<()> {
73+
info!("Validating CODEOWNERS files");
74+
info!("Strict mode: {}", strict);
75+
info!("Output format: {}", output);
3676

37-
// We should never get here...
77+
println!("CODEOWNERS validation completed");
3878
Ok(())
3979
}

core/src/error.rs

Lines changed: 0 additions & 11 deletions
This file was deleted.

core/src/hazard.rs

Lines changed: 0 additions & 6 deletions
This file was deleted.

core/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
extern crate log;
33

44
pub mod commands;
5-
pub mod error;
6-
pub mod hazard;
5+
pub mod types;
76

87
use utils::error::Result;
98

0 commit comments

Comments
 (0)