View Javadoc
1   package org.apache.maven.scm.provider.git.jgit.command.checkin;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.scm.ScmException;
23  import org.apache.maven.scm.ScmFile;
24  import org.apache.maven.scm.ScmFileSet;
25  import org.apache.maven.scm.ScmVersion;
26  import org.apache.maven.scm.command.checkin.AbstractCheckInCommand;
27  import org.apache.maven.scm.command.checkin.CheckInScmResult;
28  import org.apache.maven.scm.provider.ScmProviderRepository;
29  import org.apache.maven.scm.provider.git.command.GitCommand;
30  import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
31  import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
32  import org.codehaus.plexus.util.StringUtils;
33  import org.eclipse.jgit.api.AddCommand;
34  import org.eclipse.jgit.api.Git;
35  import org.eclipse.jgit.lib.Constants;
36  import org.eclipse.jgit.lib.UserConfig;
37  import org.eclipse.jgit.revwalk.RevCommit;
38  import org.eclipse.jgit.transport.RefSpec;
39  
40  import java.io.File;
41  import java.net.InetAddress;
42  import java.net.UnknownHostException;
43  import java.util.Collections;
44  import java.util.List;
45  import java.util.Set;
46  
47  /**
48   * This provider uses the following strategy to discover the committer and author name/mail for a commit:
49   * <ol>
50   * <li>"user" section in .gitconfig</li>
51   * <li>"username" passed to maven execution</li>
52   * <li>default git config (system user and hostname for email)</li>
53   * </ol>
54   * the "maven-scm" config can be configured like this: <br>
55   * the default email domain to be used (will be used to create an email from the username passed to maven):<br>
56   * <code>git config --global maven-scm.maildomain mycomp.com</code> <br>
57   * you can also enforce the usage of the username for the author and committer:<br>
58   * <code>git config --global maven-scm.forceUsername true</code> <br>
59   * 
60   * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
61   * @author Dominik Bartholdi (imod)
62   * @since 1.9
63   */
64  public class JGitCheckInCommand
65      extends AbstractCheckInCommand
66      implements GitCommand
67  {
68  
69      protected static final String GIT_MAVEN_SECTION = "maven-scm";
70  
71      protected static final String GIT_MAILDOMAIN = "maildomain";
72  
73      protected static final String GIT_FORCE = "forceUsername";
74  
75      /**
76       * {@inheritDoc}
77       */
78      protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repo, ScmFileSet fileSet, String message,
79                                                        ScmVersion version )
80          throws ScmException
81      {
82  
83          Git git = null;
84          try
85          {
86              File basedir = fileSet.getBasedir();
87              git = Git.open( basedir );
88  
89              boolean doCommit = false;
90  
91              if ( !fileSet.getFileList().isEmpty() )
92              {
93                  doCommit = JGitUtils.addAllFiles( git, fileSet ).size() > 0;
94              }
95              else
96              {
97                  // add all tracked files which are modified manually
98                  Set<String> changeds = git.status().call().getModified();
99                  if ( changeds.isEmpty() )
100                 {
101                     // warn there is nothing to add
102                     getLogger().warn( "there are no files to be added" );
103                     doCommit = false;
104                 }
105                 else
106                 {
107                     AddCommand add = git.add();
108                     for ( String changed : changeds )
109                     {
110                         getLogger().debug( "add manualy: " + changed );
111                         add.addFilepattern( changed );
112                         doCommit = true;
113                     }
114                     add.call();
115                 }
116             }
117 
118             List<ScmFile> checkedInFiles = Collections.emptyList();
119             if ( doCommit )
120             {
121                 UserInfo author = getAuthor( repo, git );
122                 UserInfo committer = getCommitter( repo, git );
123 
124                 RevCommit commitRev =
125                     git.commit().setMessage( message ).setAuthor( author.name, author.email ).setCommitter( committer.name,
126                                                                                                             committer.email ).call();
127                 getLogger().info( "commit done: " + commitRev.getShortMessage() );
128                 checkedInFiles = JGitUtils.getFilesInCommit( git.getRepository(), commitRev );
129                 if ( getLogger().isDebugEnabled() )
130                 {
131                     for ( ScmFile scmFile : checkedInFiles )
132                     {
133                         getLogger().debug( "in commit: " + scmFile );
134                     }
135                 }
136             }
137 
138             if ( repo.isPushChanges() )
139             {
140                 String branch = version != null ? version.getName() : null;
141                 if ( StringUtils.isBlank( branch ) )
142                 {
143                     branch = git.getRepository().getBranch();
144                 }
145                 RefSpec refSpec = new RefSpec( Constants.R_HEADS + branch + ":" + Constants.R_HEADS + branch );
146                 getLogger().info( "push changes to remote... " + refSpec.toString() );
147                 JGitUtils.push( getLogger(), git, (GitScmProviderRepository) repo, refSpec );
148             }
149 
150             return new CheckInScmResult( "JGit checkin", checkedInFiles );
151         }
152         catch ( Exception e )
153         {
154             throw new ScmException( "JGit checkin failure!", e );
155         }
156         finally
157         {
158             JGitUtils.closeRepo( git );
159         }
160     }
161 
162     private static final class UserInfo
163     {
164         final String name;
165 
166         final String email;
167 
168         public UserInfo( String name, String email )
169         {
170             this.name = name;
171             this.email = email;
172         }
173     }
174 
175     private UserInfo getCommitter( ScmProviderRepository repo, Git git )
176     {
177         boolean forceMvnUser = git.getRepository().getConfig().getBoolean( GIT_MAVEN_SECTION, GIT_FORCE, false );
178 
179         // git config
180         UserConfig user = git.getRepository().getConfig().get( UserConfig.KEY );
181         String committerName = null;
182         if ( !forceMvnUser && !user.isCommitterNameImplicit() )
183         {
184             committerName = user.getCommitterName();
185         }
186 
187         // mvn parameter
188         if ( StringUtils.isBlank( committerName ) )
189         {
190             committerName = repo.getUser();
191         }
192 
193         // git default
194         if ( StringUtils.isBlank( committerName ) )
195         {
196             committerName = user.getCommitterName();
197         }
198 
199         // git config
200         String committerMail = null;
201         if ( !user.isCommitterEmailImplicit() )
202         {
203             committerMail = user.getCommitterEmail();
204         }
205 
206         if ( StringUtils.isBlank( committerMail ) )
207         {
208             String defaultDomain = git.getRepository().getConfig().getString( GIT_MAVEN_SECTION, null, GIT_MAILDOMAIN );
209             defaultDomain = StringUtils.isNotBlank( defaultDomain ) ? defaultDomain : getHostname();
210 
211             // mvn parameter (constructed with username) or git default
212             committerMail =
213                 StringUtils.isNotBlank( repo.getUser() ) ? repo.getUser() + "@" + defaultDomain
214                                 : user.getCommitterEmail();
215         }
216 
217         return new UserInfo( committerName, committerMail );
218     }
219 
220     private UserInfo getAuthor( ScmProviderRepository repo, Git git )
221     {
222         boolean forceMvnUser = git.getRepository().getConfig().getBoolean( GIT_MAVEN_SECTION, GIT_FORCE, false );
223 
224         // git config
225         UserConfig user = git.getRepository().getConfig().get( UserConfig.KEY );
226         String authorName = null;
227         if ( !forceMvnUser && !user.isAuthorNameImplicit() )
228         {
229             authorName = user.getAuthorName();
230         }
231 
232         // mvn parameter
233         if ( StringUtils.isBlank( authorName ) )
234         {
235             authorName = repo.getUser();
236         }
237 
238         // git default
239         if ( StringUtils.isBlank( authorName ) )
240         {
241             authorName = user.getAuthorName();
242         }
243 
244         // git config
245         String authorMail = null;
246         if ( !user.isAuthorEmailImplicit() )
247         {
248             authorMail = user.getAuthorEmail();
249         }
250 
251         if ( StringUtils.isBlank( authorMail ) )
252         {
253             String defaultDomain = git.getRepository().getConfig().getString( GIT_MAVEN_SECTION, null, GIT_MAILDOMAIN );
254             defaultDomain = StringUtils.isNotBlank( defaultDomain ) ? defaultDomain : getHostname();
255 
256             // mvn parameter (constructed with username) or git default
257             authorMail =
258                 StringUtils.isNotBlank( repo.getUser() ) ? repo.getUser() + "@" + defaultDomain : user.getAuthorEmail();
259         }
260 
261         return new UserInfo( authorName, authorMail );
262     }
263 
264     private String getHostname()
265     {
266         String hostname;
267         try
268         {
269             InetAddress localhost = java.net.InetAddress.getLocalHost();
270             hostname = localhost.getHostName();
271         }
272         catch ( UnknownHostException e )
273         {
274             getLogger().warn( "failed to resolve hostname to create mail address, defaulting to 'maven-scm-provider-jgit'" );
275             hostname = "maven-scm-provider-jgit";
276         }
277         return hostname;
278     }
279 
280 }