Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ directories-next = "2.0"
futures = "0.3"
gtmpl = "0.7"
http = "0.2"
human-errors = "0.1.5"
human-errors = "0.2.3"
inventory = "0.3.21"
itertools = "0.14"
keyring = { version = "3.6.3", optional = true, features = ["apple-native", "windows-native", "sync-secret-service"] }
Expand Down
4 changes: 3 additions & 1 deletion src/commands/apps.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::errors::HumanErrorResultExt;

use super::*;
use tracing_batteries::prelude::*;

Expand All @@ -20,7 +22,7 @@ impl CommandRunnable for AppsCommand {
#[tracing::instrument(name = "gt apps", err, skip(self, core, _matches))]
async fn run(&self, core: &Core, _matches: &ArgMatches) -> Result<i32, engine::Error> {
for app in core.config().get_apps() {
writeln!(core.output(), "{}", app.get_name())?;
writeln!(core.output(), "{}", app.get_name()).to_human_error()?;
}

Ok(0)
Expand Down
63 changes: 31 additions & 32 deletions src/commands/auth.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::errors::HumanErrorResultExt;

use super::*;
use clap::Arg;
use human_errors::prelude::*;
use tracing_batteries::prelude::*;

pub struct AuthCommand;
Expand Down Expand Up @@ -34,22 +37,17 @@ impl CommandRunnable for AuthCommand {
#[tracing::instrument(name = "gt auth", err, skip(self, core, matches))]
async fn run(&self, core: &Core, matches: &ArgMatches) -> Result<i32, engine::Error> {
let service = matches.get_one::<String>("service").ok_or_else(|| {
errors::user(
"You have not provided the name of the service you wish to authenticate.",
"Please provide the name of the service when running this command: `git-tool auth gh`.",
)
human_errors::user("You have not provided the name of the service you wish to authenticate.", &["Please provide the name of the service when running this command: `git-tool auth gh`."])
})?;

if let Ok(svc) = core.config().get_service(service) {
if svc.api.is_none() {
return Err(errors::user(
&format!(
"The service '{}' does not include an API which supports authentication.",
&svc.name
),
"You do not need to configure authentication for this service, but you can check the services in your configuration using `git-tool services`.",
));
}
svc.api.as_ref().ok_or_user_err(
format!(
"The service '{}' does not include an API which supports authentication.",
&svc.name
),
&["You do not need to configure authentication for this service, but you can check the services in your configuration using `git-tool services`."],
)?;

if matches.get_flag("remove-token") {
core.keychain().delete_token(service)?;
Expand All @@ -62,40 +60,41 @@ impl CommandRunnable for AuthCommand {
.find(|s| s.handles(svc))
.cloned()
{
writeln!(core.output(), "{}", online_service.auth_instructions())?;
writeln!(core.output(), "{}", online_service.auth_instructions())
.to_human_error()?;
}

writeln!(core.output(), "Access Token: ")?;
rpassword::read_password().map_err(|e| errors::user_with_internal(
"Could not read the access token that you entered.",
"Please try running this command again, or let us know if you continue to run into problems by opening a GitHub issue.",
e))?
writeln!(core.output(), "Access Token: ").to_human_error()?;
rpassword::read_password().wrap_user_err(
"Could not read the access token that you entered.",
&["Please try running this command again, or let us know if you continue to run into problems by opening a GitHub issue."],
)?
}
};

core.keychain().set_token(service, &token)?;

writeln!(core.output(), "Access Token set for service '{service}'")?;
writeln!(core.output(), "Access Token set for service '{service}'")
.to_human_error()?;
if let Some(online_service) = online::services().iter().find(|s| s.handles(svc)) {
writeln!(core.output(), "Testing authentication token...")?;
writeln!(core.output(), "Testing authentication token...").to_human_error()?;
online_service.test(core, svc).await?;
writeln!(core.output(), "Authentication token is valid.")?;
writeln!(core.output(), "Authentication token is valid.").to_human_error()?;
}
}
} else if core.config().get_services().next().is_some() {
return Err(human_errors::user(
format!(
"The service you specified ('{service}') does not exist in your configuration."
),
&["Try using one of the services listing in `git-tool services` instead."],
));
} else {
let suggestion = if let Some(default_service) = core.config().get_services().next() {
return Err(human_errors::user(
format!(
"Try running `git-tool auth {default_service}` or use one of the services listed in `git-tool services`."
)
} else {
"Make sure that you have registered a service in your configuration file.".into()
};

return Err(errors::user(
&format!(
"The service you specified ('{service}') does not exist in your configuration."
),
&suggestion,
&["Make sure that you have registered a service in your configuration file."],
));
}

Expand Down
21 changes: 10 additions & 11 deletions src/commands/clone.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use crate::engine::Target;
use crate::errors::HumanErrorResultExt;
use crate::tasks::*;
use clap::Arg;
use std::path::PathBuf;
Expand Down Expand Up @@ -27,26 +28,24 @@ impl CommandRunnable for CloneCommand {
}

#[tracing::instrument(name = "gt clone", err, skip(self, core, matches))]
async fn run(&self, core: &Core, matches: &ArgMatches) -> Result<i32, errors::Error> {
let repo_name = matches.get_one::<String>("repo").ok_or_else(|| errors::user(
"You didn't specify the repository you wanted to clone.",
"Remember to specify a repository name like this: 'git-tool clone gh:sierrasoftworks/git-tool'."))?;
async fn run(&self, core: &Core, matches: &ArgMatches) -> Result<i32, human_errors::Error> {
let repo_name = matches.get_one::<String>("repo").ok_or_else(|| human_errors::user("You didn't specify the repository you wanted to clone.", &["Remember to specify a repository name like this: 'git-tool clone gh:sierrasoftworks/git-tool'."]))?;

if let Some(file_path) = repo_name.strip_prefix('@') {
// Load the list of repos to clone from a file
let file_path: PathBuf = file_path.parse().map_err(|e| {
errors::user_with_internal(
"The specified file path is not valid.",
"Please make sure you are specifying a valid file path for your import file.",
human_errors::wrap_user(
e,
"The specified file path is not valid.",
&["Please make sure you are specifying a valid file path for your import file."],
)
})?;

let file = std::fs::read_to_string(&file_path).map_err(|e| {
errors::user_with_internal(
"Could not read the specified clone file.",
"Please make sure the file exists and is readable.",
human_errors::wrap_user(
e,
"Could not read the specified clone file.",
&["Please make sure the file exists and is readable."],
)
})?;

Expand All @@ -58,7 +57,7 @@ impl CommandRunnable for CloneCommand {
}

let repo = core.resolver().get_best_repo(&line.trim().parse()?)?;
writeln!(core.output(), "{}", repo)?;
writeln!(core.output(), "{}", repo).to_human_error()?;
match operation.apply_repo(core, &repo).await {
Ok(()) => {}
Err(e) => return Err(e),
Expand Down
15 changes: 8 additions & 7 deletions src/commands/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,22 @@ impl CompleteCommand {
}
}

fn get_completion_matches(&self, args: &str) -> Result<ArgMatches, errors::Error> {
fn get_completion_matches(&self, args: &str) -> Result<ArgMatches, human_errors::Error> {
let true_args = shell_words::split(args)
.map_err(|e| errors::user_with_internal(
.map_err(|e| human_errors::wrap_user(
e,
"Could not parse the arguments you provided.",
"Please make sure that you are using auto-complete with a valid set of command line arguments.",
e))?;
&["Please make sure that you are using auto-complete with a valid set of command line arguments."],
))?;

let complete_app = clap::Command::new("Git-Tool")
.subcommands(inventory::iter::<Command>().map(|x| x.app()));

complete_app.try_get_matches_from(true_args).map_err(|err| {
errors::user_with_internal(
human_errors::wrap_user(
err.to_string(),
"Failed to parse command line arguments for auto-completion.",
"Make sure that you are using valid Git-Tool command line arguments and try again.",
errors::detailed_message(&err.to_string()),
&["Make sure that you are using valid Git-Tool command line arguments and try again."],
)
})
}
Expand Down
45 changes: 25 additions & 20 deletions src/commands/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::engine::features;
use crate::errors::HumanErrorResultExt;

use super::async_trait;
use super::*;
use clap::Arg;
use human_errors::OptionExt;
use online::registry::Registry;
use tracing_batteries::prelude::*;

Expand Down Expand Up @@ -89,7 +91,7 @@ impl CommandRunnable for ConfigCommand {
}

#[tracing::instrument(name = "gt config", err, skip(self, core, matches))]
async fn run(&self, core: &Core, matches: &ArgMatches) -> Result<i32, errors::Error> {
async fn run(&self, core: &Core, matches: &ArgMatches) -> Result<i32, human_errors::Error> {
let mut cfg = core.config().clone();

let save_config = match matches.subcommand() {
Expand All @@ -99,24 +101,22 @@ impl CommandRunnable for ConfigCommand {
let entries = registry.get_entries(core).await?;
let mut output = core.output();
for entry in entries {
writeln!(output, "{entry}")?;
writeln!(output, "{entry}").to_human_error()?;
}

false
}
Some(("add", args)) => {
let id = args.get_one::<String>("id").ok_or_else(|| {
errors::user(
"You have not provided an ID for the config template you wish to add.",
"",
)
})?;
let id = args.get_one::<String>("id").ok_or_user_err(
"You have not provided an ID for the config template you wish to add.",
&["Please provide the ID of the config template when running this command (e.g. `git-tool config add apps/bash`)."],
)?;

let registry = online::GitHubRegistry;
let entry = registry.get_entry(core, id).await?;

writeln!(core.output(), "Applying {}", entry.name)?;
writeln!(core.output(), "> {}", entry.description)?;
writeln!(core.output(), "Applying {}", entry.name).to_human_error()?;
writeln!(core.output(), "> {}", entry.description).to_human_error()?;

for ec in entry.configs {
if ec.is_compatible() {
Expand Down Expand Up @@ -147,14 +147,15 @@ impl CommandRunnable for ConfigCommand {
}
None => match core.config().get_alias(alias) {
Some(repo) => {
writeln!(core.output(), "{alias} = {repo}")?;
writeln!(core.output(), "{alias} = {repo}").to_human_error()?;
false
}
None => {
writeln!(
core.output(),
"No alias exists with the name '{alias}'"
)?;
)
.to_human_error()?;
false
}
},
Expand All @@ -164,7 +165,7 @@ impl CommandRunnable for ConfigCommand {
None => {
let mut output = core.output();
for (alias, repo) in core.config().get_aliases() {
writeln!(output, "{alias} = {repo}")?;
writeln!(output, "{alias} = {repo}").to_human_error()?;
}

false
Expand All @@ -180,7 +181,7 @@ impl CommandRunnable for ConfigCommand {
writeln!(
core.output(),
"Cannot set the feature flag '{flag}' to '{invalid}' because only 'true' and 'false' are valid settings."
)?;
).to_human_error()?;
return Ok(1);
}
None => {
Expand All @@ -189,7 +190,8 @@ impl CommandRunnable for ConfigCommand {
"{} = {}",
flag,
core.config().get_features().has(flag)
)?;
)
.to_human_error()?;

false
}
Expand All @@ -202,7 +204,8 @@ impl CommandRunnable for ConfigCommand {
"{} = {}",
feature,
core.config().get_features().has(feature)
)?;
)
.to_human_error()?;
}

false
Expand All @@ -221,7 +224,8 @@ impl CommandRunnable for ConfigCommand {
core.output(),
"{}",
core.config().get_scratch_directory().display()
)?;
)
.to_human_error()?;

false
}
Expand All @@ -238,13 +242,14 @@ impl CommandRunnable for ConfigCommand {
core.output(),
"{}",
core.config().get_dev_directory().display()
)?;
)
.to_human_error()?;

false
}
},
_ => {
writeln!(core.output(), "{}", core.config().to_string()?)?;
writeln!(core.output(), "{}", core.config().to_string()?).to_human_error()?;

false
}
Expand All @@ -256,7 +261,7 @@ impl CommandRunnable for ConfigCommand {
cfg.save(&path).await?;
}
None => {
writeln!(core.output(), "{}", cfg.to_string()?)?;
writeln!(core.output(), "{}", cfg.to_string()?).to_human_error()?;
}
}
}
Expand Down
Loading
Loading