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