Unverified Commit 258115db by Edward Thomson Committed by GitHub

Merge pull request #6016 from libgit2/ethomson/commit_create_cb

Introduce `create_commit_cb`, deprecate `signing_cb`
parents 16a2e667 ef03e150
...@@ -503,25 +503,41 @@ GIT_EXTERN(int) git_commit_create_with_signature( ...@@ -503,25 +503,41 @@ GIT_EXTERN(int) git_commit_create_with_signature(
GIT_EXTERN(int) git_commit_dup(git_commit **out, git_commit *source); GIT_EXTERN(int) git_commit_dup(git_commit **out, git_commit *source);
/** /**
* Commit signing callback. * Commit creation callback: used when a function is going to create
* * commits (for example, in `git_rebase_commit`) to allow callers to
* The callback will be called with the commit content, giving a user an * override the commit creation behavior. For example, users may
* opportunity to sign the commit content. The signature_field * wish to sign commits by providing this information to
* buf may be left empty to specify the default field "gpgsig". * `git_commit_create_buffer`, signing that buffer, then calling
* * `git_commit_create_with_signature`. The resultant commit id
* Signatures can take the form of any string, and can be created on an arbitrary * should be set in the `out` object id parameter.
* header field. Signatures are most commonly used for verifying authorship of a *
* commit using GPG or a similar cryptographically secure signing algorithm. * @param out pointer that this callback will populate with the object
* See https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work for more * id of the commit that is created
* details. * @param author the author name and time of the commit
* * @param committer the committer name and time of the commit
* When the callback: * @param message_encoding the encoding of the given message, or NULL
* - returns GIT_PASSTHROUGH, no signature will be added to the commit. * to assume UTF8
* - returns < 0, commit creation will be aborted. * @param message the commit message
* - returns GIT_OK, the signature parameter is expected to be filled. * @param tree the tree to be committed
*/ * @param parent_count the number of parents for this commit
typedef int (*git_commit_signing_cb)( * @param parents the commit parents
git_buf *signature, git_buf *signature_field, const char *commit_content, void *payload); * @param payload the payload pointer in the rebase options
* @return 0 if this callback has created the commit and populated the out
* parameter, GIT_PASSTHROUGH if the callback has not created a
* commit and wants the calling function to create the commit as
* if no callback had been specified, any other value to stop
* and return a failure
*/
typedef int (*git_commit_create_cb)(
git_oid *out,
const git_signature *author,
const git_signature *committer,
const char *message_encoding,
const char *message,
const git_tree *tree,
size_t parent_count,
const git_commit *parents[],
void *payload);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -205,6 +205,27 @@ GIT_EXTERN(void) git_buf_free(git_buf *buffer); ...@@ -205,6 +205,27 @@ GIT_EXTERN(void) git_buf_free(git_buf *buffer);
/**@}*/ /**@}*/
/** @name Deprecated Commit Definitions
*/
/**@{*/
/**
* Provide a commit signature during commit creation.
*
* Callers should instead define a `git_commit_create_cb` that
* generates a commit buffer using `git_commit_create_buffer`, sign
* that buffer and call `git_commit_create_with_signature`.
*
* @deprecated use a `git_commit_create_cb` instead
*/
typedef int (*git_commit_signing_cb)(
git_buf *signature,
git_buf *signature_field,
const char *commit_content,
void *payload);
/**@}*/
/** @name Deprecated Config Functions and Constants /** @name Deprecated Config Functions and Constants
*/ */
/**@{*/ /**@{*/
......
...@@ -75,13 +75,37 @@ typedef struct { ...@@ -75,13 +75,37 @@ typedef struct {
git_checkout_options checkout_options; git_checkout_options checkout_options;
/** /**
* Optional callback that allows users to override commit
* creation in `git_rebase_commit`. If specified, users can
* create their own commit and provide the commit ID, which
* may be useful for signing commits or otherwise customizing
* the commit creation.
*
* If this callback returns `GIT_PASSTHROUGH`, then
* `git_rebase_commit` will continue to create the commit.
*/
git_commit_create_cb commit_create_cb;
#ifdef GIT_DEPRECATE_HARD
void *reserved;
#else
/**
* If provided, this will be called with the commit content, allowing * If provided, this will be called with the commit content, allowing
* a signature to be added to the rebase commit. Can be skipped with * a signature to be added to the rebase commit. Can be skipped with
* GIT_PASSTHROUGH. If GIT_PASSTHROUGH is returned, a commit will be made * GIT_PASSTHROUGH. If GIT_PASSTHROUGH is returned, a commit will be made
* without a signature. * without a signature.
*
* This field is only used when performing git_rebase_commit. * This field is only used when performing git_rebase_commit.
*
* This callback is not invoked if a `git_commit_create_cb` is
* specified.
*
* This callback is deprecated; users should provide a
* creation callback as `commit_create_cb` that produces a
* commit buffer, signs it, and commits it.
*/ */
git_commit_signing_cb signing_cb; int (*signing_cb)(git_buf *, git_buf *, const char *, void *);
#endif
/** /**
* This will be passed to each of the callbacks in this struct * This will be passed to each of the callbacks in this struct
......
...@@ -943,6 +943,54 @@ int git_rebase_inmemory_index( ...@@ -943,6 +943,54 @@ int git_rebase_inmemory_index(
return 0; return 0;
} }
#ifndef GIT_DEPRECATE_HARD
static int create_signed(
git_oid *out,
git_rebase *rebase,
const git_signature *author,
const git_signature *committer,
const char *message_encoding,
const char *message,
git_tree *tree,
size_t parent_count,
const git_commit **parents)
{
git_buf commit_content = GIT_BUF_INIT,
commit_signature = GIT_BUF_INIT,
signature_field = GIT_BUF_INIT;
int error;
git_error_clear();
if ((error = git_commit_create_buffer(&commit_content,
rebase->repo, author, committer, message_encoding,
message, tree, parent_count, parents)) < 0)
goto done;
error = rebase->options.signing_cb(&commit_signature,
&signature_field, commit_content.ptr,
rebase->options.payload);
if (error) {
if (error != GIT_PASSTHROUGH)
git_error_set_after_callback_function(error, "signing_cb");
goto done;
}
error = git_commit_create_with_signature(out, rebase->repo,
commit_content.ptr,
commit_signature.size > 0 ? commit_signature.ptr : NULL,
signature_field.size > 0 ? signature_field.ptr : NULL);
done:
git_buf_dispose(&commit_signature);
git_buf_dispose(&signature_field);
git_buf_dispose(&commit_content);
return error;
}
#endif
static int rebase_commit__create( static int rebase_commit__create(
git_commit **out, git_commit **out,
git_rebase *rebase, git_rebase *rebase,
...@@ -957,10 +1005,6 @@ static int rebase_commit__create( ...@@ -957,10 +1005,6 @@ static int rebase_commit__create(
git_commit *current_commit = NULL, *commit = NULL; git_commit *current_commit = NULL, *commit = NULL;
git_tree *parent_tree = NULL, *tree = NULL; git_tree *parent_tree = NULL, *tree = NULL;
git_oid tree_id, commit_id; git_oid tree_id, commit_id;
git_buf commit_content = GIT_BUF_INIT, commit_signature = GIT_BUF_INIT,
signature_field = GIT_BUF_INIT;
const char *signature_field_string = NULL,
*commit_signature_string = NULL;
int error; int error;
operation = git_array_get(rebase->operations, rebase->current); operation = git_array_get(rebase->operations, rebase->current);
...@@ -991,37 +1035,32 @@ static int rebase_commit__create( ...@@ -991,37 +1035,32 @@ static int rebase_commit__create(
message = git_commit_message(current_commit); message = git_commit_message(current_commit);
} }
if ((error = git_commit_create_buffer(&commit_content, rebase->repo, author, committer, git_error_clear();
message_encoding, message, tree, 1, (const git_commit **)&parent_commit)) < 0) error = GIT_PASSTHROUGH;
goto done;
if (rebase->options.signing_cb) { if (rebase->options.commit_create_cb) {
git_error_clear(); error = rebase->options.commit_create_cb(&commit_id,
error = git_error_set_after_callback_function(rebase->options.signing_cb( author, committer, message_encoding, message,
&commit_signature, &signature_field, git_buf_cstr(&commit_content), tree, 1, (const git_commit **)&parent_commit,
rebase->options.payload), "commit signing_cb failed"); rebase->options.payload);
if (error == GIT_PASSTHROUGH) {
git_buf_dispose(&commit_signature);
git_buf_dispose(&signature_field);
git_error_clear();
error = GIT_OK;
} else if (error < 0)
goto done;
}
if (git_buf_is_allocated(&commit_signature)) { git_error_set_after_callback_function(error,
GIT_ASSERT(git_buf_contains_nul(&commit_signature)); "commit_create_cb");
commit_signature_string = git_buf_cstr(&commit_signature);
} }
#ifndef GIT_DEPRECATE_HARD
if (git_buf_is_allocated(&signature_field)) { else if (rebase->options.signing_cb) {
GIT_ASSERT(git_buf_contains_nul(&signature_field)); error = create_signed(&commit_id, rebase, author,
signature_field_string = git_buf_cstr(&signature_field); committer, message_encoding, message, tree,
1, (const git_commit **)&parent_commit);
} }
#endif
if ((error = git_commit_create_with_signature(&commit_id, rebase->repo, if (error == GIT_PASSTHROUGH)
git_buf_cstr(&commit_content), commit_signature_string, error = git_commit_create(&commit_id, rebase->repo, NULL,
signature_field_string))) author, committer, message_encoding, message,
tree, 1, (const git_commit **)&parent_commit);
if (error)
goto done; goto done;
if ((error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0) if ((error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0)
...@@ -1033,9 +1072,6 @@ done: ...@@ -1033,9 +1072,6 @@ done:
if (error < 0) if (error < 0)
git_commit_free(commit); git_commit_free(commit);
git_buf_dispose(&commit_signature);
git_buf_dispose(&signature_field);
git_buf_dispose(&commit_content);
git_commit_free(current_commit); git_commit_free(current_commit);
git_tree_free(parent_tree); git_tree_free(parent_tree);
git_tree_free(tree); git_tree_free(tree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment