Line data Source code
1 : // Copyright (C) 2013 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.restapi.change; 16 : 17 : import com.google.common.collect.ImmutableList; 18 : import com.google.common.collect.Lists; 19 : import com.google.common.flogger.FluentLogger; 20 : import com.google.gerrit.common.Nullable; 21 : import com.google.gerrit.entities.Change; 22 : import com.google.gerrit.entities.PatchSet; 23 : import com.google.gerrit.entities.Project; 24 : import com.google.gerrit.entities.SubmitRequirementResult; 25 : import com.google.gerrit.extensions.api.changes.GetRelatedOption; 26 : import com.google.gerrit.extensions.api.changes.RelatedChangeAndCommitInfo; 27 : import com.google.gerrit.extensions.api.changes.RelatedChangesInfo; 28 : import com.google.gerrit.extensions.common.CommitInfo; 29 : import com.google.gerrit.extensions.restapi.Response; 30 : import com.google.gerrit.extensions.restapi.RestReadView; 31 : import com.google.gerrit.server.ChangeUtil; 32 : import com.google.gerrit.server.CommonConverters; 33 : import com.google.gerrit.server.change.GetRelatedChangesUtil; 34 : import com.google.gerrit.server.change.RelatedChangesSorter; 35 : import com.google.gerrit.server.change.RevisionResource; 36 : import com.google.gerrit.server.permissions.PermissionBackendException; 37 : import com.google.gerrit.server.project.NoSuchProjectException; 38 : import com.google.gerrit.server.query.change.ChangeData; 39 : import com.google.inject.Inject; 40 : import java.io.IOException; 41 : import java.util.ArrayList; 42 : import java.util.List; 43 : import java.util.Locale; 44 : import org.eclipse.jgit.revwalk.RevCommit; 45 : import org.kohsuke.args4j.Option; 46 : 47 : public class GetRelated implements RestReadView<RevisionResource> { 48 91 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 49 : 50 : private final ChangeData.Factory changeDataFactory; 51 : private final GetRelatedChangesUtil getRelatedChangesUtil; 52 91 : private boolean computeSubmittable = false; 53 : 54 : @Inject 55 91 : GetRelated(ChangeData.Factory changeDataFactory, GetRelatedChangesUtil getRelatedChangesUtil) { 56 91 : this.changeDataFactory = changeDataFactory; 57 91 : this.getRelatedChangesUtil = getRelatedChangesUtil; 58 91 : } 59 : 60 : @Option(name = "-o", usage = "Options") 61 : public void addOption(GetRelatedOption option) { 62 1 : if (option == GetRelatedOption.SUBMITTABLE) { 63 1 : computeSubmittable = true; 64 : } else { 65 0 : throw new IllegalArgumentException("option not recognized: " + option); 66 : } 67 1 : } 68 : 69 : @Override 70 : public Response<RelatedChangesInfo> apply(RevisionResource rsrc) 71 : throws IOException, NoSuchProjectException, PermissionBackendException { 72 6 : RelatedChangesInfo relatedChangesInfo = new RelatedChangesInfo(); 73 6 : relatedChangesInfo.changes = getRelated(rsrc); 74 6 : return Response.ok(relatedChangesInfo); 75 : } 76 : 77 : public ImmutableList<RelatedChangeAndCommitInfo> getRelated(RevisionResource rsrc) 78 : throws IOException, PermissionBackendException { 79 6 : boolean isEdit = rsrc.getEdit().isPresent(); 80 6 : PatchSet basePs = isEdit ? rsrc.getEdit().get().getBasePatchSet() : rsrc.getPatchSet(); 81 6 : logger.atFine().log("isEdit = %s, basePs = %s", isEdit, basePs); 82 : 83 6 : List<RelatedChangesSorter.PatchSetData> sortedResult = 84 6 : getRelatedChangesUtil.getRelated(changeDataFactory.create(rsrc.getNotes()), basePs); 85 : 86 6 : List<RelatedChangeAndCommitInfo> result = new ArrayList<>(sortedResult.size()); 87 6 : for (RelatedChangesSorter.PatchSetData d : sortedResult) { 88 5 : PatchSet ps = d.patchSet(); 89 : RevCommit commit; 90 5 : if (isEdit && ps.id().equals(basePs.id())) { 91 : // Replace base of an edit with the edit itself. 92 1 : ps = rsrc.getPatchSet(); 93 1 : commit = rsrc.getEdit().get().getEditCommit(); 94 1 : logger.atFine().log( 95 : "Replaced base of edit (patch set %s, commit %s) with edit (patch set %s, commit %s)", 96 1 : d.patchSet().id(), d.commit(), ps.id(), commit); 97 : } else { 98 5 : commit = d.commit(); 99 : } 100 5 : result.add(newChangeAndCommit(rsrc.getProject(), d.data(), ps, commit)); 101 5 : } 102 : 103 6 : if (result.size() == 1) { 104 2 : RelatedChangeAndCommitInfo r = result.get(0); 105 2 : if (r.commit != null && r.commit.commit.equals(rsrc.getPatchSet().commitId().name())) { 106 2 : return ImmutableList.of(); 107 : } 108 : } 109 6 : return ImmutableList.copyOf(result); 110 : } 111 : 112 : private RelatedChangeAndCommitInfo newChangeAndCommit( 113 : Project.NameKey project, ChangeData cd, @Nullable PatchSet ps, RevCommit c) { 114 5 : RelatedChangeAndCommitInfo info = new RelatedChangeAndCommitInfo(); 115 5 : info.project = project.get(); 116 : 117 5 : Change change = cd.change(); 118 5 : if (change != null) { 119 5 : info.changeId = change.getKey().get(); 120 5 : info._changeNumber = change.getChangeId(); 121 5 : info._revisionNumber = ps != null ? ps.number() : null; 122 5 : PatchSet.Id curr = change.currentPatchSetId(); 123 5 : info._currentRevisionNumber = curr != null ? curr.get() : null; 124 5 : info.status = ChangeUtil.status(change).toUpperCase(Locale.US); 125 5 : info.submittable = computeSubmittable ? submittable(cd) : null; 126 : } 127 : 128 5 : info.commit = new CommitInfo(); 129 5 : info.commit.commit = c.name(); 130 5 : info.commit.parents = Lists.newArrayListWithCapacity(c.getParentCount()); 131 5 : for (int i = 0; i < c.getParentCount(); i++) { 132 5 : CommitInfo p = new CommitInfo(); 133 5 : p.commit = c.getParent(i).name(); 134 5 : info.commit.parents.add(p); 135 : } 136 5 : info.commit.author = CommonConverters.toGitPerson(c.getAuthorIdent()); 137 5 : info.commit.subject = c.getShortMessage(); 138 5 : return info; 139 : } 140 : 141 : private static boolean submittable(ChangeData cd) { 142 1 : return cd.submitRequirementsIncludingLegacy().values().stream() 143 1 : .allMatch(SubmitRequirementResult::fulfilled); 144 : } 145 : }