8000 hooks: commit-related wrappers · libgit2/libgit2@a466d92 · GitHub
[go: up one dir, main page]

Skip to content

Commit a466d92

Browse files
committed
hooks: commit-related wrappers
1 parent f4aeca4 commit a466d92

File tree

3 files changed

+309
-0
lines changed

3 files changed

+309
-0
lines changed

include/git2/hook.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,36 @@ GIT_EXTERN(int) git_hook_register_callback(
105105
git_hook_destructor_cb destructor,
106106
void *payload);
107107

108+
/**
109+
* Call the pre-commit hook, if available.
110+
*/
111+
GIT_EXTERN(int) git_hook_call_pre_commit(git_repository *repo);
112+
113+
/* modes for git_hook_call_prepare_commit_message */
114+
#define GIT_HOOK_PREPARE_COMMIT_MSG_MESSAGE "message"
115+
#define GIT_HOOK_PREPARE_COMMIT_MSG_TEMPLATE "template"
116+
#define GIT_HOOK_PREPARE_COMMIT_MSG_MERGE "merge"
117+
#define GIT_HOOK_PREPARE_COMMIT_MSG_SQUASH "squash"
118+
#define GIT_HOOK_PREPARE_COMMIT_MSG_COMMIT "commit"
119+
120+
/**
121+
* Call the prepare-commit-msg hook, with a plain text message.
122+
*/
123+
GIT_EXTERN(int) git_hook_call_prepare_commit_message(git_repository *repo, const char *mode, ...);
124+
125+
/**
126+
* Call the commit-msg hook, with the given commit message.
127+
*/
128+
GIT_EXTERN(int) git_hook_call_commit_msg(git_repository *repo, const char *message);
129+
130+
/**
131+
* Call the post-commit hook.
132+
*/
133+
GIT_EXTERN(int) git_hook_call_post_commit(git_repository *repo);
134+
135+
/**
136+
* Call the pre-rebase hook.
137+
*/
108138
GIT_EXTERN(int) git_hook_call_pre_rebase(
109139
git_repository *repo,
110140
const git_annotated_commit *upstream,

src/hook.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,176 @@ int git_hook_execute_io(git_buf *io, git_repository *repo, const char *hook_name
244244

245245
/** High-level hook calls */
246246

247+
int git_hook_call_pre_commit(git_repository *repo)
248+
{
249+
assert(repo);
250+
251+
return git_hook_execute(repo, "pre-commit", NULL);
252+
}
253+
254+
static int commit_message_file(git_buf *msg_path, git_repository *repo, const char *message, const char *file)
255+
{
256+
int err = 0;
257+
git_buf msg_buf = GIT_BUF_INIT;
258+
259+
assert(msg_path && repo && message && file);
260+
261+
git_buf_attach_notowned(&msg_buf, message, strlen(message));
262+
263+
if ((err = git_repository_item_path(msg_path, repo, GIT_REPOSITORY_ITEM_GITDIR)) != 0)
264+
goto cleanup;
265+
266+
if ((err = git_buf_joinpath(msg_path, git_buf_cstr(msg_path), file)) != 0)
267+
goto cleanup;
268+
269+
if ((err = git_futils_writebuffer(&msg_buf, git_buf_cstr(msg_path), O_CREAT|O_WRONLY, 0766)) != 0)
270+
goto cleanup;
271+
272+
cleanup:
273+
git_buf_dispose(&msg_buf);
274+
if (err != 0) {
275+
git_buf_dispose(msg_path);
276+
}
277+
278+
return err;
279+
}
280+
281+
int prepare_commit_msg__message(git_buf *msg_path, git_repository *repo, const char *message);
282+
int prepare_commit_msg__template(git_buf *msg_path, git_repository *repo, const char *template_file);
283+
int prepare_commit_msg__commit(git_buf *msg_path, git_repository *repo, const git_oid *oid);
284+
285+
int git_hook_call_prepare_commit_message(git_repository *repo, const char *mode, ...)
286+
{
287+
va_list args;
288+
int err = 0;
289+
git_buf msg_path = GIT_BUF_INIT;
290+
291+
assert(repo && mode);
292+
293+
va_start(args, mode);
294+
295+
if (git__strcmp(mode, GIT_HOOK_PREPARE_COMMIT_MSG_MESSAGE) == 0) {
296+
char *message = va_arg(args, char *);
297+
298+
if (message) {
299+
if ((err = prepare_commit_msg__message(&msg_path, repo, message)) != 0)
300+
goto cleanup;
301+
} else {
302+
if ((err = prepare_commit_msg__template(&msg_path, repo, NULL)) != 0)
303+
goto cleanup;
304+
305+
mode = GIT_HOOK_PREPARE_COMMIT_MSG_TEMPLATE;
306+
}
307+
} else if (git__strcmp(mode, GIT_HOOK_PREPARE_COMMIT_MSG_TEMPLATE) == 0) {
308+
if ((err = prepare_commit_msg__template(&msg_path, repo, va_arg(args, char *))) != 0)
309+
goto cleanup;
310+
} else if (git__strcmp(mode, GIT_HOOK_PREPARE_COMMIT_MSG_MERGE) == 0) {
311+
312+
} else if (git__strcmp(mode, GIT_HOOK_PREPARE_COMMIT_MSG_SQUASH) == 0) {
313+
314+
} else if (git__strcmp(mode, GIT_HOOK_PREPARE_COMMIT_MSG_COMMIT) == 0) {
315+
if ((err = prepare_commit_msg__commit(&msg_path, repo, va_arg(args, const git_oid *))) != 0)
316+
goto cleanup;
317+
} else {
318+
git_error_set(GIT_ERROR_HOOK, "prepare-commit-msg: unhandled mode %s", mode);
319+
err = -1;
320+
goto cleanup;
321+
}
322+
323+
err = git_hook_execute(repo, "prepare-commit-msg", git_buf_cstr(&msg_path), mode, NULL);
324+
325+
p_unlink(git_buf_cstr(&msg_path));
326+
327+
cleanup:
328+
git_buf_dispose(&msg_path);
329+
330+
va_end(args);
331+
332+
return err;
333+
}
334+
335+
int prepare_commit_msg__message(git_buf *msg_path, git_repository *repo, const char *message)
336+
{
337+
assert(repo);
338+
339+
if (message == NULL) {
340+
return prepare_commit_msg__template(msg_path, repo, NULL);
341+
}
342+
343+
return commit_message_file(msg_path, repo, message, "COMMIT_MSG");
344+
}
345+
346+
int prepare_commit_msg__template(git_buf *msg_path, git_repository *repo, const char *template_file)
347+
{
348+
int err = 0;
349+
git_buf tpl_path = GIT_BUF_INIT;
350+
git_buf tpl_msg = GIT_BUF_INIT;
351+
git_config *conf;
352+
353+
assert(repo);
354+
355+
if (template_file == NULL) {
356+
git_repository_config__weakptr(&conf, repo);
357+
git_config_get_path(&tpl_path, conf, "commit.template");
358+
} else {
359+
git_buf_puts(&tpl_path, template_file);
360+
}
361+
362+
git_futils_readbuffer(&tpl_msg, git_buf_cstr(&tpl_path));
363+
git_buf_dispose(&tpl_path);
364+
365+
err = commit_message_file(msg_path, repo, git_buf_cstr(&tpl_msg), "COMMIT_MSG");
366+
git_buf_dispose(&tpl_msg);
367+
368+
return err;
369+
}
370+
371+
int prepare_commit_msg__commit(git_buf *msg_path, git_repository *repo, const git_oid *oid)
372+
{
373+
int err = 0;
374+
git_commit *commit;
375+
376+
assert(repo);
377+
378+
if (oid == NULL) {
379+
return -1;
380+
}
381+
382+
if ((err = git_commit_lookup(&commit, repo, oid)) != 0)
383+
return -1;;
384+
385+
err = commit_message_file(msg_path, repo, git_commit_message_raw(commit), "COMMIT_MSG");
386+
git_commit_free(commit);
387+
388+
return err;
389+
}
390+
391+
int git_hook_call_commit_msg(git_repository *repo, const char *message)
392+
{
393+
int err = 0;
394+
git_buf msg_path = GIT_BUF_INIT;
395+
396+
assert(repo && message);
397+
398+
if ((err = commit_message_file(&msg_path, repo, message, "COMMIT_MSG")) != 0)
399+
goto cleanup;
400+
401+
err = git_hook_execute(repo, "commit-msg", git_buf_cstr(&msg_path), NULL);
402+
403+
p_unlink(git_buf_cstr(&msg_path));
404+
405+
cleanup:
406+
git_buf_dispose(&msg_path);
407+
return err;
408+
}
409+
410+
int git_hook_call_post_commit(git_repository *repo)
411+
{
412+
assert(repo);
413+
414+
return git_hook_execute(repo, "post-commit", NULL);
415+
}
416+
247417
int git_hook_call_pre_rebase(git_repository *repo, const git_annotated_commit *upstream, const git_annotated_commit *rebased)
248418
{
249419
int err = 0;

tests/hook/call.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,112 @@ void test_hook_call__pre_rebase_hook(void)
6969
git_reference_free(upstream_ref);
7070
git_rebase_free(rebase);
7171
}
72+
73+
struct hook_data {
74+
int calls;
75+
git_strarray args;
76+
};
77+
78+
static void cl_git_hook_check_(git_hook_env *env, struct hook_data *data)
79+
{
80+
size_t arg_id;
81+
82+
(data->calls)++;
83+
84+
cl_assert_equal_i(env->args.count, data->args.count);
85+
86+
for (arg_id = 0; arg_id < data->args.count; arg_id++)
87+
cl_assert_equal_s(data->args.strings[arg_id], env->args.strings[arg_id]);
88+
}
89+
90+
#define cl_git_hook_check(env, data) cl_git_hook_check_(env, data)
91+
92+
int hook_exec__check(git_hook_env *env, void *payload)
93+
{
94+
cl_git_hook_check(env, payload);
95+
return 0;
96+
}
97+
98+
void test_hook_call__pre_commit(void)
99+
{
100+
struct hook_data data = {0, {NULL, 0}};
101+
102+
make_dummy_hook("pre-commit");
103+
cl_git_pass(git_hook_register_callback(g_repo, hook_exec__check, NULL, &data));
104+
105+
cl_git_pass(git_hook_call_pre_commit(g_repo));
106+
cl_assert_equal_i(data.calls, 1);
107+
}
108+
109+
void test_hook_call__prepare_commit_message(void)
110+
{
111+
git_buf path = GIT_BUF_INIT;
112+
char *args_str[2];
113+
struct hook_data data = {0, {args_str, 2}};
114+
115+
git_buf_sets(&path, git_repository_path(g_repo));
116+
git_buf_joinpath(&path, path.ptr, "COMMIT_MSG");
117+
118+
args_str[0] = path.ptr;
119+
args_str[1] = "message";
120+
121+
make_dummy_hook("prepare-commit-msg");
122+
cl_git_pass(git_hook_register_callback(g_repo, hook_exec__check, NULL, &data));
123+
124+
cl_git_pass(git_hook_call_prepare_commit_message(g_repo, GIT_HOOK_PREPARE_COMMIT_MSG_MESSAGE, "nice message"));
125+
cl_assert_equal_i(data.calls, 1);
126+
127+
git_buf_dispose(&path);
128+
}
129+
130+
void test_hook_call__prepare_commit_template(void)
131+
{
132+
git_buf path = GIT_BUF_INIT;
133+
char *args_str[2];
134+
struct hook_data data = {0, {args_str, 2}};
135+
136+
git_buf_sets(&path, git_repository_path(g_repo));
137+
git_buf_joinpath(&path, path.ptr, "COMMIT_MSG");
138+
139+
args_str[0] = path.ptr;
140+
args_str[1] = "template";
141+
142+
make_dummy_hook("prepare-commit-msg");
143+
cl_git_pass(git_hook_register_callback(g_repo, hook_exec__check, NULL, &data));
144+
145+
cl_git_pass(git_hook_call_prepare_commit_message(g_repo, GIT_HOOK_PREPARE_COMMIT_MSG_TEMPLATE, "tmpl-file.txt"));
146+
cl_assert_equal_i(data.calls, 1);
147+
148+
git_buf_dispose(&path);
149+
}
150+
151+
void test_hook_call__commit_msg(void)
152+
{
153+
git_buf path = GIT_BUF_INIT;
154+
char *args_str[1];
155+
struct hook_data data = {0, {args_str, 1}};
156+
157+
git_buf_sets(&path, git_repository_path(g_repo));
158+
git_buf_joinpath(&path, path.ptr, "COMMIT_MSG");
159+
160+
args_str[0] = path.ptr;
161+
162+
make_dummy_hook("commit-msg");
163+
cl_git_pass(git_hook_register_callback(g_repo, hook_exec__check, NULL, &data));
164+
165+
cl_git_pass(git_hook_call_commit_msg(g_repo, "my message"));
166+
cl_assert_equal_i(data.calls, 1);
167+
168+
git_buf_dispose(&path);
169+
}
170+
171+
void test_hook_call__post_commit(void)
172+
{
173+
struct hook_data data = {0, {NULL, 0}};
174+
175+
make_dummy_hook("post-commit");
176+
cl_git_pass(git_hook_register_callback(g_repo, hook_exec__check, NULL, &data));
177+
178+
cl_git_pass(git_hook_call_post_commit(g_repo));
179+
cl_assert_equal_i(data.calls, 1);
180+
}

0 commit comments

Comments
 (0)
0