1 /*
2 * Copyright (C) 2015 Obeo. and others
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Distribution License v. 1.0 which is available at
6 * https://www.eclipse.org/org/documents/edl-v10.php.
7 *
8 * SPDX-License-Identifier: BSD-3-Clause
9 */
10 package org.eclipse.jgit.hooks;
11
12 import java.io.File;
13 import java.io.IOException;
14 import java.io.PrintStream;
15
16 import org.eclipse.jgit.api.errors.AbortedByHookException;
17 import org.eclipse.jgit.lib.Constants;
18 import org.eclipse.jgit.lib.Repository;
19
20 /**
21 * The <code>commit-msg</code> hook implementation. This hook is run before the
22 * commit and can reject the commit. It passes one argument to the hook script,
23 * which is the path to the COMMIT_MSG file, relative to the repository
24 * workTree.
25 *
26 * @since 4.0
27 */
28 public class CommitMsgHook extends GitHook<String> {
29
30 /**
31 * Constant indicating the name of the commit-smg hook.
32 */
33 public static final String NAME = "commit-msg"; //$NON-NLS-1$
34
35 /**
36 * The commit message.
37 */
38 private String commitMessage;
39
40 /**
41 * Constructor for CommitMsgHook
42 * <p>
43 * This constructor will use the default error stream.
44 * </p>
45 *
46 * @param repo
47 * The repository
48 * @param outputStream
49 * The output stream the hook must use. {@code null} is allowed,
50 * in which case the hook will use {@code System.out}.
51 */
52 protected CommitMsgHook(Repository repo, PrintStream outputStream) {
53 super(repo, outputStream);
54 }
55
56 /**
57 * Constructor for CommitMsgHook
58 *
59 * @param repo
60 * The repository
61 * @param outputStream
62 * The output stream the hook must use. {@code null} is allowed,
63 * in which case the hook will use {@code System.out}.
64 * @param errorStream
65 * The error stream the hook must use. {@code null} is allowed,
66 * in which case the hook will use {@code System.err}.
67 * @since 5.6
68 */
69 protected CommitMsgHook(Repository repo, PrintStream outputStream,
70 PrintStream errorStream) {
71 super(repo, outputStream, errorStream);
72 }
73
74 /** {@inheritDoc} */
75 @Override
76 public String call() throws IOException, AbortedByHookException {
77 if (commitMessage == null) {
78 throw new IllegalStateException();
79 }
80 if (canRun()) {
81 getRepository().writeCommitEditMsg(commitMessage);
82 doRun();
83 commitMessage = getRepository().readCommitEditMsg();
84 }
85 return commitMessage;
86 }
87
88 /**
89 * @return {@code true} if and only if the path to the message commit file
90 * is not null (which would happen in a bare repository) and the
91 * commit message is also not null.
92 */
93 private boolean canRun() {
94 return getCommitEditMessageFilePath() != null && commitMessage != null;
95 }
96
97 /** {@inheritDoc} */
98 @Override
99 public String getHookName() {
100 return NAME;
101 }
102
103 /**
104 * {@inheritDoc}
105 *
106 * This hook receives one parameter, which is the path to the file holding
107 * the current commit-msg, relative to the repository's work tree.
108 */
109 @Override
110 protected String[] getParameters() {
111 return new String[] { getCommitEditMessageFilePath() };
112 }
113
114 /**
115 * @return The path to the commit edit message file relative to the
116 * repository's work tree, or null if the repository is bare.
117 */
118 private String getCommitEditMessageFilePath() {
119 File gitDir = getRepository().getDirectory();
120 if (gitDir == null) {
121 return null;
122 }
123 return Repository.stripWorkDir(getRepository().getWorkTree(), new File(
124 gitDir, Constants.COMMIT_EDITMSG));
125 }
126
127 /**
128 * It is mandatory to call this method with a non-null value before actually
129 * calling the hook.
130 *
131 * @param commitMessage
132 * The commit message before the hook has run.
133 * @return {@code this} for convenience.
134 */
135 public CommitMsgHook setCommitMessage(String commitMessage) {
136 this.commitMessage = commitMessage;
137 return this;
138 }
139
140 }