diff options
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.java | 762 |
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}: "cover letter" 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(); - } -} |