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   */
50  public class GitChangeLogCommand extends AbstractChangeLogCommand implements GitCommand {
51      private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z";
52  
53      @Override
54      public ScmResult executeCommand(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
55              throws ScmException {
56          return executeChangeLogCommand(
57                  repository,
58                  fileSet,
59                  parameters.getDate(CommandParameter.START_DATE, null),
60                  parameters.getDate(CommandParameter.END_DATE, null),
61                  (ScmBranch) parameters.getScmVersion(CommandParameter.BRANCH, null),
62                  parameters.getString(CommandParameter.CHANGELOG_DATE_PATTERN, null),
63                  parameters.getScmVersion(CommandParameter.START_SCM_VERSION, null),
64                  parameters.getScmVersion(CommandParameter.END_SCM_VERSION, null),
65                  parameters.getInt(CommandParameter.LIMIT, -1),
66                  parameters.getScmVersion(CommandParameter.SCM_VERSION, null));
67      }
68  
69      /** {@inheritDoc} */
70      @Override
71      protected ChangeLogScmResult executeChangeLogCommand(
72              ScmProviderRepository repo,
73              ScmFileSet fileSet,
74              ScmVersion startVersion,
75              ScmVersion endVersion,
76              String datePattern)
77              throws ScmException {
78          return executeChangeLogCommand(repo, fileSet, null, null, null, datePattern, startVersion, endVersion);
79      }
80  
81      /** {@inheritDoc} */
82      @Override
83      protected ChangeLogScmResult executeChangeLogCommand(
84              ScmProviderRepository repo,
85              ScmFileSet fileSet,
86              Date startDate,
87              Date endDate,
88              ScmBranch branch,
89              String datePattern)
90              throws ScmException {
91          return executeChangeLogCommand(repo, fileSet, startDate, endDate, branch, datePattern, null, null);
92      }
93  
94      @Override
95      protected ChangeLogScmResult executeChangeLogCommand(
96              ScmProviderRepository repository, ScmFileSet fileSet, ScmVersion version, String datePattern)
97              throws ScmException {
98          return executeChangeLogCommand(repository, fileSet, null, null, null, datePattern, null, null, null, version);
99      }
100 
101     protected ChangeLogScmResult executeChangeLogCommand(
102             ScmProviderRepository repo,
103             ScmFileSet fileSet,
104             Date startDate,
105             Date endDate,
106             ScmBranch branch,
107             String datePattern,
108             ScmVersion startVersion,
109             ScmVersion endVersion)
110             throws ScmException {
111         return executeChangeLogCommand(
112                 repo, fileSet, startDate, endDate, branch, datePattern, startVersion, endVersion, null, null);
113     }
114 
115     @Override
116     protected ChangeLogScmResult executeChangeLogCommand(ChangeLogScmRequest request) throws ScmException {
117         final ScmVersion startVersion = request.getStartRevision();
118         final ScmVersion endVersion = request.getEndRevision();
119         final ScmVersion revision = request.getRevision();
120         final ScmFileSet fileSet = request.getScmFileSet();
121         final String datePattern = request.getDatePattern();
122         final ScmProviderRepository providerRepository =
123                 request.getScmRepository().getProviderRepository();
124         final Date startDate = request.getStartDate();
125         final Date endDate = request.getEndDate();
126         final ScmBranch branch = request.getScmBranch();
127         final Integer limit = request.getLimit();
128 
129         return executeChangeLogCommand(
130                 providerRepository,
131                 fileSet,
132                 startDate,
133                 endDate,
134                 branch,
135                 datePattern,
136                 startVersion,
137                 endVersion,
138                 limit,
139                 revision);
140     }
141 
142     protected ChangeLogScmResult executeChangeLogCommand(
143             ScmProviderRepository repo,
144             ScmFileSet fileSet,
145             Date startDate,
146             Date endDate,
147             ScmBranch branch,
148             String datePattern,
149             ScmVersion startVersion,
150             ScmVersion endVersion,
151             Integer limit)
152             throws ScmException {
153         return executeChangeLogCommand(
154                 repo, fileSet, startDate, endDate, branch, datePattern, startVersion, endVersion, limit, null);
155     }
156 
157     protected ChangeLogScmResult executeChangeLogCommand(
158             ScmProviderRepository repo,
159             ScmFileSet fileSet,
160             Date startDate,
161             Date endDate,
162             ScmBranch branch,
163             String datePattern,
164             ScmVersion startVersion,
165             ScmVersion endVersion,
166             Integer limit,
167             ScmVersion version)
168             throws ScmException {
169         Commandline cl = createCommandLine(
170                 (GitScmProviderRepository) repo,
171                 fileSet.getBasedir(),
172                 branch,
173                 startDate,
174                 endDate,
175                 startVersion,
176                 endVersion,
177                 limit,
178                 version);
179 
180         GitChangeLogConsumer consumer = new GitChangeLogConsumer(datePattern);
181 
182         CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
183 
184         int exitCode;
185 
186         exitCode = GitCommandLineUtils.execute(cl, consumer, stderr);
187         if (exitCode != 0) {
188             return new ChangeLogScmResult(cl.toString(), "The git-log command failed.", stderr.getOutput(), false);
189         }
190         ChangeLogSet changeLogSet = new ChangeLogSet(consumer.getModifications(), startDate, endDate);
191         changeLogSet.setStartVersion(startVersion);
192         changeLogSet.setEndVersion(endVersion);
193 
194         return new ChangeLogScmResult(cl.toString(), changeLogSet);
195     }
196 
197     // ----------------------------------------------------------------------
198     //
199     // ----------------------------------------------------------------------
200 
201     /**
202      * This method creates the commandline for the git-whatchanged command.
203      * <p>
204      * Since it uses --since and --until for the start and end date, the branch
205      * and version parameters can be used simultanously.
206      *
207      * @param repository Provider repositry to use.
208      * @param workingDirectory Working copy directory.
209      * @param branch Branch to run command on.
210      * @param startDate Start date of log entries.
211      * @param endDate End date of log entries.
212      * @param startVersion Start version of log entries.
213      * @param endVersion End version of log entries.
214      * @return Command line.
215      */
216     public static Commandline createCommandLine(
217             GitScmProviderRepository repository,
218             File workingDirectory,
219             ScmBranch branch,
220             Date startDate,
221             Date endDate,
222             ScmVersion startVersion,
223             ScmVersion endVersion) {
224         return createCommandLine(
225                 repository, workingDirectory, branch, startDate, endDate, startVersion, endVersion, null);
226     }
227 
228     static Commandline createCommandLine(
229             GitScmProviderRepository repository,
230             File workingDirectory,
231             ScmBranch branch,
232             Date startDate,
233             Date endDate,
234             ScmVersion startVersion,
235             ScmVersion endVersion,
236             Integer limit) {
237         return createCommandLine(
238                 repository, workingDirectory, branch, startDate, endDate, startVersion, endVersion, limit, null);
239     }
240 
241     static Commandline createCommandLine(
242             GitScmProviderRepository repository,
243             File workingDirectory,
244             ScmBranch branch,
245             Date startDate,
246             Date endDate,
247             ScmVersion startVersion,
248             ScmVersion endVersion,
249             Integer limit,
250             ScmVersion version) {
251         SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
252         dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
253 
254         Commandline cl = GitCommandLineUtils.getBaseGitCommandLine(workingDirectory, "whatchanged");
255         cl.createArg().setValue("--format=medium");
256         cl.createArg().setValue("--decorate=short");
257         cl.createArg().setValue("--raw");
258         cl.createArg().setValue("--no-merges");
259 
260         if (startDate != null || endDate != null) {
261             if (startDate != null) {
262                 cl.createArg().setValue("--since=" + StringEscapeUtils.escapeJava(dateFormat.format(startDate)));
263             }
264 
265             if (endDate != null) {
266                 cl.createArg().setValue("--until=" + StringEscapeUtils.escapeJava(dateFormat.format(endDate)));
267             }
268         }
269 
270         // since this parameter is also used for the output formatting, we need it also if no start nor end date is
271         // given
272         cl.createArg().setValue("--date=iso");
273 
274         if (startVersion != null || endVersion != null) {
275             StringBuilder versionRange = new StringBuilder();
276 
277             if (startVersion != null) {
278                 versionRange.append(StringEscapeUtils.escapeJava(startVersion.getName()));
279             }
280 
281             versionRange.append("..");
282 
283             if (endVersion != null) {
284                 versionRange.append(StringEscapeUtils.escapeJava(endVersion.getName()));
285             }
286 
287             cl.createArg().setValue(versionRange.toString());
288 
289         } else if (version != null) {
290             cl.createArg().setValue(StringEscapeUtils.escapeJava(version.getName()));
291         }
292 
293         if (limit != null && limit > 0) {
294             cl.createArg().setValue("--max-count=" + limit);
295         }
296 
297         if (branch != null && branch.getName() != null && branch.getName().length() > 0) {
298             cl.createArg().setValue(branch.getName());
299         }
300 
301         // Insert a separator to make sure that files aren't interpreted as part of the version spec
302         cl.createArg().setValue("--");
303 
304         // We have to report only the changes of the current project.
305         // This is needed for child projects, otherwise we would get the changelog of the
306         // whole parent-project including all childs.
307         cl.createArg().setValue(".");
308 
309         return cl;
310     }
311 }