diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2021-09-13 08:17:21 -0400 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2021-09-18 08:32:41 -0400 |
commit | 6aa349667974a521dbe0c7e0f543f9086156689d (patch) | |
tree | 7a5de38fdd1aeaa35792a7b9db2b9ebcb6849078 | |
parent | 75d4676a64a73be937916361d2f0471055dec0e7 (diff) | |
download | libgit2-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.h | 35 | ||||
-rw-r--r-- | include/git2/sys/email.h | 45 | ||||
-rw-r--r-- | src/email.c | 108 | ||||
-rw-r--r-- | tests/email/create.c | 60 |
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) |