summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2021-09-13 08:17:21 -0400
committerEdward Thomson <ethomson@edwardthomson.com>2021-09-18 08:32:41 -0400
commit6aa349667974a521dbe0c7e0f543f9086156689d (patch)
tree7a5de38fdd1aeaa35792a7b9db2b9ebcb6849078
parent75d4676a64a73be937916361d2f0471055dec0e7 (diff)
downloadlibgit2-6aa349667974a521dbe0c7e0f543f9086156689d.tar.gz
email: introduce `git_email_create_from_diff`
Introduce a function to create an email from a diff and multiple inputs about the source of the diff. Creating an email from a diff requires many more inputs, and should be discouraged in favor of building directly from a commit, and is thus in the `sys` namespace.
-rw-r--r--include/git2/email.h35
-rw-r--r--include/git2/sys/email.h45
-rw-r--r--src/email.c108
-rw-r--r--tests/email/create.c60
4 files changed, 195 insertions, 53 deletions
diff --git a/include/git2/email.h b/include/git2/email.h
index 6014c6c7c..48715fe76 100644
--- a/include/git2/email.h
+++ b/include/git2/email.h
@@ -73,30 +73,39 @@ typedef struct {
/**
* Create a diff for a commit in mbox format for sending via email.
- * The commit must not be a merge commit.
*
* @param out buffer to store the e-mail patch in
- * @param commit commit to create a patch for
+ * @param diff the changes to include in the email
+ * @param patch_idx the patch index
+ * @param patch_count the total number of patches that will be included
+ * @param commit_id the commit id for this change
+ * @param summary the commit message for this change
+ * @param body optional text to include above the diffstat
+ * @param author the person who authored this commit
* @param opts email creation options
*/
-GIT_EXTERN(int) git_email_create_from_commit(
+GIT_EXTERN(int) git_email_create_from_diff(
git_buf *out,
- git_commit *commit,
+ git_diff *diff,
+ size_t patch_idx,
+ size_t patch_count,
+ const git_oid *commit_id,
+ const char *summary,
+ const char *body,
+ const git_signature *author,
const git_email_create_options *opts);
/**
- * Create an mbox format diff for the given commits in the revision
- * spec, excluding merge commits.
+ * Create a diff for a commit in mbox format for sending via email.
+ * The commit must not be a merge commit.
*
- * @param out buffer to store the e-mail patches in
- * @param commits the array of commits to create patches for
- * @param len the length of the `commits` array
+ * @param out buffer to store the e-mail patch in
+ * @param commit commit to create a patch for
* @param opts email creation options
*/
-GIT_EXTERN(int) git_email_create_from_commits(
- git_strarray *out,
- git_commit **commits,
- size_t len,
+GIT_EXTERN(int) git_email_create_from_commit(
+ git_buf *out,
+ git_commit *commit,
const git_email_create_options *opts);
GIT_END_DECL
diff --git a/include/git2/sys/email.h b/include/git2/sys/email.h
new file mode 100644
index 000000000..6f4a28662
--- /dev/null
+++ b/include/git2/sys/email.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_sys_git_email_h__
+#define INCLUDE_sys_git_email_h__
+
+/**
+ * @file git2/sys/email.h
+ * @brief Advanced git email creation routines
+ * @defgroup git_email Advanced git email creation routines
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Create a diff for a commit in mbox format for sending via email.
+ *
+ * @param out buffer to store the e-mail patch in
+ * @param diff the changes to include in the email
+ * @param patch_idx the patch index
+ * @param patch_count the total number of patches that will be included
+ * @param commit_id the commit id for this change
+ * @param summary the commit message for this change
+ * @param body optional text to include above the diffstat
+ * @param author the person who authored this commit
+ * @param opts email creation options
+ */
+GIT_EXTERN(int) git_email_create_from_diff(
+ git_buf *out,
+ git_diff *diff,
+ size_t patch_idx,
+ size_t patch_count,
+ const git_oid *commit_id,
+ const char *summary,
+ const char *body,
+ const git_signature *author,
+ const git_email_create_options *opts);
+
+/** @} */
+GIT_END_DECL
+#endif
diff --git a/src/email.c b/src/email.c
index b269dee67..b238f5b47 100644
--- a/src/email.c
+++ b/src/email.c
@@ -38,9 +38,6 @@ static int append_prefix(
const char *subject_prefix = opts->subject_prefix ?
opts->subject_prefix : "PATCH";
- if (!include_prefix(patch_count, opts))
- return 0;
-
git_buf_putc(out, '[');
if (*subject_prefix)
@@ -66,47 +63,65 @@ static int append_prefix(
patch_count + (start_number - 1));
}
- git_buf_puts(out, "] ");
+ git_buf_puts(out, "]");
return git_buf_oom(out) ? -1 : 0;
}
static int append_subject(
git_buf *out,
- git_commit *commit,
size_t patch_idx,
size_t patch_count,
+ const char *summary,
git_email_create_options *opts)
{
+ bool prefix = include_prefix(patch_count, opts);
+ size_t summary_len = summary ? strlen(summary) : 0;
int error;
- if ((error = git_buf_puts(out, "Subject: ")) < 0 ||
- (error = append_prefix(out, patch_idx, patch_count, opts)) < 0 ||
- (error = git_buf_puts(out, git_commit_summary(commit))) < 0 ||
- (error = git_buf_putc(out, '\n')) < 0)
+ if (summary_len) {
+ const char *nl = strchr(summary, '\n');
+
+ if (nl)
+ summary_len = (nl - summary);
+ }
+
+ if ((error = git_buf_puts(out, "Subject: ")) < 0)
return error;
- return 0;
+ if (prefix &&
+ (error = append_prefix(out, patch_idx, patch_count, opts)) < 0)
+ return error;
+
+ if (prefix && summary_len && (error = git_buf_putc(out, ' ')) < 0)
+ return error;
+
+ if (summary_len &&
+ (error = git_buf_put(out, summary, summary_len)) < 0)
+ return error;
+
+ return git_buf_putc(out, '\n');
}
static int append_header(
git_buf *out,
- git_commit *commit,
size_t patch_idx,
size_t patch_count,
+ const git_oid *commit_id,
+ const char *summary,
+ const git_signature *author,
git_email_create_options *opts)
{
- const git_signature *author = git_commit_author(commit);
char id[GIT_OID_HEXSZ];
char date[GIT_DATE_RFC2822_SZ];
int error;
- if ((error = git_oid_fmt(id, git_commit_id(commit))) < 0 ||
+ if ((error = git_oid_fmt(id, commit_id)) < 0 ||
(error = git_buf_printf(out, "From %.*s %s\n", GIT_OID_HEXSZ, id, EMAIL_TIMESTAMP)) < 0 ||
(error = git_buf_printf(out, "From: %s <%s>\n", author->name, author->email)) < 0 ||
(error = git__date_rfc2822_fmt(date, sizeof(date), &author->when)) < 0 ||
(error = git_buf_printf(out, "Date: %s\n", date)) < 0 ||
- (error = append_subject(out, commit, patch_idx, patch_count, opts)) < 0)
+ (error = append_subject(out, patch_idx, patch_count, summary, opts)) < 0)
return error;
if ((error = git_buf_putc(out, '\n')) < 0)
@@ -115,9 +130,8 @@ static int append_header(
return 0;
}
-static int append_body(git_buf *out, git_commit *commit)
+static int append_body(git_buf *out, const char *body)
{
- const char *body = git_commit_body(commit);
size_t body_len;
int error;
@@ -173,18 +187,25 @@ static int append_patches(git_buf *out, git_diff *diff)
return error;
}
-int git_email_create_from_commit(
+int git_email_create_from_diff(
git_buf *out,
- git_commit *commit,
+ git_diff *diff,
+ size_t patch_idx,
+ size_t patch_count,
+ const git_oid *commit_id,
+ const char *summary,
+ const char *body,
+ const git_signature *author,
const git_email_create_options *given_opts)
{
- git_diff *diff = NULL;
git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
- git_repository *repo;
- int error = 0;
+ int error;
GIT_ASSERT_ARG(out);
- GIT_ASSERT_ARG(commit);
+ GIT_ASSERT_ARG(diff);
+ GIT_ASSERT_ARG(!patch_idx || patch_idx <= patch_count);
+ GIT_ASSERT_ARG(commit_id);
+ GIT_ASSERT_ARG(author);
GIT_ERROR_CHECK_VERSION(given_opts,
GIT_EMAIL_CREATE_OPTIONS_VERSION,
@@ -196,16 +217,49 @@ int git_email_create_from_commit(
git_buf_sanitize(out);
git_buf_clear(out);
- repo = git_commit_owner(commit);
-
- if ((error = git_diff__commit(&diff, repo, commit, &opts.diff_opts)) == 0 &&
- (error = append_header(out, commit, 1, 1, &opts)) == 0 &&
- (error = append_body(out, commit)) == 0 &&
+ if ((error = append_header(out, patch_idx, patch_count, commit_id, summary, author, &opts)) == 0 &&
+ (error = append_body(out, body)) == 0 &&
(error = git_buf_puts(out, "---\n")) == 0 &&
(error = append_diffstat(out, diff)) == 0 &&
(error = append_patches(out, diff)) == 0)
error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n");
+ return error;
+}
+
+int git_email_create_from_commit(
+ git_buf *out,
+ git_commit *commit,
+ const git_email_create_options *opts)
+{
+ const git_diff_options *diff_opts;
+ git_diff *diff = NULL;
+ git_repository *repo;
+ const git_signature *author;
+ const char *summary, *body;
+ const git_oid *commit_id;
+ int error = -1;
+
+ GIT_ASSERT_ARG(out);
+ GIT_ASSERT_ARG(commit);
+
+ GIT_ERROR_CHECK_VERSION(opts,
+ GIT_EMAIL_CREATE_OPTIONS_VERSION,
+ "git_email_create_options");
+
+ repo = git_commit_owner(commit);
+ author = git_commit_author(commit);
+ summary = git_commit_summary(commit);
+ body = git_commit_body(commit);
+ commit_id = git_commit_id(commit);
+ diff_opts = opts ? &opts->diff_opts : NULL;
+
+ if ((error = git_diff__commit(&diff, repo, commit, diff_opts)) < 0)
+ goto done;
+
+ error = git_email_create_from_diff(out, diff, 1, 1, commit_id, summary, body, author, opts);
+
+done:
git_diff_free(diff);
return error;
}
diff --git a/tests/email/create.c b/tests/email/create.c
index 3a17ff59f..2b16d1da1 100644
--- a/tests/email/create.c
+++ b/tests/email/create.c
@@ -2,6 +2,7 @@
#include "clar_libgit2.h"
#include "buffer.h"
+#include "diff_generate.h"
static git_repository *repo;
@@ -111,27 +112,60 @@ void test_email_create__commit(void)
email, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", NULL);
}
-void test_email_create__mode_change(void)
+void test_email_create__custom_summary_and_body(void)
{
- const char *expected =
- "From 7ade76dd34bba4733cf9878079f9fd4a456a9189 Mon Sep 17 00:00:00 2001\n" \
- "From: Jacques Germishuys <jacquesg@striata.com>\n" \
- "Date: Thu, 10 Apr 2014 10:05:03 +0200\n" \
- "Subject: [PATCH] Update permissions\n" \
+ const char *expected = "From 627e7e12d87e07a83fad5b6bfa25e86ead4a5270 Mon Sep 17 00:00:00 2001\n" \
+ "From: Patrick Steinhardt <ps@pks.im>\n" \
+ "Date: Tue, 24 Nov 2015 13:34:39 +0100\n" \
+ "Subject: [PPPPPATCH 2/4] This is a subject\n" \
+ "\n" \
+ "Modify content of file3.txt by appending a new line. Make this\n" \
+ "commit message somewhat longer to test behavior with newlines\n" \
+ "embedded in the message body.\n" \
"\n" \
+ "Also test if new paragraphs are included correctly.\n" \
"---\n" \
- " file1.txt.renamed | 0\n" \
- " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \
- " mode change 100644 => 100755 file1.txt.renamed\n" \
+ " file3.txt | 1 +\n" \
+ " 1 file changed, 1 insertion(+)\n" \
"\n" \
- "diff --git a/file1.txt.renamed b/file1.txt.renamed\n" \
- "old mode 100644\n" \
- "new mode 100755\n" \
+ "diff --git a/file3.txt b/file3.txt\n" \
+ "index 9a2d780..7309653 100644\n" \
+ "--- a/file3.txt\n" \
+ "+++ b/file3.txt\n" \
+ "@@ -3,3 +3,4 @@ file3!\n" \
+ " file3\n" \
+ " file3\n" \
+ " file3\n" \
+ "+file3\n" \
"--\n" \
"libgit2 " LIBGIT2_VERSION "\n" \
"\n";
- assert_email_match(expected, "7ade76dd34bba4733cf9878079f9fd4a456a9189", NULL);
+ const char *summary = "This is a subject\nwith\nnewlines";
+ const char *body = "Modify content of file3.txt by appending a new line. Make this\n" \
+ "commit message somewhat longer to test behavior with newlines\n" \
+ "embedded in the message body.\n" \
+ "\n" \
+ "Also test if new paragraphs are included correctly.";
+
+ git_oid oid;
+ git_commit *commit = NULL;
+ git_diff *diff = NULL;
+ git_buf buf = GIT_BUF_INIT;
+ git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
+
+ opts.subject_prefix = "PPPPPATCH";
+
+ git_oid_fromstr(&oid, "627e7e12d87e07a83fad5b6bfa25e86ead4a5270");
+ cl_git_pass(git_commit_lookup(&commit, repo, &oid));
+ cl_git_pass(git_diff__commit(&diff, repo, commit, NULL));
+ cl_git_pass(git_email_create_from_diff(&buf, diff, 2, 4, &oid, summary, body, git_commit_author(commit), &opts));
+
+ cl_assert_equal_s(expected, git_buf_cstr(&buf));
+
+ git_diff_free(diff);
+ git_commit_free(commit);
+ git_buf_dispose(&buf);
}
void test_email_create__commit_subjects(void)