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.entities; 16 : 17 : import static com.google.common.base.Preconditions.checkArgument; 18 : import static com.google.common.collect.ImmutableList.toImmutableList; 19 : import static java.util.Objects.requireNonNull; 20 : 21 : import com.google.auto.value.AutoValue; 22 : import com.google.common.base.Splitter; 23 : import com.google.common.collect.ImmutableList; 24 : import com.google.common.primitives.Ints; 25 : import com.google.errorprone.annotations.InlineMe; 26 : import com.google.gerrit.common.Nullable; 27 : import java.time.Instant; 28 : import java.util.List; 29 : import java.util.Optional; 30 : import org.eclipse.jgit.lib.ObjectId; 31 : 32 : /** A single revision of a {@link Change}. */ 33 : @AutoValue 34 105 : public abstract class PatchSet { 35 : /** Is the reference name a change reference? */ 36 : public static boolean isChangeRef(String name) { 37 27 : return Id.fromRef(name) != null; 38 : } 39 : 40 : /** 41 : * Is the reference name a change reference? 42 : * 43 : * @deprecated use isChangeRef instead. 44 : */ 45 : @Deprecated 46 : @InlineMe( 47 : replacement = "PatchSet.isChangeRef(name)", 48 : imports = "com.google.gerrit.entities.PatchSet") 49 : public static boolean isRef(String name) { 50 0 : return isChangeRef(name); 51 : } 52 : 53 : public static String joinGroups(List<String> groups) { 54 105 : requireNonNull(groups); 55 105 : for (String group : groups) { 56 105 : checkArgument(!group.contains(","), "group may not contain ',': %s", group); 57 105 : } 58 105 : return String.join(",", groups); 59 : } 60 : 61 : public static ImmutableList<String> splitGroups(String joinedGroups) { 62 105 : return Splitter.on(',').splitToStream(joinedGroups).collect(toImmutableList()); 63 : } 64 : 65 : public static Id id(Change.Id changeId, int id) { 66 107 : return new AutoValue_PatchSet_Id(changeId, id); 67 : } 68 : 69 : @AutoValue 70 107 : public abstract static class Id implements Comparable<Id> { 71 : /** Parse a PatchSet.Id out of a string representation. */ 72 : public static Id parse(String str) { 73 12 : List<String> parts = Splitter.on(',').splitToList(str); 74 12 : checkIdFormat(parts.size() == 2, str); 75 12 : Integer changeId = Ints.tryParse(parts.get(0)); 76 12 : checkIdFormat(changeId != null, str); 77 12 : Integer id = Ints.tryParse(parts.get(1)); 78 12 : checkIdFormat(id != null, str); 79 12 : return PatchSet.id(Change.id(changeId), id); 80 : } 81 : 82 : private static void checkIdFormat(boolean test, String input) { 83 12 : checkArgument(test, "invalid patch set ID: %s", input); 84 12 : } 85 : 86 : /** Parse a PatchSet.Id from a {@link #refName()} result. */ 87 : @Nullable 88 : public static Id fromRef(String ref) { 89 101 : int cs = Change.Id.startIndex(ref); 90 101 : if (cs < 0) { 91 45 : return null; 92 : } 93 101 : int ce = Change.Id.nextNonDigit(ref, cs); 94 101 : int patchSetId = fromRef(ref, ce); 95 101 : if (patchSetId < 0) { 96 72 : return null; 97 : } 98 101 : int changeId = Integer.parseInt(ref.substring(cs, ce)); 99 101 : return PatchSet.id(Change.id(changeId), patchSetId); 100 : } 101 : 102 : /** Parse a PatchSet.Id from an edit ref. */ 103 : public static PatchSet.Id fromEditRef(String ref) { 104 28 : Change.Id changeId = Change.Id.fromEditRefPart(ref); 105 28 : return PatchSet.id(changeId, Ints.tryParse(ref.substring(ref.lastIndexOf('/') + 1))); 106 : } 107 : 108 : static int fromRef(String ref, int changeIdEnd) { 109 : // Patch set ID. 110 101 : int ps = changeIdEnd + 1; 111 101 : if (ps >= ref.length() || ref.charAt(ps) == '0') { 112 1 : return -1; 113 : } 114 101 : for (int i = ps; i < ref.length(); i++) { 115 101 : if (ref.charAt(i) < '0' || ref.charAt(i) > '9') { 116 72 : return -1; 117 : } 118 : } 119 101 : return Integer.parseInt(ref.substring(ps)); 120 : } 121 : 122 : public static String toId(int number) { 123 11 : return number == 0 ? "edit" : String.valueOf(number); 124 : } 125 : 126 : public String getId() { 127 11 : return toId(id()); 128 : } 129 : 130 : public abstract Change.Id changeId(); 131 : 132 : abstract int id(); 133 : 134 : public int get() { 135 106 : return id(); 136 : } 137 : 138 : public String getCommaSeparatedChangeAndPatchSetId() { 139 71 : return changeId().toString() + ',' + id(); 140 : } 141 : 142 : public String toRefName() { 143 104 : return changeId().refPrefixBuilder().append(id()).toString(); 144 : } 145 : 146 : @Override 147 : public final String toString() { 148 14 : return getCommaSeparatedChangeAndPatchSetId(); 149 : } 150 : 151 : @Override 152 : public int compareTo(Id other) { 153 103 : return Ints.compare(get(), other.get()); 154 : } 155 : } 156 : 157 : public static Builder builder() { 158 105 : return new AutoValue_PatchSet.Builder().groups(ImmutableList.of()); 159 : } 160 : 161 : @AutoValue.Builder 162 105 : public abstract static class Builder { 163 : public abstract Builder id(Id id); 164 : 165 : public abstract Id id(); 166 : 167 : public abstract Builder commitId(ObjectId commitId); 168 : 169 : public abstract Optional<ObjectId> commitId(); 170 : 171 : public abstract Builder uploader(Account.Id uploader); 172 : 173 : public abstract Builder createdOn(Instant createdOn); 174 : 175 : public abstract Builder groups(Iterable<String> groups); 176 : 177 : public abstract ImmutableList<String> groups(); 178 : 179 : public abstract Builder pushCertificate(Optional<String> pushCertificate); 180 : 181 : public abstract Builder pushCertificate(String pushCertificate); 182 : 183 : public abstract Builder description(Optional<String> description); 184 : 185 : public abstract Builder description(String description); 186 : 187 : public abstract Optional<String> description(); 188 : 189 : public abstract PatchSet build(); 190 : } 191 : 192 : /** ID of the patch set. */ 193 : public abstract Id id(); 194 : 195 : /** 196 : * Commit ID of the patch set, also known as the revision. 197 : * 198 : * <p>If this is a deserialized instance that was originally serialized by an older version of 199 : * Gerrit, and the old data erroneously did not include a {@code commitId}, then this method will 200 : * return {@link ObjectId#zeroId()}. 201 : */ 202 : public abstract ObjectId commitId(); 203 : 204 : /** 205 : * Account that uploaded the patch set. 206 : * 207 : * <p>If this is a deserialized instance that was originally serialized by an older version of 208 : * Gerrit, and the old data erroneously did not include an {@code uploader}, then this method will 209 : * return an account ID of 0. 210 : */ 211 : public abstract Account.Id uploader(); 212 : 213 : /** 214 : * When this patch set was first introduced onto the change. 215 : * 216 : * <p>If this is a deserialized instance that was originally serialized by an older version of 217 : * Gerrit, and the old data erroneously did not include a {@code createdOn}, then this method will 218 : * return a timestamp of 0. 219 : */ 220 : public abstract Instant createdOn(); 221 : 222 : /** 223 : * Opaque group identifier, usually assigned during creation. 224 : * 225 : * <p>This field is actually a comma-separated list of values, as in rare cases involving merge 226 : * commits a patch set may belong to multiple groups. 227 : * 228 : * <p>Changes on the same branch having patch sets with intersecting groups are considered 229 : * related, as in the "Related Changes" tab. 230 : */ 231 : public abstract ImmutableList<String> groups(); 232 : 233 : /** Certificate sent with a push that created this patch set. */ 234 : public abstract Optional<String> pushCertificate(); 235 : 236 : /** 237 : * Optional user-supplied description for this patch set. 238 : * 239 : * <p>When this field is an empty {@code Optional}, the description was never set on the patch 240 : * set. When this field is present but an empty string, the description was set and later cleared. 241 : */ 242 : public abstract Optional<String> description(); 243 : 244 : /** Patch set number. */ 245 : public int number() { 246 103 : return id().get(); 247 : } 248 : 249 : /** Name of the corresponding patch set ref. */ 250 : public String refName() { 251 103 : return id().toRefName(); 252 : } 253 : }