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