View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.scm.provider.git.gitexe.command.changelog;
20  
21  import java.io.File;
22  import java.text.SimpleDateFormat;
23  import java.util.Date;
24  import java.util.TimeZone;
25  
26  import org.apache.commons.text.StringEscapeUtils;
27  import org.apache.maven.scm.CommandParameter;
28  import org.apache.maven.scm.CommandParameters;
29  import org.apache.maven.scm.ScmBranch;
30  import org.apache.maven.scm.ScmException;
31  import org.apache.maven.scm.ScmFileSet;
32  import org.apache.maven.scm.ScmResult;
33  import org.apache.maven.scm.ScmVersion;
34  import org.apache.maven.scm.command.changelog.AbstractChangeLogCommand;
35  import org.apache.maven.scm.command.changelog.ChangeLogScmRequest;
36  import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
37  import org.apache.maven.scm.command.changelog.ChangeLogSet;
38  import org.apache.maven.scm.provider.ScmProviderRepository;
39  import org.apache.maven.scm.provider.git.command.GitCommand;
40  import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
41  import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
42  import org.codehaus.plexus.util.cli.CommandLineUtils;
43  import org.codehaus.plexus.util.cli.Commandline;
44  
45  /**
46   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
47   * @author Olivier Lamy
48   */
49  public class GitChangeLogCommand extends AbstractChangeLogCommand implements GitCommand {
50      private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z";
51  
52      @Override
53      public ScmResult executeCommand(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
54              throws ScmException {
55          return executeChangeLogCommand(
56                  repository,
57                  fileSet,
58                  parameters.getDate(CommandParameter.START_DATE, null),
59                  parameters.getDate(CommandParameter.END_DATE, null),
60                  (ScmBranch) parameters.getScmVersion(CommandParameter.BRANCH, null),
61                  parameters.getString(CommandParameter.CHANGELOG_DATE_PATTERN, null),
62                  parameters.getScmVersion(CommandParameter.START_SCM_VERSION, null),
63                  parameters.getScmVersion(CommandParameter.END_SCM_VERSION, null),
64                  parameters.getInt(CommandParameter.LIMIT, -1),
65                  parameters.getScmVersion(CommandParameter.SCM_VERSION, null));
66      }
67  
68      /**
69       * {@inheritDoc}
70       */
71      @Override
72      protected ChangeLogScmResult executeChangeLogCommand(
73              ScmProviderRepository repo,
74              ScmFileSet fileSet,
75              ScmVersion startVersion,
76              ScmVersion endVersion,
77              String datePattern)
78              throws ScmException {
79          return executeChangeLogCommand(repo, fileSet, null, null, null, datePattern, startVersion, endVersion);
80      }
81  
82      /**
83       * {@inheritDoc}
84       */
85      @Override
86      protected ChangeLogScmResult executeChangeLogCommand(
87              ScmProviderRepository repo,
88              ScmFileSet fileSet,
89              Date startDate,
90              Date endDate,
91              ScmBranch branch,
92              String datePattern)
93              throws ScmException {
94          return executeChangeLogCommand(repo, fileSet, startDate, endDate, branch, datePattern, null, null);
95      }
96  
97      @Override
98      protected ChangeLogScmResult executeChangeLogCommand(
99              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 }