Skip to content

Commit 21fb39f

Browse files
committed
feat: integrate builds into wizard
- Show saved builds at wizard start, allow selecting one - Ask to save configuration as build at wizard end - Update README with builds documentation - Add builds to features list
1 parent 5189639 commit 21fb39f

3 files changed

Lines changed: 88 additions & 5 deletions

File tree

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Set up a git repo the way you actually work — one guided flow for hooks, `.git
3737
- **🧰 Hook management** — Install, list, show, or remove built-in hooks, or wire up your own command.
3838
- **🧩 Ignore and attribute presets** — Browse built-in and gitignore.io templates, then apply line-ending or binary presets.
3939
- **⚙️ Curated git config** — Apply practical presets with `--global` or `--local` scope, with idempotency detection.
40+
- **💾 Save & reuse builds** — Save configurations and apply them to any project with one command.
4041
- **📦 Single binary** — No Node.js, no Python, no extra runtime.
4142

4243
---
@@ -259,6 +260,30 @@ $ gitkit config apply defaults --global
259260
All configs already applied.
260261
```
261262

263+
### Build
264+
265+
Save and reuse configurations across projects.
266+
267+
| Command | Description |
268+
|---|---|
269+
| `gitkit build list` | List saved builds |
270+
| `gitkit build save <name>` | Save current repo config as a build |
271+
| `gitkit build apply <name>` | Apply a saved build |
272+
| `gitkit build delete <name>` | Delete a saved build |
273+
274+
**Example:**
275+
276+
```bash
277+
# Save current configuration
278+
gitkit build save rust-dev --description "Rust development setup"
279+
280+
# Apply to another project
281+
cd /path/to/other/project
282+
gitkit build apply rust-dev
283+
```
284+
285+
Builds are saved to `~/.gitkit/builds/` as TOML files.
286+
262287
---
263288

264289
## Built-in Hooks

src/builds/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ fn default_scope() -> String {
9191
"local".to_string()
9292
}
9393

94-
fn builds_dir() -> Result<PathBuf> {
94+
pub(crate) fn builds_dir() -> Result<PathBuf> {
9595
let home = std::env::var("HOME").context("HOME environment variable not set")?;
9696
Ok(PathBuf::from(home).join(".gitkit").join("builds"))
9797
}
@@ -262,7 +262,7 @@ fn save(name: &str, description: Option<&str>) -> Result<()> {
262262
anyhow::bail!("Build '{name}' already exists. Delete it first or choose another name.");
263263
}
264264

265-
let build = capture_current_config(name, description.unwrap_or(""))?;
265+
let build = capture_current_config(name, description)?;
266266

267267
let dir = builds_dir()?;
268268
fs::create_dir_all(&dir).context("Failed to create builds directory")?;
@@ -274,7 +274,7 @@ fn save(name: &str, description: Option<&str>) -> Result<()> {
274274
Ok(())
275275
}
276276

277-
pub(crate) fn capture_current_config(name: &str, description: &str) -> Result<Build> {
277+
pub(crate) fn capture_current_config(name: &str, description: Option<&str>) -> Result<Build> {
278278
let root = crate::utils::find_repo_root()?;
279279

280280
let mut builtins = Vec::new();
@@ -328,7 +328,7 @@ pub(crate) fn capture_current_config(name: &str, description: &str) -> Result<Bu
328328

329329
Ok(Build {
330330
name: name.to_string(),
331-
description: description.to_string(),
331+
description: description.unwrap_or("").to_string(),
332332
hooks: HooksConfig {
333333
builtins,
334334
custom: Vec::new(),

src/init.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use anyhow::Result;
22
use inquire::{MultiSelect, Select, Text};
33
use std::{collections::HashSet, fs};
44

5-
use crate::{attributes, config, git, hooks, ignore, utils::find_repo_root};
5+
use crate::{attributes, builds, config, git, hooks, ignore, utils::find_repo_root};
66

77
const BANNER: &str = r#"
88
███ █████ █████ ███ █████
@@ -28,6 +28,28 @@ pub fn run() -> Result<()> {
2828
println!("{BANNER}");
2929
println!(" Configure your git repo\n");
3030

31+
// ── Build selection ─────────────────────────────────────────────────────
32+
let saved_builds = builds::list_build_names();
33+
if !saved_builds.is_empty() {
34+
let mut options = vec!["Start fresh configuration".to_string()];
35+
options.extend(saved_builds.iter().map(|b| format!("Use build: {b}")));
36+
37+
let choice = Select::new("Saved builds available", options)
38+
.with_help_message("↑↓ move enter confirm")
39+
.prompt_skippable()?
40+
.unwrap_or_default();
41+
42+
if choice != "Start fresh configuration" {
43+
let build_name = choice.strip_prefix("Use build: ").unwrap_or(&choice);
44+
println!();
45+
let build = builds::load_build(build_name)?;
46+
builds::apply_build(&build)?;
47+
println!("\n Done\n");
48+
return Ok(());
49+
}
50+
println!();
51+
}
52+
3153
let cargo_available = std::process::Command::new("cargo")
3254
.arg("--version")
3355
.output()
@@ -255,6 +277,42 @@ pub fn run() -> Result<()> {
255277
}
256278
}
257279

280+
// ── Save as build ─────────────────────────────────────────────────────
281+
if nothing {
282+
println!("\n Nothing selected — exiting.");
283+
return Ok(());
284+
}
285+
286+
println!();
287+
let save_build = inquire::Confirm::new("Save this configuration as a reusable build?")
288+
.with_default(false)
289+
.prompt()?;
290+
291+
if save_build {
292+
let name = Text::new(" Build name").prompt()?;
293+
let description = Text::new(" Description (optional)")
294+
.with_default("")
295+
.prompt()?;
296+
let desc_ref = if description.is_empty() {
297+
None
298+
} else {
299+
Some(description.as_str())
300+
};
301+
builds::capture_current_config(&name, desc_ref)
302+
.and_then(|b| {
303+
let dir = builds::builds_dir()?;
304+
fs::create_dir_all(&dir)?;
305+
let path = dir.join(format!("{name}.toml"));
306+
let content = toml::to_string_pretty(&b)?;
307+
fs::write(&path, content)?;
308+
println!(" ✓ Build '{name}' saved");
309+
Ok(())
310+
})
311+
.unwrap_or_else(|e| {
312+
println!(" ⚠ Failed to save build: {e}");
313+
});
314+
}
315+
258316
println!("\n Done\n");
259317
Ok(())
260318
}

0 commit comments

Comments
 (0)