1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.scm.provider.git.jgit.command.checkin;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.net.InetAddress;
24 import java.net.UnknownHostException;
25 import java.util.Collections;
26 import java.util.EnumSet;
27 import java.util.List;
28 import java.util.Optional;
29 import java.util.Set;
30 import java.util.function.BiFunction;
31
32 import org.apache.commons.lang3.StringUtils;
33 import org.apache.maven.scm.CommandParameter;
34 import org.apache.maven.scm.CommandParameters;
35 import org.apache.maven.scm.ScmException;
36 import org.apache.maven.scm.ScmFile;
37 import org.apache.maven.scm.ScmFileSet;
38 import org.apache.maven.scm.ScmVersion;
39 import org.apache.maven.scm.command.checkin.AbstractCheckInCommand;
40 import org.apache.maven.scm.command.checkin.CheckInScmResult;
41 import org.apache.maven.scm.provider.ScmProviderRepository;
42 import org.apache.maven.scm.provider.git.command.GitCommand;
43 import org.apache.maven.scm.provider.git.jgit.command.CustomizableSshSessionFactoryCommand;
44 import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
45 import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
46 import org.apache.maven.scm.provider.git.jgit.command.PushException;
47 import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
48 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
49 import org.apache.maven.scm.provider.git.util.GitUtil;
50 import org.eclipse.jgit.api.AddCommand;
51 import org.eclipse.jgit.api.CommitCommand;
52 import org.eclipse.jgit.api.Git;
53 import org.eclipse.jgit.api.Status;
54 import org.eclipse.jgit.api.TransportConfigCallback;
55 import org.eclipse.jgit.api.errors.GitAPIException;
56 import org.eclipse.jgit.lib.Constants;
57 import org.eclipse.jgit.lib.UserConfig;
58 import org.eclipse.jgit.revwalk.RevCommit;
59 import org.eclipse.jgit.transport.RefSpec;
60 import org.eclipse.jgit.transport.RemoteRefUpdate;
61 import org.slf4j.Logger;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public class JGitCheckInCommand extends AbstractCheckInCommand
81 implements GitCommand, CustomizableSshSessionFactoryCommand {
82
83 protected static final String GIT_MAVEN_SECTION = "maven-scm";
84
85 protected static final String GIT_MAILDOMAIN = "maildomain";
86
87 protected static final String GIT_FORCE = "forceUsername";
88
89 private BiFunction<GitScmProviderRepository, Logger, ScmProviderAwareSshdSessionFactory> sshSessionFactorySupplier;
90
91 public JGitCheckInCommand() {
92 sshSessionFactorySupplier = ScmProviderAwareSshdSessionFactory::new;
93 }
94
95 @Override
96 public void setSshSessionFactorySupplier(
97 BiFunction<GitScmProviderRepository, Logger, ScmProviderAwareSshdSessionFactory>
98 sshSessionFactorySupplier) {
99 this.sshSessionFactorySupplier = sshSessionFactorySupplier;
100 }
101
102 @Override
103 public CheckInScmResult executeCommand(ScmProviderRepository repo, ScmFileSet fileSet, CommandParameters parameters)
104 throws ScmException {
105 String message = parameters.getString(CommandParameter.MESSAGE);
106
107 ScmVersion version = parameters.getScmVersion(CommandParameter.SCM_VERSION, null);
108
109 Git git = null;
110 try {
111 File basedir = fileSet.getBasedir();
112 git = JGitUtils.openRepo(basedir);
113
114 boolean doCommit = false;
115
116 if (!fileSet.getFileList().isEmpty()) {
117
118 doCommit = JGitUtils.addAllFiles(git, fileSet).size() > 0;
119 if (!doCommit) {
120 Status status = git.status().call();
121 doCommit = status.getAdded().size() > 0
122 || status.getChanged().size() > 0
123 || status.getRemoved().size() > 0;
124 }
125 } else {
126
127 Status status = git.status().call();
128 Set<String> changeds = git.status().call().getModified();
129 if (changeds.isEmpty()) {
130 if (!status.hasUncommittedChanges()) {
131
132 logger.warn("There are neither files to be added nor any uncommitted changes");
133 doCommit = false;
134 } else {
135 logger.debug("There are uncommitted changes in the git index");
136 doCommit = true;
137 }
138 } else {
139
140 AddCommand add = git.add();
141 for (String changed : changeds) {
142 logger.debug("Add manually: {}", changed);
143 add.addFilepattern(changed);
144 doCommit = true;
145 }
146 add.call();
147 }
148 }
149
150 List<ScmFile> checkedInFiles = Collections.emptyList();
151 if (doCommit) {
152 UserInfo author = getAuthor(repo, git);
153 UserInfo committer = getCommitter(repo, git);
154
155 CommitCommand command = git.commit()
156 .setMessage(message)
157 .setAuthor(author.name, author.email)
158 .setCommitter(committer.name, committer.email);
159 if (GitUtil.getSettings().isCommitNoVerify()) {
160 command.setNoVerify(true);
161 }
162 RevCommit commitRev = command.call();
163
164 logger.debug("commit done: " + commitRev.getShortMessage());
165 checkedInFiles = JGitUtils.getFilesInCommit(git.getRepository(), commitRev, fileSet.getBasedir());
166 if (logger.isDebugEnabled()) {
167 for (ScmFile scmFile : checkedInFiles) {
168 logger.debug("in commit: " + scmFile);
169 }
170 }
171 } else {
172 logger.info("nothing to commit");
173 }
174
175 if (repo.isPushChanges()) {
176 String branch = version != null ? version.getName() : null;
177 if (StringUtils.isBlank(branch)) {
178 branch = git.getRepository().getBranch();
179 }
180 RefSpec refSpec = new RefSpec(Constants.R_HEADS + branch + ":" + Constants.R_HEADS + branch);
181 logger.info("push changes to remote... " + refSpec);
182 TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback(
183 sshSessionFactorySupplier.apply((GitScmProviderRepository) repo, logger));
184
185 JGitUtils.push(
186 git,
187 (GitScmProviderRepository) repo,
188 refSpec,
189 EnumSet.of(RemoteRefUpdate.Status.OK, RemoteRefUpdate.Status.UP_TO_DATE),
190 Optional.of(transportConfigCallback));
191 }
192
193 return new CheckInScmResult("JGit checkin", checkedInFiles);
194 } catch (PushException e) {
195 logger.debug("Failed to push commits", e);
196 return new CheckInScmResult("JGit checkin", "Failed to push changes: " + e.getMessage(), "", false);
197 } catch (IOException | GitAPIException e) {
198 throw new ScmException("JGit checkin failure!", e);
199 } finally {
200 JGitUtils.closeRepo(git);
201 }
202 }
203
204
205
206
207 protected CheckInScmResult executeCheckInCommand(
208 ScmProviderRepository repo, ScmFileSet fileSet, String message, ScmVersion version) throws ScmException {
209
210 CommandParameters parameters = new CommandParameters();
211 parameters.setString(CommandParameter.MESSAGE, message);
212 parameters.setScmVersion(CommandParameter.SCM_VERSION, version);
213 return executeCommand(repo, fileSet, parameters);
214 }
215
216 private static final class UserInfo {
217
218 final String name;
219
220 final String email;
221
222 UserInfo(String name, String email) {
223 this.name = name;
224 this.email = email;
225 }
226 }
227
228 private UserInfo getCommitter(ScmProviderRepository repo, Git git) {
229 boolean forceMvnUser = git.getRepository().getConfig().getBoolean(GIT_MAVEN_SECTION, GIT_FORCE, false);
230
231
232 UserConfig user = git.getRepository().getConfig().get(UserConfig.KEY);
233 String committerName = null;
234 if (!forceMvnUser && !user.isCommitterNameImplicit()) {
235 committerName = user.getCommitterName();
236 }
237
238
239 if (StringUtils.isBlank(committerName)) {
240 committerName = repo.getUser();
241 }
242
243
244 if (StringUtils.isBlank(committerName)) {
245 committerName = user.getCommitterName();
246 }
247
248
249 String committerMail = null;
250 if (!user.isCommitterEmailImplicit()) {
251 committerMail = user.getCommitterEmail();
252 }
253
254 if (StringUtils.isBlank(committerMail)) {
255 String defaultDomain = git.getRepository().getConfig().getString(GIT_MAVEN_SECTION, null, GIT_MAILDOMAIN);
256 defaultDomain = StringUtils.isNotBlank(defaultDomain) ? defaultDomain : getHostname();
257
258
259 committerMail = StringUtils.isNotBlank(repo.getUser())
260 ? repo.getUser() + "@" + defaultDomain
261 : user.getCommitterEmail();
262 }
263
264 return new UserInfo(committerName, committerMail);
265 }
266
267 private UserInfo getAuthor(ScmProviderRepository repo, Git git) {
268 boolean forceMvnUser = git.getRepository().getConfig().getBoolean(GIT_MAVEN_SECTION, GIT_FORCE, false);
269
270
271 UserConfig user = git.getRepository().getConfig().get(UserConfig.KEY);
272 String authorName = null;
273 if (!forceMvnUser && !user.isAuthorNameImplicit()) {
274 authorName = user.getAuthorName();
275 }
276
277
278 if (StringUtils.isBlank(authorName)) {
279 authorName = repo.getUser();
280 }
281
282
283 if (StringUtils.isBlank(authorName)) {
284 authorName = user.getAuthorName();
285 }
286
287
288 String authorMail = null;
289 if (!user.isAuthorEmailImplicit()) {
290 authorMail = user.getAuthorEmail();
291 }
292
293 if (StringUtils.isBlank(authorMail)) {
294 String defaultDomain = git.getRepository().getConfig().getString(GIT_MAVEN_SECTION, null, GIT_MAILDOMAIN);
295 defaultDomain = StringUtils.isNotBlank(defaultDomain) ? defaultDomain : getHostname();
296
297
298 authorMail = StringUtils.isNotBlank(repo.getUser())
299 ? repo.getUser() + "@" + defaultDomain
300 : user.getAuthorEmail();
301 }
302
303 return new UserInfo(authorName, authorMail);
304 }
305
306 private String getHostname() {
307 String hostname;
308 try {
309 InetAddress localhost = java.net.InetAddress.getLocalHost();
310 hostname = localhost.getHostName();
311 } catch (UnknownHostException e) {
312 logger.warn(
313 "failed to resolve hostname to create mail address, " + "defaulting to 'maven-scm-provider-jgit'");
314 hostname = "maven-scm-provider-jgit";
315 }
316 return hostname;
317 }
318 }