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
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/forge_main/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ update-informer = { version = "1.2.0", default-features = false, features = [
"ureq",
"rustls-tls",
] }
dirs.workspace = true
open.workspace = true
humantime.workspace = true
num-format.workspace = true
Expand Down
6 changes: 6 additions & 0 deletions crates/forge_main/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,12 @@ pub enum ConfigCommand {

/// List configuration values.
List,

/// Print the path to the global config file.
Path,

/// Migrate the legacy ~/forge directory to ~/.forge.
Migrate,
}

/// Arguments for `forge config set`.
Expand Down
49 changes: 49 additions & 0 deletions crates/forge_main/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3595,7 +3595,56 @@ impl<A: API + ConsoleWriter + 'static, F: Fn(ForgeConfig) -> A + Send + Sync> UI
crate::cli::ConfigCommand::List => {
self.on_show_config(porcelain).await?;
}
crate::cli::ConfigCommand::Path => {
let path = forge_config::ConfigReader::config_path();
self.writeln(path.display().to_string())?;
}
crate::cli::ConfigCommand::Migrate => {
self.handle_config_migrate()?;
}
}
Ok(())
}

/// Rename `~/forge` to `~/.forge`.
///
/// Errors if the legacy directory does not exist, if the new directory
/// already exists, or if the rename fails.
fn handle_config_migrate(&mut self) -> Result<()> {
let home = dirs::home_dir()
.ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
let legacy = home.join("forge");
let new = home.join(".forge");

if !legacy.exists() {
anyhow::bail!(
"Legacy directory {} does not exist — nothing to migrate",
legacy.display()
);
}

if new.exists() {
anyhow::bail!(
"Target directory {} already exists — remove it first or migrate manually",
new.display()
);
}

std::fs::rename(&legacy, &new).map_err(|e| {
anyhow::anyhow!(
"Failed to rename {} to {}: {}",
legacy.display(),
new.display(),
e
)
})?;

self.writeln_title(TitleFormat::info("Migration Completed").sub_title(format!(
"{} → {}",
legacy.display(),
new.display()
)))?;

Ok(())
}

Expand Down
18 changes: 14 additions & 4 deletions shell-plugin/lib/actions/config.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -463,12 +463,22 @@ function _forge_action_config_edit() {
return 1
fi

local config_file="${HOME}/forge/.forge.toml"
# Resolve config file path via the forge binary (honours FORGE_CONFIG,
# new ~/.forge path, and legacy ~/forge fallback automatically)
local config_file
config_file=$(forge config path 2>/dev/null)
if [[ -z "$config_file" ]]; then
_forge_log error "Failed to resolve config path from 'forge config path'"
return 1
fi

local config_dir
config_dir=$(dirname "$config_file")

# Ensure the config directory exists
if [[ ! -d "${HOME}/forge" ]]; then
mkdir -p "${HOME}/forge" || {
_forge_log error "Failed to create ~/forge directory"
if [[ ! -d "$config_dir" ]]; then
mkdir -p "$config_dir" || {
_forge_log error "Failed to create $config_dir directory"
return 1
}
fi
Expand Down
Loading