1
1
use super :: { get_head, utils:: repo, CommitId } ;
2
2
use crate :: error:: Result ;
3
3
use git2:: { ErrorCode , ObjectType , Repository , Signature } ;
4
+ use gpgme:: { Context , Protocol } ;
4
5
use scopetime:: scope_time;
5
6
6
7
///
@@ -54,6 +55,7 @@ pub fn commit(repo_path: &str, msg: &str) -> Result<CommitId> {
54
55
scope_time ! ( "commit" ) ;
55
56
56
57
let repo = repo ( repo_path) ?;
58
+ let config = repo. config ( ) ?;
57
59
58
60
let signature = signature_allow_undefined_name ( & repo) ?;
59
61
let mut index = repo. index ( ) ?;
@@ -68,16 +70,64 @@ pub fn commit(repo_path: &str, msg: &str) -> Result<CommitId> {
68
70
69
71
let parents = parents. iter ( ) . collect :: < Vec < _ > > ( ) ;
70
72
71
- Ok ( repo
72
- . commit (
73
+ let commit_oid = if config. get_bool ( "commit.gpgsign" ) ? {
74
+ // Generate commit content
75
+ let commit_bufffer = repo. commit_create_buffer (
76
+ & signature,
77
+ & signature,
78
+ msg,
79
+ & tree,
80
+ parents. as_slice ( ) ,
81
+ ) ?;
82
+ let commit_content =
83
+ commit_bufffer. as_str ( ) . expect ( "Buffer was not valid UTF-8" ) ;
84
+
85
+ // Prepare to sign using the designated key in the user's git config
86
+ let mut gpg_ctx = Context :: from_protocol ( Protocol :: OpenPgp ) ?;
87
+ let key = gpg_ctx. get_key ( config. get_string ( "user.signingkey" ) ?) ?;
88
+ gpg_ctx. add_signer ( & key) ?;
89
+ gpg_ctx. set_armor ( true ) ;
90
+
91
+ // Create GPG signature for commit content
92
+ let mut signature_buffer = Vec :: new ( ) ;
93
+ gpg_ctx. sign_detached ( & * commit_bufffer, & mut signature_buffer) ?;
94
+ let gpg_signature = std:: str:: from_utf8 ( & signature_buffer) . unwrap ( ) ;
95
+
96
+ let commit_oid =
97
+ repo. commit_signed ( & commit_content, & gpg_signature, None ) ?;
98
+
99
+ match repo. head ( ) {
100
+ // If HEAD reference is returned, simply update the target.
101
+ Ok ( mut head) => { head. set_target ( commit_oid, msg) ?; }
102
+ // If there is an error getting HEAD, likely it is a new repo
103
+ // and a reference to a default branch needs to be created.
104
+ Err ( _) => {
105
+ // Default branch name behavior as of git 2.28.
106
+ let default_branch_name =
107
+ config. get_str ( "init.defaultBranch" ) . unwrap_or ( "master" ) ;
108
+
109
+ repo. reference (
110
+ & format ! ( "refs/heads/{}" , default_branch_name) ,
111
+ commit_oid,
112
+ true ,
113
+ msg
114
+ ) ?;
115
+ }
116
+ }
117
+
118
+ commit_oid
119
+ } else {
120
+ repo. commit (
73
121
Some ( "HEAD" ) ,
74
122
& signature,
75
123
& signature,
76
124
msg,
77
125
& tree,
78
126
parents. as_slice ( ) ,
79
127
) ?
80
- . into ( ) )
128
+ } ;
129
+
130
+ Ok ( commit_oid. into ( ) )
81
131
}
82
132
83
133
/// Tag a commit.
0 commit comments