1use anyhow::{Result, bail};
2use std::process::Command;
3
4mod commits;
5mod detect;
6mod github_api;
7mod remote;
8mod semver;
9mod status;
10mod tags;
11
12#[cfg(test)]
13mod tests;
14
15pub use commits::{
16 Commit, add_path_in, commit_in, get_all_commits, get_all_commits_paths,
17 get_commit_messages_between, get_commit_messages_between_path, get_commits_between,
18 get_commits_between_paths, get_current_branch, get_head_commit, get_last_commit_messages,
19 get_last_commit_messages_path, get_short_commit, has_changes_since, has_commits_since_tag,
20 log_subjects_for_range, paths_changed_since_tag, stage_and_commit,
21};
22pub use detect::{GitInfo, detect_git_info};
23pub use github_api::{create_tag_via_github_api, gh_api_get, gh_api_get_paginated};
24pub use remote::{
25 detect_github_repo, detect_owner_repo, parse_github_remote, parse_remote_owner_repo,
26};
27pub use semver::{SemVer, parse_semver, parse_semver_tag};
28pub use status::{
29 check_git_available, git_status_porcelain, is_git_dirty, is_git_repo, is_shallow_clone,
30 local_git_user_email, local_git_user_name,
31};
32pub use tags::{
33 create_and_push_tag, extract_tag_prefix, find_latest_tag_matching,
34 find_latest_tag_matching_with_prefix, find_previous_tag, find_previous_tag_with_prefix,
35 get_all_semver_tags, get_branch_semver_tags, get_first_commit, has_version_placeholder,
36 list_tags_with_prefix, render_ignore_patterns, strip_monorepo_prefix, tag_points_at_head,
37};
38
39fn git_output(args: &[&str]) -> Result<String> {
50 let output = Command::new("git").args(args).output()?;
51 if !output.status.success() {
52 let stderr_raw = String::from_utf8_lossy(&output.stderr);
53 let raw = format!("git {} failed: {}", args.join(" "), stderr_raw.trim());
54 bail!("{}", crate::redact::redact_process_env(&raw));
55 }
56 Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
57}