001package org.apache.maven.scm.provider.git.jgit.command.checkin; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.maven.scm.ScmException; 023import org.apache.maven.scm.ScmFile; 024import org.apache.maven.scm.ScmFileSet; 025import org.apache.maven.scm.ScmVersion; 026import org.apache.maven.scm.command.checkin.AbstractCheckInCommand; 027import org.apache.maven.scm.command.checkin.CheckInScmResult; 028import org.apache.maven.scm.provider.ScmProviderRepository; 029import org.apache.maven.scm.provider.git.command.GitCommand; 030import org.apache.maven.scm.provider.git.jgit.command.JGitUtils; 031import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; 032import org.codehaus.plexus.util.StringUtils; 033import org.eclipse.jgit.api.AddCommand; 034import org.eclipse.jgit.api.CommitCommand; 035import org.eclipse.jgit.api.Git; 036import org.eclipse.jgit.lib.Constants; 037import org.eclipse.jgit.lib.UserConfig; 038import org.eclipse.jgit.revwalk.RevCommit; 039import org.eclipse.jgit.transport.RefSpec; 040 041import java.io.File; 042import java.net.InetAddress; 043import java.net.UnknownHostException; 044import java.util.Collections; 045import java.util.List; 046import java.util.Set; 047 048/** 049 * This provider uses the following strategy to discover the committer and author name/mail for a commit: 050 * <ol> 051 * <li>"user" section in .gitconfig</li> 052 * <li>"username" passed to maven execution</li> 053 * <li>default git config (system user and hostname for email)</li> 054 * </ol> 055 * the "maven-scm" config can be configured like this: <br> 056 * the default email domain to be used (will be used to create an email from the username passed to maven):<br> 057 * <code>git config --global maven-scm.maildomain mycomp.com</code> <br> 058 * you can also enforce the usage of the username for the author and committer:<br> 059 * <code>git config --global maven-scm.forceUsername true</code> <br> 060 * 061 * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a> 062 * @author Dominik Bartholdi (imod) 063 * @since 1.9 064 */ 065public class JGitCheckInCommand 066 extends AbstractCheckInCommand 067 implements GitCommand 068{ 069 070 protected static final String GIT_MAVEN_SECTION = "maven-scm"; 071 072 protected static final String GIT_MAILDOMAIN = "maildomain"; 073 074 protected static final String GIT_FORCE = "forceUsername"; 075 076 /** 077 * {@inheritDoc} 078 */ 079 protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repo, ScmFileSet fileSet, String message, 080 ScmVersion version ) 081 throws ScmException 082 { 083 084 Git git = null; 085 try 086 { 087 File basedir = fileSet.getBasedir(); 088 git = JGitUtils.openRepo( basedir ); 089 090 boolean doCommit = false; 091 092 if ( !fileSet.getFileList().isEmpty() ) 093 { 094 doCommit = JGitUtils.addAllFiles( git, fileSet ).size() > 0; 095 } 096 else 097 { 098 // add all tracked files which are modified manually 099 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 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}