| // Copyright (C) 2008 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.gerrit.entities; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| import static com.google.common.collect.ImmutableList.toImmutableList; |
| import static java.util.Objects.requireNonNull; |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.common.base.Splitter; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.primitives.Ints; |
| import com.google.errorprone.annotations.InlineMe; |
| import com.google.gerrit.common.Nullable; |
| import java.time.Instant; |
| import java.util.List; |
| import java.util.Optional; |
| import org.eclipse.jgit.lib.ObjectId; |
| |
| /** A single revision of a {@link Change}. */ |
| @AutoValue |
| public abstract class PatchSet { |
| /** Is the reference name a change reference? */ |
| public static boolean isChangeRef(String name) { |
| return Id.fromRef(name) != null; |
| } |
| |
| /** |
| * Is the reference name a change reference? |
| * |
| * @deprecated use isChangeRef instead. |
| */ |
| @Deprecated |
| @InlineMe( |
| replacement = "PatchSet.isChangeRef(name)", |
| imports = "com.google.gerrit.entities.PatchSet") |
| public static boolean isRef(String name) { |
| return isChangeRef(name); |
| } |
| |
| public static String joinGroups(List<String> groups) { |
| requireNonNull(groups); |
| for (String group : groups) { |
| checkArgument(!group.contains(","), "group may not contain ',': %s", group); |
| } |
| return String.join(",", groups); |
| } |
| |
| public static ImmutableList<String> splitGroups(String joinedGroups) { |
| return Splitter.on(',').splitToStream(joinedGroups).collect(toImmutableList()); |
| } |
| |
| public static Id id(Change.Id changeId, int id) { |
| return new AutoValue_PatchSet_Id(changeId, id); |
| } |
| |
| @AutoValue |
| public abstract static class Id implements Comparable<Id> { |
| /** Parse a PatchSet.Id out of a string representation. */ |
| public static Id parse(String str) { |
| List<String> parts = Splitter.on(',').splitToList(str); |
| checkIdFormat(parts.size() == 2, str); |
| Integer changeId = Ints.tryParse(parts.get(0)); |
| checkIdFormat(changeId != null, str); |
| Integer id = Ints.tryParse(parts.get(1)); |
| checkIdFormat(id != null, str); |
| return PatchSet.id(Change.id(changeId), id); |
| } |
| |
| private static void checkIdFormat(boolean test, String input) { |
| checkArgument(test, "invalid patch set ID: %s", input); |
| } |
| |
| /** Parse a PatchSet.Id from a {@link #refName()} result. */ |
| @Nullable |
| public static Id fromRef(String ref) { |
| int cs = Change.Id.startIndex(ref); |
| if (cs < 0) { |
| return null; |
| } |
| int ce = Change.Id.nextNonDigit(ref, cs); |
| int patchSetId = fromRef(ref, ce); |
| if (patchSetId < 0) { |
| return null; |
| } |
| int changeId = Integer.parseInt(ref.substring(cs, ce)); |
| return PatchSet.id(Change.id(changeId), patchSetId); |
| } |
| |
| /** Parse a PatchSet.Id from an edit ref. */ |
| public static PatchSet.Id fromEditRef(String ref) { |
| Change.Id changeId = Change.Id.fromEditRefPart(ref); |
| return PatchSet.id(changeId, Ints.tryParse(ref.substring(ref.lastIndexOf('/') + 1))); |
| } |
| |
| static int fromRef(String ref, int changeIdEnd) { |
| // Patch set ID. |
| int ps = changeIdEnd + 1; |
| if (ps >= ref.length() || ref.charAt(ps) == '0') { |
| return -1; |
| } |
| for (int i = ps; i < ref.length(); i++) { |
| if (ref.charAt(i) < '0' || ref.charAt(i) > '9') { |
| return -1; |
| } |
| } |
| return Integer.parseInt(ref.substring(ps)); |
| } |
| |
| public static String toId(int number) { |
| return number == 0 ? "edit" : String.valueOf(number); |
| } |
| |
| public String getId() { |
| return toId(id()); |
| } |
| |
| public abstract Change.Id changeId(); |
| |
| abstract int id(); |
| |
| public int get() { |
| return id(); |
| } |
| |
| public String getCommaSeparatedChangeAndPatchSetId() { |
| return changeId().toString() + ',' + id(); |
| } |
| |
| public String toRefName() { |
| return changeId().refPrefixBuilder().append(id()).toString(); |
| } |
| |
| @Override |
| public final String toString() { |
| return getCommaSeparatedChangeAndPatchSetId(); |
| } |
| |
| @Override |
| public int compareTo(Id other) { |
| return Ints.compare(get(), other.get()); |
| } |
| } |
| |
| public static Builder builder() { |
| return new AutoValue_PatchSet.Builder().groups(ImmutableList.of()); |
| } |
| |
| @AutoValue.Builder |
| public abstract static class Builder { |
| public abstract Builder id(Id id); |
| |
| public abstract Id id(); |
| |
| public abstract Builder commitId(ObjectId commitId); |
| |
| public abstract Optional<ObjectId> commitId(); |
| |
| public abstract Builder branch(Optional<String> branch); |
| |
| public abstract Builder branch(String branch); |
| |
| public abstract Builder uploader(Account.Id uploader); |
| |
| public abstract Builder realUploader(Account.Id realUploader); |
| |
| public abstract Builder createdOn(Instant createdOn); |
| |
| public abstract Builder groups(Iterable<String> groups); |
| |
| public abstract ImmutableList<String> groups(); |
| |
| public abstract Builder pushCertificate(Optional<String> pushCertificate); |
| |
| public abstract Builder pushCertificate(String pushCertificate); |
| |
| public abstract Builder description(Optional<String> description); |
| |
| public abstract Builder description(String description); |
| |
| public abstract Optional<String> description(); |
| |
| public abstract PatchSet build(); |
| } |
| |
| /** ID of the patch set. */ |
| public abstract Id id(); |
| |
| /** |
| * Commit ID of the patch set, also known as the revision. |
| * |
| * <p>If this is a deserialized instance that was originally serialized by an older version of |
| * Gerrit, and the old data erroneously did not include a {@code commitId}, then this method will |
| * return {@link ObjectId#zeroId()}. |
| */ |
| public abstract ObjectId commitId(); |
| |
| /** |
| * Name of the target branch where this patch-set should be merged into. If the change is moved, |
| * different patch-sets will have different target branches. |
| */ |
| public abstract Optional<String> branch(); |
| |
| /** |
| * Account that uploaded the patch set. |
| * |
| * <p>If the upload was done on behalf of another user, the impersonated user on whom's behalf the |
| * patch set was uploaded. |
| * |
| * <p>If this is a deserialized instance that was originally serialized by an older version of |
| * Gerrit, and the old data erroneously did not include an {@code uploader}, then this method will |
| * return an account ID of 0. |
| */ |
| public abstract Account.Id uploader(); |
| |
| /** |
| * The real account that uploaded the patch set. |
| * |
| * <p>If this is a deserialized instance that was originally serialized by an older version of |
| * Gerrit, and the old data did not include an {@code realUploader}, then this method will return |
| * the {@code uploader}. |
| */ |
| public abstract Account.Id realUploader(); |
| |
| /** |
| * When this patch set was first introduced onto the change. |
| * |
| * <p>If this is a deserialized instance that was originally serialized by an older version of |
| * Gerrit, and the old data erroneously did not include a {@code createdOn}, then this method will |
| * return a timestamp of 0. |
| */ |
| public abstract Instant createdOn(); |
| |
| /** |
| * Opaque group identifier, usually assigned during creation. |
| * |
| * <p>This field is actually a comma-separated list of values, as in rare cases involving merge |
| * commits a patch set may belong to multiple groups. |
| * |
| * <p>Changes on the same branch having patch sets with intersecting groups are considered |
| * related, as in the "Related Changes" tab. |
| */ |
| public abstract ImmutableList<String> groups(); |
| |
| /** Certificate sent with a push that created this patch set. */ |
| public abstract Optional<String> pushCertificate(); |
| |
| /** |
| * Optional user-supplied description for this patch set. |
| * |
| * <p>When this field is an empty {@code Optional}, the description was never set on the patch |
| * set. When this field is present but an empty string, the description was set and later cleared. |
| */ |
| public abstract Optional<String> description(); |
| |
| /** Patch set number. */ |
| public int number() { |
| return id().get(); |
| } |
| |
| /** Name of the corresponding patch set ref. */ |
| public String refName() { |
| return id().toRefName(); |
| } |
| } |