001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.scm.provider.git.gitexe.command.changelog; 020 021import java.io.File; 022import java.text.SimpleDateFormat; 023import java.util.Date; 024import java.util.TimeZone; 025 026import org.apache.commons.text.StringEscapeUtils; 027import org.apache.maven.scm.CommandParameter; 028import org.apache.maven.scm.CommandParameters; 029import org.apache.maven.scm.ScmBranch; 030import org.apache.maven.scm.ScmException; 031import org.apache.maven.scm.ScmFileSet; 032import org.apache.maven.scm.ScmResult; 033import org.apache.maven.scm.ScmVersion; 034import org.apache.maven.scm.command.changelog.AbstractChangeLogCommand; 035import org.apache.maven.scm.command.changelog.ChangeLogScmRequest; 036import org.apache.maven.scm.command.changelog.ChangeLogScmResult; 037import org.apache.maven.scm.command.changelog.ChangeLogSet; 038import org.apache.maven.scm.provider.ScmProviderRepository; 039import org.apache.maven.scm.provider.git.command.GitCommand; 040import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils; 041import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; 042import org.codehaus.plexus.util.cli.CommandLineUtils; 043import org.codehaus.plexus.util.cli.Commandline; 044 045/** 046 * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a> 047 * @author Olivier Lamy 048 */ 049public class GitChangeLogCommand extends AbstractChangeLogCommand implements GitCommand { 050 private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z"; 051 052 @Override 053 public ScmResult executeCommand(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) 054 throws ScmException { 055 return executeChangeLogCommand( 056 repository, 057 fileSet, 058 parameters.getDate(CommandParameter.START_DATE, null), 059 parameters.getDate(CommandParameter.END_DATE, null), 060 (ScmBranch) parameters.getScmVersion(CommandParameter.BRANCH, null), 061 parameters.getString(CommandParameter.CHANGELOG_DATE_PATTERN, null), 062 parameters.getScmVersion(CommandParameter.START_SCM_VERSION, null), 063 parameters.getScmVersion(CommandParameter.END_SCM_VERSION, null), 064 parameters.getInt(CommandParameter.LIMIT, -1), 065 parameters.getScmVersion(CommandParameter.SCM_VERSION, null)); 066 } 067 068 /** 069 * {@inheritDoc} 070 */ 071 @Override 072 protected ChangeLogScmResult executeChangeLogCommand( 073 ScmProviderRepository repo, 074 ScmFileSet fileSet, 075 ScmVersion startVersion, 076 ScmVersion endVersion, 077 String datePattern) 078 throws ScmException { 079 return executeChangeLogCommand(repo, fileSet, null, null, null, datePattern, startVersion, endVersion); 080 } 081 082 /** 083 * {@inheritDoc} 084 */ 085 @Override 086 protected ChangeLogScmResult executeChangeLogCommand( 087 ScmProviderRepository repo, 088 ScmFileSet fileSet, 089 Date startDate, 090 Date endDate, 091 ScmBranch branch, 092 String datePattern) 093 throws ScmException { 094 return executeChangeLogCommand(repo, fileSet, startDate, endDate, branch, datePattern, null, null); 095 } 096 097 @Override 098 protected ChangeLogScmResult executeChangeLogCommand( 099 ScmProviderRepository repository, ScmFileSet fileSet, ScmVersion version, String datePattern) 100 throws ScmException { 101 return executeChangeLogCommand(repository, fileSet, null, null, null, datePattern, null, null, null, version); 102 } 103 104 protected ChangeLogScmResult executeChangeLogCommand( 105 ScmProviderRepository repo, 106 ScmFileSet fileSet, 107 Date startDate, 108 Date endDate, 109 ScmBranch branch, 110 String datePattern, 111 ScmVersion startVersion, 112 ScmVersion endVersion) 113 throws ScmException { 114 return executeChangeLogCommand( 115 repo, fileSet, startDate, endDate, branch, datePattern, startVersion, endVersion, null, null); 116 } 117 118 @Override 119 protected ChangeLogScmResult executeChangeLogCommand(ChangeLogScmRequest request) throws ScmException { 120 final ScmVersion startVersion = request.getStartRevision(); 121 final ScmVersion endVersion = request.getEndRevision(); 122 final ScmVersion revision = request.getRevision(); 123 final ScmFileSet fileSet = request.getScmFileSet(); 124 final String datePattern = request.getDatePattern(); 125 final ScmProviderRepository providerRepository = 126 request.getScmRepository().getProviderRepository(); 127 final Date startDate = request.getStartDate(); 128 final Date endDate = request.getEndDate(); 129 final ScmBranch branch = request.getScmBranch(); 130 final Integer limit = request.getLimit(); 131 132 return executeChangeLogCommand( 133 providerRepository, 134 fileSet, 135 startDate, 136 endDate, 137 branch, 138 datePattern, 139 startVersion, 140 endVersion, 141 limit, 142 revision); 143 } 144 145 protected ChangeLogScmResult executeChangeLogCommand( 146 ScmProviderRepository repo, 147 ScmFileSet fileSet, 148 Date startDate, 149 Date endDate, 150 ScmBranch branch, 151 String datePattern, 152 ScmVersion startVersion, 153 ScmVersion endVersion, 154 Integer limit) 155 throws ScmException { 156 return executeChangeLogCommand( 157 repo, fileSet, startDate, endDate, branch, datePattern, startVersion, endVersion, limit, null); 158 } 159 160 protected ChangeLogScmResult executeChangeLogCommand( 161 ScmProviderRepository repo, 162 ScmFileSet fileSet, 163 Date startDate, 164 Date endDate, 165 ScmBranch branch, 166 String datePattern, 167 ScmVersion startVersion, 168 ScmVersion endVersion, 169 Integer limit, 170 ScmVersion version) 171 throws ScmException { 172 Commandline cl = createCommandLine( 173 (GitScmProviderRepository) repo, 174 fileSet.getBasedir(), 175 branch, 176 startDate, 177 endDate, 178 startVersion, 179 endVersion, 180 limit, 181 version); 182 183 GitChangeLogConsumer consumer = new GitChangeLogConsumer(datePattern); 184 185 CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer(); 186 187 int exitCode; 188 189 exitCode = GitCommandLineUtils.execute(cl, consumer, stderr); 190 if (exitCode != 0) { 191 return new ChangeLogScmResult(cl.toString(), "The git-log command failed.", stderr.getOutput(), false); 192 } 193 ChangeLogSet changeLogSet = new ChangeLogSet(consumer.getModifications(), startDate, endDate); 194 changeLogSet.setStartVersion(startVersion); 195 changeLogSet.setEndVersion(endVersion); 196 197 return new ChangeLogScmResult(cl.toString(), changeLogSet); 198 } 199 200 // ---------------------------------------------------------------------- 201 // 202 // ---------------------------------------------------------------------- 203 204 /** 205 * This method creates the commandline for the git-whatchanged command. 206 * <p> 207 * Since it uses --since and --until for the start and end date, the branch 208 * and version parameters can be used simultanously. 209 * 210 * @param repository provider repositry to use 211 * @param workingDirectory working copy directory 212 * @param branch branch to run command on 213 * @param startDate start date of log entries 214 * @param endDate end date of log entries 215 * @param startVersion start version of log entries 216 * @param endVersion end version of log entries 217 * @return command line 218 */ 219 public static Commandline createCommandLine( 220 GitScmProviderRepository repository, 221 File workingDirectory, 222 ScmBranch branch, 223 Date startDate, 224 Date endDate, 225 ScmVersion startVersion, 226 ScmVersion endVersion) { 227 return createCommandLine( 228 repository, workingDirectory, branch, startDate, endDate, startVersion, endVersion, null); 229 } 230 231 static Commandline createCommandLine( 232 GitScmProviderRepository repository, 233 File workingDirectory, 234 ScmBranch branch, 235 Date startDate, 236 Date endDate, 237 ScmVersion startVersion, 238 ScmVersion endVersion, 239 Integer limit) { 240 return createCommandLine( 241 repository, workingDirectory, branch, startDate, endDate, startVersion, endVersion, limit, null); 242 } 243 244 static Commandline createCommandLine( 245 GitScmProviderRepository repository, 246 File workingDirectory, 247 ScmBranch branch, 248 Date startDate, 249 Date endDate, 250 ScmVersion startVersion, 251 ScmVersion endVersion, 252 Integer limit, 253 ScmVersion version) { 254 SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); 255 dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); 256 257 Commandline cl = GitCommandLineUtils.getBaseGitCommandLine(workingDirectory, "log"); 258 cl.createArg().setValue("--format=medium"); 259 cl.createArg().setValue("--decorate=short"); 260 cl.createArg().setValue("--raw"); 261 cl.createArg().setValue("--no-merges"); 262 263 if (startDate != null || endDate != null) { 264 if (startDate != null) { 265 cl.createArg().setValue("--since=" + StringEscapeUtils.escapeJava(dateFormat.format(startDate))); 266 } 267 268 if (endDate != null) { 269 cl.createArg().setValue("--until=" + StringEscapeUtils.escapeJava(dateFormat.format(endDate))); 270 } 271 } 272 273 // since this parameter is also used for the output formatting, we need it also if no start nor end date is 274 // given 275 cl.createArg().setValue("--date=iso"); 276 277 if (startVersion != null || endVersion != null) { 278 StringBuilder versionRange = new StringBuilder(); 279 280 if (startVersion != null) { 281 versionRange.append(StringEscapeUtils.escapeJava(startVersion.getName())); 282 } 283 284 versionRange.append(".."); 285 286 if (endVersion != null) { 287 versionRange.append(StringEscapeUtils.escapeJava(endVersion.getName())); 288 } 289 290 cl.createArg().setValue(versionRange.toString()); 291 292 } else if (version != null) { 293 cl.createArg().setValue(StringEscapeUtils.escapeJava(version.getName())); 294 } 295 296 if (limit != null && limit > 0) { 297 cl.createArg().setValue("--max-count=" + limit); 298 } 299 300 if (branch != null && branch.getName() != null && branch.getName().length() > 0) { 301 cl.createArg().setValue(branch.getName()); 302 } 303 304 // Insert a separator to make sure that files aren't interpreted as part of the version spec 305 cl.createArg().setValue("--"); 306 307 // We have to report only the changes of the current project. 308 // This is needed for child projects, otherwise we would get the changelog of the 309 // whole parent-project including all childs. 310 cl.createArg().setValue("."); 311 312 return cl; 313 } 314}