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.jgit.command.changelog;
020
021import java.io.File;
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.Date;
025import java.util.List;
026
027import org.apache.maven.scm.ChangeSet;
028import org.apache.maven.scm.ScmBranch;
029import org.apache.maven.scm.ScmException;
030import org.apache.maven.scm.ScmFileSet;
031import org.apache.maven.scm.ScmVersion;
032import org.apache.maven.scm.command.changelog.AbstractChangeLogCommand;
033import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
034import org.apache.maven.scm.command.changelog.ChangeLogSet;
035import org.apache.maven.scm.provider.ScmProviderRepository;
036import org.apache.maven.scm.provider.git.command.GitCommand;
037import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
038import org.eclipse.jgit.api.Git;
039import org.eclipse.jgit.errors.IncorrectObjectTypeException;
040import org.eclipse.jgit.errors.MissingObjectException;
041import org.eclipse.jgit.lib.Repository;
042import org.eclipse.jgit.revwalk.RevCommit;
043import org.eclipse.jgit.revwalk.RevSort;
044
045import static org.apache.maven.scm.provider.git.jgit.command.JGitUtils.getTags;
046
047/**
048 * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
049 * @author Dominik Bartholdi (imod)
050 * @since 1.9
051 */
052public class JGitChangeLogCommand extends AbstractChangeLogCommand implements GitCommand {
053
054    /**
055     * {@inheritDoc}
056     */
057    protected ChangeLogScmResult executeChangeLogCommand(
058            ScmProviderRepository repo,
059            ScmFileSet fileSet,
060            ScmVersion startVersion,
061            ScmVersion endVersion,
062            String datePattern)
063            throws ScmException {
064        return executeChangeLogCommand(repo, fileSet, null, null, null, datePattern, startVersion, endVersion);
065    }
066
067    @Override
068    protected ChangeLogScmResult executeChangeLogCommand(
069            ScmProviderRepository repository, ScmFileSet fileSet, ScmVersion version, String datePattern)
070            throws ScmException {
071        return executeChangeLogCommand(repository, fileSet, null, null, null, datePattern, null, null, version);
072    }
073
074    /**
075     * {@inheritDoc}
076     */
077    protected ChangeLogScmResult executeChangeLogCommand(
078            ScmProviderRepository repo,
079            ScmFileSet fileSet,
080            Date startDate,
081            Date endDate,
082            ScmBranch branch,
083            String datePattern)
084            throws ScmException {
085        return executeChangeLogCommand(repo, fileSet, startDate, endDate, branch, datePattern, null, null);
086    }
087
088    protected ChangeLogScmResult executeChangeLogCommand(
089            ScmProviderRepository repo,
090            ScmFileSet fileSet,
091            Date startDate,
092            Date endDate,
093            ScmBranch branch,
094            String datePattern,
095            ScmVersion startVersion,
096            ScmVersion endVersion)
097            throws ScmException {
098        return executeChangeLogCommand(
099                repo, fileSet, startDate, endDate, branch, datePattern, startVersion, endVersion, null);
100    }
101
102    protected ChangeLogScmResult executeChangeLogCommand(
103            ScmProviderRepository repo,
104            ScmFileSet fileSet,
105            Date startDate,
106            Date endDate,
107            ScmBranch branch,
108            String datePattern,
109            ScmVersion startVersion,
110            ScmVersion endVersion,
111            ScmVersion version)
112            throws ScmException {
113        Git git = null;
114        boolean isARangeChangeLog = startVersion != null || endVersion != null;
115
116        try {
117            git = JGitUtils.openRepo(fileSet.getBasedir());
118
119            boolean versionOnly = startVersion == null && endVersion == null && version != null;
120
121            String startRev;
122            String endRev;
123
124            if (versionOnly) {
125                startRev = null;
126                endRev = version.getName();
127            } else {
128                startRev = startVersion != null ? startVersion.getName() : (isARangeChangeLog ? "HEAD" : null);
129                endRev = endVersion != null ? endVersion.getName() : (isARangeChangeLog ? "HEAD" : null);
130            }
131
132            List<ChangeEntry> gitChanges =
133                    this.whatchanged(git.getRepository(), null, startRev, endRev, startDate, endDate, -1);
134
135            List<ChangeSet> modifications = new ArrayList<>(gitChanges.size());
136
137            for (ChangeEntry change : gitChanges) {
138                ChangeSet scmChange = new ChangeSet();
139
140                scmChange.setAuthor(change.getAuthorName());
141                scmChange.setComment(change.getBody());
142                scmChange.setDate(change.getAuthorDate());
143                scmChange.setRevision(change.getCommitHash());
144                scmChange.setTags(change.getTags());
145                // X TODO scmChange.setFiles( change.get )
146
147                modifications.add(scmChange);
148            }
149
150            ChangeLogSet changeLogSet = new ChangeLogSet(modifications, startDate, endDate);
151            changeLogSet.setStartVersion(startVersion);
152            changeLogSet.setEndVersion(endVersion);
153
154            return new ChangeLogScmResult("JGit changelog", changeLogSet);
155        } catch (IOException e) {
156            throw new ScmException("JGit changelog failure!", e);
157        } finally {
158            JGitUtils.closeRepo(git);
159        }
160    }
161
162    public List<ChangeEntry> whatchanged(
163            Repository repo, RevSort[] sortings, String fromRev, String toRev, Date fromDate, Date toDate, int maxLines)
164            throws MissingObjectException, IncorrectObjectTypeException, IOException {
165        List<RevCommit> revs = JGitUtils.getRevCommits(repo, sortings, fromRev, toRev, fromDate, toDate, maxLines);
166        List<ChangeEntry> changes = new ArrayList<>(revs.size());
167
168        if (fromRev != null && fromRev.equals(toRev)) {
169            // there are no changes between 2 identical versions
170            return changes;
171        }
172
173        for (RevCommit c : revs) {
174            ChangeEntry ce = new ChangeEntry();
175
176            ce.setAuthorDate(c.getAuthorIdent().getWhen());
177            ce.setAuthorEmail(c.getAuthorIdent().getEmailAddress());
178            ce.setAuthorName(c.getAuthorIdent().getName());
179            ce.setCommitterDate(c.getCommitterIdent().getWhen());
180            ce.setCommitterEmail(c.getCommitterIdent().getEmailAddress());
181            ce.setCommitterName(c.getCommitterIdent().getName());
182
183            ce.setSubject(c.getShortMessage());
184            ce.setBody(c.getFullMessage());
185
186            ce.setCommitHash(c.getId().name());
187            ce.setTreeHash(c.getTree().getId().name());
188
189            ce.setTags(getTags(repo, c));
190            // X TODO missing: file list
191
192            changes.add(ce);
193        }
194
195        return changes;
196    }
197
198    public static final class ChangeEntry {
199        private String commitHash;
200
201        private String treeHash;
202
203        private String authorName;
204
205        private String authorEmail;
206
207        private Date authorDate;
208
209        private String committerName;
210
211        private String committerEmail;
212
213        private Date committerDate;
214
215        private String subject;
216
217        private String body;
218
219        private List<File> files;
220
221        private List<String> tags;
222
223        public String getCommitHash() {
224            return commitHash;
225        }
226
227        public void setCommitHash(String commitHash) {
228            this.commitHash = commitHash;
229        }
230
231        public String getTreeHash() {
232            return treeHash;
233        }
234
235        public void setTreeHash(String treeHash) {
236            this.treeHash = treeHash;
237        }
238
239        public String getAuthorName() {
240            return authorName;
241        }
242
243        public void setAuthorName(String authorName) {
244            this.authorName = authorName;
245        }
246
247        public String getAuthorEmail() {
248            return authorEmail;
249        }
250
251        public void setAuthorEmail(String authorEmail) {
252            this.authorEmail = authorEmail;
253        }
254
255        public Date getAuthorDate() {
256            return authorDate;
257        }
258
259        public void setAuthorDate(Date authorDate) {
260            this.authorDate = authorDate;
261        }
262
263        public String getCommitterName() {
264            return committerName;
265        }
266
267        public void setCommitterName(String committerName) {
268            this.committerName = committerName;
269        }
270
271        public String getCommitterEmail() {
272            return committerEmail;
273        }
274
275        public void setCommitterEmail(String committerEmail) {
276            this.committerEmail = committerEmail;
277        }
278
279        public Date getCommitterDate() {
280            return committerDate;
281        }
282
283        public void setCommitterDate(Date committerDate) {
284            this.committerDate = committerDate;
285        }
286
287        public String getSubject() {
288            return subject;
289        }
290
291        public void setSubject(String subject) {
292            this.subject = subject;
293        }
294
295        public String getBody() {
296            return body;
297        }
298
299        public void setBody(String body) {
300            this.body = body;
301        }
302
303        public List<File> getFiles() {
304            return files;
305        }
306
307        public void setFiles(List<File> files) {
308            this.files = files;
309        }
310
311        public List<String> getTags() {
312            return tags;
313        }
314
315        public void setTags(List<String> tags) {
316            this.tags = tags;
317        }
318    }
319}