Skip to content

Commit

Permalink
Config cmd (#29)
Browse files Browse the repository at this point in the history
* fix: making default pr be draft.

* feat: add a local config command.

* fix: cargo fmt

* fix: removed unused imports

* fix: ask user do they want to edit and not erroring anymore.

* update command

* update ser

---------

Co-authored-by: clabby <[email protected]>
  • Loading branch information
blmalone and clabby authored Oct 24, 2024
1 parent d295967 commit ec1c630
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 20 deletions.
23 changes: 5 additions & 18 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! The CLI for `st`.
use crate::{
config::{StConfig, DEFAULT_CONFIG_PRETTY},
config::{prompt_for_configuration, StConfig},
ctx::StContext,
errors::{StError, StResult},
subcommands::Subcommands,
Expand Down Expand Up @@ -35,32 +35,19 @@ impl Cli {
let repo = crate::git::active_repository().ok_or(StError::NotAGitRepository)?;
let config = Self::load_cfg_or_initialize()?;
let context = Self::load_ctx_or_initialize(config, &repo)?;

self.subcommand.run(context).await
}

/// Loads the [StConfig]. If the config does not exist, prompts the user to set up the
/// `st` for the first time.
/// Loads the [StConfig]. If the config does not exist or is the default config, prompts
/// the user to set up the `st` for the first time.
///
/// ## Returns
/// - `Result<StConfig>` - The global `st` config.
pub(crate) fn load_cfg_or_initialize() -> StResult<StConfig> {
// Load the global configuration for `st`, or initialize it if it doesn't exist.
match StConfig::try_load()? {
Some(config) => Ok(config),
None => {
let setup_message = format!(
"No global configuration found for `{}`. Set up the environment.",
Blue.paint("st")
);

// Print the default config.
let ser_cfg = inquire::Editor::new(&setup_message)
.with_file_extension(".toml")
.with_predefined_text(DEFAULT_CONFIG_PRETTY)
.prompt()?;
Ok(toml::from_str(&ser_cfg)?)
}
Some(config) if config.validate().is_ok() => Ok(config),
_ => prompt_for_configuration(None),
}
}

Expand Down
40 changes: 39 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Contains the global configuration for `st`.
use crate::constants::ST_CFG_FILE_NAME;
use crate::{constants::ST_CFG_FILE_NAME, errors::StResult};
use nu_ansi_term::Color;
use serde::{Deserialize, Serialize};
use std::{fs, io, path::PathBuf};
use thiserror::Error;
Expand Down Expand Up @@ -36,6 +37,14 @@ impl StConfig {
Err(_) => Ok(None),
}
}

/// Validates the configuration.
pub fn validate(&self) -> Result<(), StConfigError> {
if self.github_token.is_empty() {
return Err(StConfigError::MissingField("github_token".to_string()));
}
Ok(())
}
}

impl Drop for StConfig {
Expand All @@ -51,6 +60,35 @@ pub enum StConfigError {
/// Failed to load the configuration file.
#[error("Failed to load the configuration file: {}", .0)]
FailedToLoad(io::Error),
/// Missing a reqired field.
#[error("Missing required field: {}", .0)]
MissingField(String),
}

/// Prompts the user to set up the global configuration for `st`.
///
/// ## Returns
/// - `Result<StConfig>` - The newly created global `st` config.
pub fn prompt_for_configuration(existing_config: Option<&str>) -> StResult<StConfig> {
let setup_text = format!(
"{} configuration found for `{}`. Set up the environment.",
existing_config.map(|_| "Existing").unwrap_or("No"),
Color::Blue.paint("st")
);

// Use the provided predefined text or fall back to the default.
let default_text = existing_config.unwrap_or(DEFAULT_CONFIG_PRETTY);

// Print the default config.
let ser_cfg = inquire::Editor::new(&setup_text)
.with_file_extension(".toml")
.with_predefined_text(default_text)
.prompt()?;

let config: StConfig = toml::from_str(&ser_cfg)?;
config.validate()?;

Ok(config)
}

#[cfg(test)]
Expand Down
3 changes: 3 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ pub enum StError {
/// A [std::fmt::Write] error occurred.
#[error("🖋️ write error: {}", .0)]
WriteError(#[from] std::fmt::Error),
/// A [toml::ser::Error] occurred.
#[error("🍅 toml serialization error: {}", .0)]
TomlSerializationError(#[from] toml::ser::Error),
/// A [toml::de::Error] occurred.
#[error("🍅 toml decoding error: {}", .0)]
TomlDecodingError(#[from] toml::de::Error),
Expand Down
17 changes: 17 additions & 0 deletions src/subcommands/local/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! `config` subcommand.
use crate::{config::prompt_for_configuration, ctx::StContext, errors::StResult};

#[derive(Debug, Clone, Eq, PartialEq, clap::Args)]
pub struct ConfigCmd;

impl ConfigCmd {
/// Run the `config` subcommand to force or allow configuration editing.
pub fn run(self, mut ctx: StContext<'_>) -> StResult<()> {
let ser = toml::to_string_pretty(&ctx.cfg)?;
let cfg = prompt_for_configuration(Some(&ser))?;
ctx.cfg = cfg;

Ok(())
}
}
3 changes: 3 additions & 0 deletions src/subcommands/local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ pub use track::TrackCmd;

mod untrack;
pub use untrack::UntrackCmd;

mod config;
pub use config::ConfigCmd;
8 changes: 7 additions & 1 deletion src/subcommands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use crate::{ctx::StContext, errors::StResult};
use clap::Subcommand;

mod local;
use local::{CheckoutCmd, CreateCmd, DeleteCmd, LogCmd, RestackCmd, TrackCmd, UntrackCmd};
use local::{
CheckoutCmd, ConfigCmd, CreateCmd, DeleteCmd, LogCmd, RestackCmd, TrackCmd, UntrackCmd,
};

mod remote;
use remote::{StatusCmd, SubmitCmd, SyncCmd};
Expand Down Expand Up @@ -41,6 +43,9 @@ pub enum Subcommands {
/// Untrack the passed branch.
#[clap(visible_alias = "ut")]
Untrack(UntrackCmd),
/// Configure the st application.
#[clap(visible_alias = "cfg")]
Config(ConfigCmd),
}

impl Subcommands {
Expand All @@ -59,6 +64,7 @@ impl Subcommands {
Self::Log(args) => args.run(ctx),
Self::Track(args) => args.run(ctx),
Self::Untrack(args) => args.run(ctx),
Self::Config(args) => args.run(ctx),
}
}
}

0 comments on commit ec1c630

Please sign in to comment.