kodegen_tools_git/operations/push/mod.rs
1//! Git push operations
2//!
3//! Provides functionality for pushing commits and tags to remote repositories.
4//! Uses native git CLI since gix doesn't yet support push operations.
5//!
6//! **Dependency**: Requires git to be installed and available in PATH.
7//!
8//! # Authentication
9//!
10//! This module relies on git's configured authentication methods. Authentication
11//! configuration is critical for production use to avoid hangs, timeouts, and failures.
12//!
13//! ## SSH (Recommended for automation)
14//!
15//! SSH authentication requires keys to be properly configured and loaded:
16//! - SSH keys must be loaded in ssh-agent
17//! - Or SSH key must not have a passphrase
18//! - Respects user's `~/.ssh/config` settings
19//! - Environment variable: `SSH_AUTH_SOCK` (set by ssh-agent)
20//!
21//! **Setup for CI/CD:**
22//! ```bash
23//! # Start SSH agent and add key
24//! eval "$(ssh-agent -s)"
25//! ssh-add ~/.ssh/id_rsa
26//!
27//! # Or disable strict host checking for CI
28//! export GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no"
29//! ```
30//!
31//! ## HTTPS
32//!
33//! HTTPS authentication requires credential configuration:
34//! - Credential helper: `git config --global credential.helper store`
35//! - Or environment variables: `GIT_ASKPASS`, `GIT_USERNAME`, `GIT_PASSWORD`
36//! - Or credentials stored in git config (not recommended for security)
37//!
38//! **WARNING**: HTTPS push will fail with an error if credentials are needed
39//! because `GIT_TERMINAL_PROMPT=0` is set by this implementation to prevent
40//! hanging on password prompts in automation scenarios.
41//!
42//! ## Preventing Hangs in CI/CD
43//!
44//! This implementation sets `GIT_TERMINAL_PROMPT=0` to prevent git from prompting
45//! for credentials, which would cause indefinite hangs in automated environments.
46//! If authentication is not properly configured, the push will fail immediately
47//! rather than hang.
48//!
49//! **Recommended practices:**
50//! ```rust
51//! use std::env;
52//!
53//! // For SSH in CI/CD environments
54//! env::set_var("GIT_SSH_COMMAND", "ssh -o StrictHostKeyChecking=no");
55//!
56//! // For HTTPS with credential helper
57//! // Run: git config --global credential.helper store
58//! // Or set GIT_ASKPASS to a script that provides credentials
59//! ```
60//!
61//! # Examples
62//!
63//! ## CI/CD Setup (GitHub Actions)
64//!
65//! ```yaml
66//! # Using SSH with GitHub Actions
67//! - name: Setup SSH
68//! uses: webfactory/ssh-agent@v0.5.4
69//! with:
70//! ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
71//!
72//! # Using HTTPS with personal access token
73//! - name: Configure Git Credentials
74//! run: |
75//! git config --global credential.helper store
76//! echo "https://${{ secrets.GITHUB_TOKEN }}@github.com" > ~/.git-credentials
77//! ```
78//!
79//! ## Local Development
80//!
81//! ```bash
82//! # SSH authentication (recommended)
83//! eval "$(ssh-agent -s)"
84//! ssh-add ~/.ssh/id_rsa
85//!
86//! # HTTPS with credential helper
87//! git config --global credential.helper store
88//! # First push will prompt for credentials, then store them
89//!
90//! # HTTPS with personal access token
91//! git config --global credential.helper 'store --file ~/.git-credentials'
92//! echo "https://username:token@github.com" > ~/.git-credentials
93//! chmod 600 ~/.git-credentials
94//! ```
95//!
96//! # Troubleshooting
97//!
98//! ## "Failed to authenticate" or "Permission denied"
99//! - Verify SSH key is loaded: `ssh-add -l`
100//! - Test SSH connection: `ssh -T git@github.com`
101//! - Check credential helper: `git config --get credential.helper`
102//!
103//! ## "Operation timed out"
104//! - Check network connectivity to remote
105//! - Verify remote URL is correct: `git remote -v`
106//! - Increase timeout via `PushOpts.timeout_secs`
107//!
108//! ## "Authentication required" in CI/CD
109//! - Ensure SSH key is added to ssh-agent in CI workflow
110//! - Or configure HTTPS credential helper before push
111//! - Verify `GIT_SSH_COMMAND` or `GIT_ASKPASS` environment variables
112//!
113//! For more details, see:
114//! - [Git Credential Storage](https://git-scm.com/docs/gitcredentials)
115//! - [Git SSH Configuration](https://git-scm.com/docs/git-config#Documentation/git-config.txt-coresshCommand)
116
117mod core;
118mod delete;
119mod check;
120
121pub use core::{push, push_current_branch, push_tags};
122pub use delete::{delete_remote_tag, delete_remote_branch};
123pub use check::{check_remote_branch_exists, check_remote_tag_exists};
124
125/// Options for push operation
126#[derive(Debug, Clone)]
127pub struct PushOpts {
128 /// Remote name (defaults to "origin")
129 pub remote: String,
130 /// Refspecs to push (empty means current branch)
131 pub refspecs: Vec<String>,
132 /// Force push
133 pub force: bool,
134 /// Push all tags
135 pub tags: bool,
136 /// Timeout in seconds (default: 300)
137 pub timeout_secs: Option<u64>,
138}
139
140impl Default for PushOpts {
141 fn default() -> Self {
142 Self {
143 remote: "origin".to_string(),
144 refspecs: Vec::new(),
145 force: false,
146 tags: false,
147 timeout_secs: None,
148 }
149 }
150}
151
152/// Result of push operation
153#[derive(Debug, Clone)]
154pub struct PushResult {
155 /// Number of refs (branches/tags) successfully pushed
156 ///
157 /// Note: This counts the number of ref updates, not individual commits.
158 /// For example, pushing a branch with 5 commits counts as 1 ref update.
159 pub commits_pushed: usize,
160
161 /// Number of tags pushed (conservative estimate)
162 ///
163 /// **Note:** Returns 1 when `--tags` is used and push succeeds, or counts
164 /// the number of `refs/tags/*` refspecs provided. Does not parse git output
165 /// for exact count due to fragility. Sufficient for most telemetry use cases.
166 pub tags_pushed: usize,
167
168 /// Any warnings or messages
169 pub warnings: Vec<String>,
170}