Line data Source code
1 : // Copyright (C) 2008 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.git; 16 : 17 : import static com.google.common.base.Preconditions.checkArgument; 18 : 19 : import com.google.common.collect.ImmutableSet; 20 : import com.google.common.collect.Ordering; 21 : import com.google.gerrit.common.Nullable; 22 : import com.google.gerrit.entities.Change; 23 : import com.google.gerrit.entities.PatchSet; 24 : import com.google.gerrit.server.notedb.ChangeNotes; 25 : import com.google.gerrit.server.submit.CommitMergeStatus; 26 : import java.io.IOException; 27 : import java.io.ObjectInputStream; 28 : import java.io.ObjectOutputStream; 29 : import java.io.Serializable; 30 : import java.util.Optional; 31 : import java.util.Set; 32 : import org.eclipse.jgit.errors.IncorrectObjectTypeException; 33 : import org.eclipse.jgit.errors.MissingObjectException; 34 : import org.eclipse.jgit.lib.AnyObjectId; 35 : import org.eclipse.jgit.lib.ObjectReader; 36 : import org.eclipse.jgit.lib.Repository; 37 : import org.eclipse.jgit.revwalk.RevCommit; 38 : import org.eclipse.jgit.revwalk.RevWalk; 39 : 40 : /** Extended commit entity with code review specific metadata. */ 41 : public class CodeReviewCommit extends RevCommit implements Serializable { 42 : 43 : private static final long serialVersionUID = 1L; 44 : 45 : /** 46 : * Default ordering when merging multiple topologically-equivalent commits. 47 : * 48 : * <p>Operates only on these commits and does not take ancestry into account. 49 : * 50 : * <p>Use this in preference to the default order, which comes from {@link AnyObjectId} and only 51 : * orders on SHA-1. 52 : */ 53 71 : public static final Ordering<CodeReviewCommit> ORDER = 54 71 : Ordering.natural() 55 71 : .onResultOf( 56 : (CodeReviewCommit c) -> 57 6 : c.getPatchsetId() != null ? c.getPatchsetId().changeId().get() : null) 58 71 : .nullsFirst(); 59 : 60 : public static CodeReviewRevWalk newRevWalk(Repository repo) { 61 21 : return new CodeReviewRevWalk(repo); 62 : } 63 : 64 : public static CodeReviewRevWalk newRevWalk(ObjectReader reader) { 65 71 : return new CodeReviewRevWalk(reader); 66 : } 67 : 68 : public static class CodeReviewRevWalk extends RevWalk { 69 : private CodeReviewRevWalk(Repository repo) { 70 21 : super(repo); 71 21 : } 72 : 73 : private CodeReviewRevWalk(ObjectReader reader) { 74 71 : super(reader); 75 71 : } 76 : 77 : @Override 78 : protected CodeReviewCommit createCommit(AnyObjectId id) { 79 71 : return new CodeReviewCommit(id); 80 : } 81 : 82 : @Override 83 : public CodeReviewCommit next() 84 : throws MissingObjectException, IncorrectObjectTypeException, IOException { 85 59 : return (CodeReviewCommit) super.next(); 86 : } 87 : 88 : @Override 89 : public void markStart(RevCommit c) 90 : throws MissingObjectException, IncorrectObjectTypeException, IOException { 91 59 : checkArgument(c instanceof CodeReviewCommit); 92 59 : super.markStart(c); 93 59 : } 94 : 95 : @Override 96 : public void markUninteresting(RevCommit c) 97 : throws MissingObjectException, IncorrectObjectTypeException, IOException { 98 54 : checkArgument(c instanceof CodeReviewCommit); 99 54 : super.markUninteresting(c); 100 54 : } 101 : 102 : @Override 103 : public CodeReviewCommit lookupCommit(AnyObjectId id) { 104 67 : return (CodeReviewCommit) super.lookupCommit(id); 105 : } 106 : 107 : @Override 108 : public CodeReviewCommit parseCommit(AnyObjectId id) 109 : throws MissingObjectException, IncorrectObjectTypeException, IOException { 110 71 : return (CodeReviewCommit) super.parseCommit(id); 111 : } 112 : } 113 : 114 : /** 115 : * Unique key of the PatchSet entity from the code review system. 116 : * 117 : * <p>This value is only available on commits that have a PatchSet represented in the code review 118 : * system. 119 : */ 120 : private PatchSet.Id patchsetId; 121 : 122 : private ChangeNotes notes; 123 : 124 : /** 125 : * The result status for this commit. 126 : * 127 : * <p>Only valid if {@link #patchsetId} is not null. 128 : */ 129 : private CommitMergeStatus statusCode; 130 : 131 : /** 132 : * Message for the status that is returned to the calling user if the status indicates a problem 133 : * that prevents submit. 134 : */ 135 71 : private transient Optional<String> statusMessage = Optional.empty(); 136 : 137 : /** List of files in this commit that contain Git conflict markers. */ 138 : private ImmutableSet<String> filesWithGitConflicts; 139 : 140 : public CodeReviewCommit(AnyObjectId id) { 141 71 : super(id); 142 71 : } 143 : 144 : public ChangeNotes notes() { 145 9 : return notes; 146 : } 147 : 148 : public CommitMergeStatus getStatusCode() { 149 53 : return statusCode; 150 : } 151 : 152 : public void setStatusCode(CommitMergeStatus statusCode) { 153 53 : this.statusCode = statusCode; 154 53 : } 155 : 156 : public Optional<String> getStatusMessage() { 157 54 : return statusMessage; 158 : } 159 : 160 : public void setStatusMessage(@Nullable String statusMessage) { 161 6 : this.statusMessage = Optional.ofNullable(statusMessage); 162 6 : } 163 : 164 : public ImmutableSet<String> getFilesWithGitConflicts() { 165 45 : return filesWithGitConflicts != null ? filesWithGitConflicts : ImmutableSet.of(); 166 : } 167 : 168 : public void setFilesWithGitConflicts(@Nullable Set<String> filesWithGitConflicts) { 169 23 : this.filesWithGitConflicts = 170 23 : filesWithGitConflicts != null && !filesWithGitConflicts.isEmpty() 171 5 : ? ImmutableSet.copyOf(filesWithGitConflicts) 172 23 : : null; 173 23 : } 174 : 175 : public PatchSet.Id getPatchsetId() { 176 53 : return patchsetId; 177 : } 178 : 179 : public void setPatchsetId(PatchSet.Id patchsetId) { 180 53 : this.patchsetId = patchsetId; 181 53 : } 182 : 183 : public void copyFrom(CodeReviewCommit src) { 184 13 : notes = src.notes; 185 13 : patchsetId = src.patchsetId; 186 13 : statusCode = src.statusCode; 187 13 : } 188 : 189 : public Change change() { 190 53 : return getNotes().getChange(); 191 : } 192 : 193 : public ChangeNotes getNotes() { 194 53 : return notes; 195 : } 196 : 197 : public void setNotes(ChangeNotes notes) { 198 53 : this.notes = notes; 199 53 : } 200 : 201 : /** Custom serialization due to {@link #statusMessage} not being Serializable by default. */ 202 : private void writeObject(ObjectOutputStream oos) throws IOException { 203 1 : oos.defaultWriteObject(); 204 1 : if (this.statusMessage.isPresent()) { 205 1 : oos.writeUTF(this.statusMessage.get()); 206 : } 207 1 : } 208 : 209 : /** Custom deserialization due to {@link #statusMessage} not being Serializable by default. */ 210 : private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { 211 1 : ois.defaultReadObject(); 212 1 : String statusMessage = null; 213 1 : if (ois.available() > 0) { 214 1 : statusMessage = ois.readUTF(); 215 : } 216 1 : this.statusMessage = Optional.ofNullable(statusMessage); 217 1 : } 218 : }