summaryrefslogtreecommitdiffstats
path: root/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java')
-rw-r--r--gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java762
1 files changed, 0 insertions, 762 deletions
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
deleted file mode 100644
index 201315ed72..0000000000
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
+++ /dev/null
@@ -1,762 +0,0 @@
-// 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.reviewdb.client;
-
-import static com.google.gerrit.reviewdb.client.RefNames.REFS_CHANGES;
-
-import com.google.gerrit.extensions.client.ChangeStatus;
-import com.google.gwtorm.client.Column;
-import com.google.gwtorm.client.IntKey;
-import com.google.gwtorm.client.RowVersion;
-import com.google.gwtorm.client.StringKey;
-import java.sql.Timestamp;
-import java.util.Arrays;
-
-/**
- * A change proposed to be merged into a {@link Branch}.
- *
- * <p>The data graph rooted below a Change can be quite complex:
- *
- * <pre>
- * {@link Change}
- * |
- * +- {@link ChangeMessage}: &quot;cover letter&quot; or general comment.
- * |
- * +- {@link PatchSet}: a single variant of this change.
- * |
- * +- {@link PatchSetApproval}: a +/- vote on the change's current state.
- * |
- * +- {@link PatchLineComment}: comment about a specific line
- * </pre>
- *
- * <p>
- *
- * <h5>PatchSets</h5>
- *
- * <p>Every change has at least one PatchSet. A change starts out with one PatchSet, the initial
- * proposal put forth by the change owner. This {@link Account} is usually also listed as the author
- * and committer in the PatchSetInfo.
- *
- * <p>Each PatchSet contains zero or more Patch records, detailing the file paths impacted by the
- * change (otherwise known as, the file paths the author added/deleted/modified). Sometimes a merge
- * commit can contain zero patches, if the merge has no conflicts, or has no impact other than to
- * cut off a line of development.
- *
- * <p>Each PatchLineComment is a draft or a published comment about a single line of the associated
- * file. These are the inline comment entities created by users as they perform a review.
- *
- * <p>When additional PatchSets appear under a change, these PatchSets reference <i>replacement</i>
- * commits; alternative commits that could be made to the project instead of the original commit
- * referenced by the first PatchSet.
- *
- * <p>A change has at most one current PatchSet. The current PatchSet is updated when a new
- * replacement PatchSet is uploaded. When a change is submitted, the current patch set is what is
- * merged into the destination branch.
- *
- * <p>
- *
- * <h5>ChangeMessage</h5>
- *
- * <p>The ChangeMessage entity is a general free-form comment about the whole change, rather than
- * PatchLineComment's file and line specific context. The ChangeMessage appears at the start of any
- * email generated by Gerrit, and is shown on the change overview page, rather than in a
- * file-specific context. Users often use this entity to describe general remarks about the overall
- * concept proposed by the change.
- *
- * <p>
- *
- * <h5>PatchSetApproval</h5>
- *
- * <p>PatchSetApproval entities exist to fill in the <i>cells</i> of the approvals table in the web
- * UI. That is, a single PatchSetApproval record's key is the tuple {@code
- * (PatchSet,Account,ApprovalCategory)}. Each PatchSetApproval carries with it a small score value,
- * typically within the range -2..+2.
- *
- * <p>If an Account has created only PatchSetApprovals with a score value of 0, the Change shows in
- * their dashboard, and they are said to be CC'd (carbon copied) on the Change, but are not a direct
- * reviewer. This often happens when an account was specified at upload time with the {@code --cc}
- * command line flag, or have published comments, but left the approval scores at 0 ("No Score").
- *
- * <p>If an Account has one or more PatchSetApprovals with a score != 0, the Change shows in their
- * dashboard, and they are said to be an active reviewer. Such individuals are highlighted when
- * notice of a replacement patch set is sent, or when notice of the change submission occurs.
- */
-public final class Change {
- public static class Id extends IntKey<com.google.gwtorm.client.Key<?>> {
- private static final long serialVersionUID = 1L;
-
- @Column(id = 1)
- public int id;
-
- protected Id() {}
-
- public Id(int id) {
- this.id = id;
- }
-
- @Override
- public int get() {
- return id;
- }
-
- @Override
- protected void set(int newValue) {
- id = newValue;
- }
-
- public String toRefPrefix() {
- return refPrefixBuilder().toString();
- }
-
- StringBuilder refPrefixBuilder() {
- StringBuilder r = new StringBuilder(32).append(REFS_CHANGES);
- int m = id % 100;
- if (m < 10) {
- r.append('0');
- }
- return r.append(m).append('/').append(id).append('/');
- }
-
- /** Parse a Change.Id out of a string representation. */
- public static Id parse(String str) {
- final Id r = new Id();
- r.fromString(str);
- return r;
- }
-
- public static Id fromRef(String ref) {
- if (RefNames.isRefsEdit(ref)) {
- return fromEditRefPart(ref);
- }
- int cs = startIndex(ref);
- if (cs < 0) {
- return null;
- }
- int ce = nextNonDigit(ref, cs);
- if (ref.substring(ce).equals(RefNames.META_SUFFIX)
- || ref.substring(ce).equals(RefNames.ROBOT_COMMENTS_SUFFIX)
- || PatchSet.Id.fromRef(ref, ce) >= 0) {
- return new Change.Id(Integer.parseInt(ref.substring(cs, ce)));
- }
- return null;
- }
-
- public static Id fromAllUsersRef(String ref) {
- if (ref == null) {
- return null;
- }
- String prefix;
- if (ref.startsWith(RefNames.REFS_STARRED_CHANGES)) {
- prefix = RefNames.REFS_STARRED_CHANGES;
- } else if (ref.startsWith(RefNames.REFS_DRAFT_COMMENTS)) {
- prefix = RefNames.REFS_DRAFT_COMMENTS;
- } else {
- return null;
- }
- int cs = startIndex(ref, prefix);
- if (cs < 0) {
- return null;
- }
- int ce = nextNonDigit(ref, cs);
- if (ce < ref.length() && ref.charAt(ce) == '/' && isNumeric(ref, ce + 1)) {
- return new Change.Id(Integer.parseInt(ref.substring(cs, ce)));
- }
- return null;
- }
-
- private static boolean isNumeric(String s, int off) {
- if (off >= s.length()) {
- return false;
- }
- for (int i = off; i < s.length(); i++) {
- if (!Character.isDigit(s.charAt(i))) {
- return false;
- }
- }
- return true;
- }
-
- public static Id fromEditRefPart(String ref) {
- int startChangeId = ref.indexOf(RefNames.EDIT_PREFIX) + RefNames.EDIT_PREFIX.length();
- int endChangeId = nextNonDigit(ref, startChangeId);
- String id = ref.substring(startChangeId, endChangeId);
- if (id != null && !id.isEmpty()) {
- return new Change.Id(Integer.parseInt(id));
- }
- return null;
- }
-
- public static Id fromRefPart(String ref) {
- Integer id = RefNames.parseShardedRefPart(ref);
- return id != null ? new Change.Id(id) : null;
- }
-
- static int startIndex(String ref) {
- return startIndex(ref, REFS_CHANGES);
- }
-
- static int startIndex(String ref, String expectedPrefix) {
- if (ref == null || !ref.startsWith(expectedPrefix)) {
- return -1;
- }
-
- // Last 2 digits.
- int ls = expectedPrefix.length();
- int le = nextNonDigit(ref, ls);
- if (le - ls != 2 || le >= ref.length() || ref.charAt(le) != '/') {
- return -1;
- }
-
- // Change ID.
- int cs = le + 1;
- if (cs >= ref.length() || ref.charAt(cs) == '0') {
- return -1;
- }
- int ce = nextNonDigit(ref, cs);
- if (ce >= ref.length() || ref.charAt(ce) != '/') {
- return -1;
- }
- switch (ce - cs) {
- case 0:
- return -1;
- case 1:
- if (ref.charAt(ls) != '0' || ref.charAt(ls + 1) != ref.charAt(cs)) {
- return -1;
- }
- break;
- default:
- if (ref.charAt(ls) != ref.charAt(ce - 2) || ref.charAt(ls + 1) != ref.charAt(ce - 1)) {
- return -1;
- }
- break;
- }
- return cs;
- }
-
- static int nextNonDigit(String s, int i) {
- while (i < s.length() && s.charAt(i) >= '0' && s.charAt(i) <= '9') {
- i++;
- }
- return i;
- }
- }
-
- /** Globally unique identification of this change. */
- public static class Key extends StringKey<com.google.gwtorm.client.Key<?>> {
- private static final long serialVersionUID = 1L;
-
- @Column(id = 1, length = 60)
- protected String id;
-
- protected Key() {}
-
- public Key(String id) {
- this.id = id;
- }
-
- @Override
- public String get() {
- return id;
- }
-
- @Override
- protected void set(String newValue) {
- id = newValue;
- }
-
- /** Construct a key that is after all keys prefixed by this key. */
- public Key max() {
- final StringBuilder revEnd = new StringBuilder(get().length() + 1);
- revEnd.append(get());
- revEnd.append('\u9fa5');
- return new Key(revEnd.toString());
- }
-
- /** Obtain a shorter version of this key string, using a leading prefix. */
- public String abbreviate() {
- final String s = get();
- return s.substring(0, Math.min(s.length(), 9));
- }
-
- /** Parse a Change.Key out of a string representation. */
- public static Key parse(String str) {
- final Key r = new Key();
- r.fromString(str);
- return r;
- }
- }
-
- /** Minimum database status constant for an open change. */
- private static final char MIN_OPEN = 'a';
- /** Database constant for {@link Status#NEW}. */
- public static final char STATUS_NEW = 'n';
- /** Maximum database status constant for an open change. */
- private static final char MAX_OPEN = 'z';
-
- /** Database constant for {@link Status#MERGED}. */
- public static final char STATUS_MERGED = 'M';
-
- /** ID number of the first patch set in a change. */
- public static final int INITIAL_PATCH_SET_ID = 1;
-
- /** Change-Id pattern. */
- public static final String CHANGE_ID_PATTERN = "^[iI][0-9a-f]{4,}.*$";
-
- /**
- * Current state within the basic workflow of the change.
- *
- * <p>Within the database, lower case codes ('a'..'z') indicate a change that is still open, and
- * that can be modified/refined further, while upper case codes ('A'..'Z') indicate a change that
- * is closed and cannot be further modified.
- */
- public enum Status {
- /**
- * Change is open and pending review, or review is in progress.
- *
- * <p>This is the default state assigned to a change when it is first created in the database. A
- * change stays in the NEW state throughout its review cycle, until the change is submitted or
- * abandoned.
- *
- * <p>Changes in the NEW state can be moved to:
- *
- * <ul>
- * <li>{@link #MERGED} - when the Submit Patch Set action is used;
- * <li>{@link #ABANDONED} - when the Abandon action is used.
- * </ul>
- */
- NEW(STATUS_NEW, ChangeStatus.NEW),
-
- /**
- * Change is closed, and submitted to its destination branch.
- *
- * <p>Once a change has been merged, it cannot be further modified by adding a replacement patch
- */
- MERGED(STATUS_MERGED, ChangeStatus.MERGED),
-
- /**
- * Change is closed, but was not submitted to its destination branch.
- *
- * <p>Once a change has been abandoned, it cannot be further modified by adding a replacement
- * patch set, and it cannot be merged. Draft comments however may be published, permitting
- * reviewers to send constructive feedback.
- */
- ABANDONED('A', ChangeStatus.ABANDONED);
-
- static {
- boolean ok = true;
- if (Status.values().length != ChangeStatus.values().length) {
- ok = false;
- }
- for (Status s : Status.values()) {
- ok &= s.name().equals(s.changeStatus.name());
- }
- if (!ok) {
- throw new IllegalStateException(
- "Mismatched status mapping: "
- + Arrays.asList(Status.values())
- + " != "
- + Arrays.asList(ChangeStatus.values()));
- }
- }
-
- private final char code;
- private final boolean closed;
- private final ChangeStatus changeStatus;
-
- Status(char c, ChangeStatus cs) {
- code = c;
- closed = !(MIN_OPEN <= c && c <= MAX_OPEN);
- changeStatus = cs;
- }
-
- public char getCode() {
- return code;
- }
-
- public boolean isOpen() {
- return !closed;
- }
-
- public boolean isClosed() {
- return closed;
- }
-
- public ChangeStatus asChangeStatus() {
- return changeStatus;
- }
-
- public static Status forCode(char c) {
- for (Status s : Status.values()) {
- if (s.code == c) {
- return s;
- }
- }
-
- // TODO(davido): Remove in 3.0, after all sites upgraded to version,
- // where DRAFT status was removed. This code path is still needed,
- // when changes are deserialized from the secondary index, during
- // the online migration to the new schema version wasn't completed.
- if (c == 'd') {
- return Status.NEW;
- }
- return null;
- }
-
- public static Status forChangeStatus(ChangeStatus cs) {
- for (Status s : Status.values()) {
- if (s.changeStatus == cs) {
- return s;
- }
- }
- return null;
- }
- }
-
- /** Locally assigned unique identifier of the change */
- @Column(id = 1)
- protected Id changeId;
-
- /** Globally assigned unique identifier of the change */
- @Column(id = 2)
- protected Key changeKey;
-
- /** optimistic locking */
- @Column(id = 3)
- @RowVersion
- protected int rowVersion;
-
- /** When this change was first introduced into the database. */
- @Column(id = 4)
- protected Timestamp createdOn;
-
- /**
- * When was a meaningful modification last made to this record's data
- *
- * <p>Note, this update timestamp includes its children.
- */
- @Column(id = 5)
- protected Timestamp lastUpdatedOn;
-
- // DELETED: id = 6 (sortkey)
-
- @Column(id = 7, name = "owner_account_id")
- protected Account.Id owner;
-
- /** The branch (and project) this change merges into. */
- @Column(id = 8)
- protected Branch.NameKey dest;
-
- // DELETED: id = 9 (open)
-
- /** Current state code; see {@link Status}. */
- @Column(id = 10)
- protected char status;
-
- // DELETED: id = 11 (nbrPatchSets)
-
- /** The current patch set. */
- @Column(id = 12)
- protected int currentPatchSetId;
-
- /** Subject from the current patch set. */
- @Column(id = 13)
- protected String subject;
-
- /** Topic name assigned by the user, if any. */
- @Column(id = 14, notNull = false)
- protected String topic;
-
- // DELETED: id = 15 (lastSha1MergeTested)
- // DELETED: id = 16 (mergeable)
-
- /**
- * First line of first patch set's commit message.
- *
- * <p>Unlike {@link #subject}, this string does not change if future patch sets change the first
- * line.
- */
- @Column(id = 17, notNull = false)
- protected String originalSubject;
-
- /**
- * Unique id for the changes submitted together assigned during merging. Only set if the status is
- * MERGED.
- */
- @Column(id = 18, notNull = false)
- protected String submissionId;
-
- /** Allows assigning a change to a user. */
- @Column(id = 19, notNull = false)
- protected Account.Id assignee;
-
- /** Whether the change is private. */
- @Column(id = 20)
- protected boolean isPrivate;
-
- /** Whether the change is work in progress. */
- @Column(id = 21)
- protected boolean workInProgress;
-
- /** Whether the change has started review. */
- @Column(id = 22)
- protected boolean reviewStarted;
-
- /** References a change that this change reverts. */
- @Column(id = 23, notNull = false)
- protected Id revertOf;
-
- /** @see com.google.gerrit.server.notedb.NoteDbChangeState */
- @Column(id = 101, notNull = false, length = Integer.MAX_VALUE)
- protected String noteDbState;
-
- protected Change() {}
-
- public Change(
- Change.Key newKey,
- Change.Id newId,
- Account.Id ownedBy,
- Branch.NameKey forBranch,
- Timestamp ts) {
- changeKey = newKey;
- changeId = newId;
- createdOn = ts;
- lastUpdatedOn = createdOn;
- owner = ownedBy;
- dest = forBranch;
- setStatus(Status.NEW);
- }
-
- public Change(Change other) {
- assignee = other.assignee;
- changeId = other.changeId;
- changeKey = other.changeKey;
- rowVersion = other.rowVersion;
- createdOn = other.createdOn;
- lastUpdatedOn = other.lastUpdatedOn;
- owner = other.owner;
- dest = other.dest;
- status = other.status;
- currentPatchSetId = other.currentPatchSetId;
- subject = other.subject;
- originalSubject = other.originalSubject;
- submissionId = other.submissionId;
- topic = other.topic;
- isPrivate = other.isPrivate;
- workInProgress = other.workInProgress;
- reviewStarted = other.reviewStarted;
- noteDbState = other.noteDbState;
- revertOf = other.revertOf;
- }
-
- /** Legacy 32 bit integer identity for a change. */
- public Change.Id getId() {
- return changeId;
- }
-
- /** Legacy 32 bit integer identity for a change. */
- public int getChangeId() {
- return changeId.get();
- }
-
- /** The Change-Id tag out of the initial commit, or a natural key. */
- public Change.Key getKey() {
- return changeKey;
- }
-
- public void setKey(Change.Key k) {
- changeKey = k;
- }
-
- public Account.Id getAssignee() {
- return assignee;
- }
-
- public void setAssignee(Account.Id a) {
- assignee = a;
- }
-
- public Timestamp getCreatedOn() {
- return createdOn;
- }
-
- public void setCreatedOn(Timestamp ts) {
- createdOn = ts;
- }
-
- public Timestamp getLastUpdatedOn() {
- return lastUpdatedOn;
- }
-
- public void setLastUpdatedOn(Timestamp now) {
- lastUpdatedOn = now;
- }
-
- public int getRowVersion() {
- return rowVersion;
- }
-
- public Account.Id getOwner() {
- return owner;
- }
-
- public void setOwner(Account.Id owner) {
- this.owner = owner;
- }
-
- public Branch.NameKey getDest() {
- return dest;
- }
-
- public void setDest(Branch.NameKey dest) {
- this.dest = dest;
- }
-
- public Project.NameKey getProject() {
- return dest.getParentKey();
- }
-
- public String getSubject() {
- return subject;
- }
-
- public String getOriginalSubject() {
- return originalSubject != null ? originalSubject : subject;
- }
-
- public String getOriginalSubjectOrNull() {
- return originalSubject;
- }
-
- /** Get the id of the most current {@link PatchSet} in this change. */
- public PatchSet.Id currentPatchSetId() {
- if (currentPatchSetId > 0) {
- return new PatchSet.Id(changeId, currentPatchSetId);
- }
- return null;
- }
-
- public void setCurrentPatchSet(PatchSetInfo ps) {
- if (originalSubject == null && subject != null) {
- // Change was created before schema upgrade. Use the last subject
- // associated with this change, as the most recent discussion will
- // be under that thread in an email client such as GMail.
- originalSubject = subject;
- }
-
- currentPatchSetId = ps.getKey().get();
- subject = ps.getSubject();
-
- if (originalSubject == null) {
- // Newly created changes remember the first commit's subject.
- originalSubject = subject;
- }
- }
-
- public void setCurrentPatchSet(PatchSet.Id psId, String subject, String originalSubject) {
- if (!psId.getParentKey().equals(changeId)) {
- throw new IllegalArgumentException("patch set ID " + psId + " is not for change " + changeId);
- }
- currentPatchSetId = psId.get();
- this.subject = subject;
- this.originalSubject = originalSubject;
- }
-
- public void clearCurrentPatchSet() {
- currentPatchSetId = 0;
- subject = null;
- originalSubject = null;
- }
-
- public String getSubmissionId() {
- return submissionId;
- }
-
- public void setSubmissionId(String id) {
- this.submissionId = id;
- }
-
- public Status getStatus() {
- return Status.forCode(status);
- }
-
- public void setStatus(Status newStatus) {
- status = newStatus.getCode();
- }
-
- public String getTopic() {
- return topic;
- }
-
- public void setTopic(String topic) {
- this.topic = topic;
- }
-
- public boolean isPrivate() {
- return isPrivate;
- }
-
- public void setPrivate(boolean isPrivate) {
- this.isPrivate = isPrivate;
- }
-
- public boolean isWorkInProgress() {
- return workInProgress;
- }
-
- public void setWorkInProgress(boolean workInProgress) {
- this.workInProgress = workInProgress;
- }
-
- public boolean hasReviewStarted() {
- return reviewStarted;
- }
-
- public void setReviewStarted(boolean reviewStarted) {
- this.reviewStarted = reviewStarted;
- }
-
- public void setRevertOf(Id revertOf) {
- this.revertOf = revertOf;
- }
-
- public Id getRevertOf() {
- return this.revertOf;
- }
-
- public String getNoteDbState() {
- return noteDbState;
- }
-
- public void setNoteDbState(String state) {
- noteDbState = state;
- }
-
- @Override
- public String toString() {
- return new StringBuilder(getClass().getSimpleName())
- .append('{')
- .append(changeId)
- .append(" (")
- .append(changeKey)
- .append("), ")
- .append("dest=")
- .append(dest)
- .append(", ")
- .append("status=")
- .append(status)
- .append('}')
- .toString();
- }
-}