Skip to main content

git_claw/workflow/
tag.rs

1//! SemVer release tag manager.
2
3use crate::cli::output::print_success;
4use crate::core::config::Config;
5use crate::core::semver::validate_semver;
6use crate::infra::git::{
7    git_create_annotated_tag, git_is_clean, resolve_repo_name, resolve_toplevel,
8};
9use crate::workflow::error::WorkflowError;
10use std::path::Path;
11
12pub struct TagOptions<'a> {
13    pub version: &'a str,
14    pub repo_root: Option<&'a Path>,
15}
16
17/// Validates SemVer, checks clean trunk, and creates an annotated Git release tag.
18pub fn tag_release(options: TagOptions<'_>) -> Result<(), WorkflowError> {
19    if !validate_semver(options.version) {
20        return Err(WorkflowError::InvalidSemVer(options.version.to_string()));
21    }
22
23    let toplevel = resolve_toplevel(options.repo_root)?;
24    let repo_name = resolve_repo_name(&toplevel);
25
26    let config_path = toplevel.join(".git-claw.toml");
27    let config = Config::load_or_default(&config_path, &repo_name)?;
28
29    if !git_is_clean(&toplevel)? {
30        return Err(WorkflowError::DirtyWorkingTree);
31    }
32
33    let message = format!("Release {}", options.version);
34    git_create_annotated_tag(&toplevel, options.version, config.main_branch(), &message)?;
35
36    print_success(format!(
37        "Created annotated release tag '{}' on branch '{}'",
38        options.version,
39        config.main_branch()
40    ));
41
42    Ok(())
43}