Line data Source code
1 : // Copyright (C) 2009 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.submit; 16 : 17 : import static java.util.stream.Collectors.toSet; 18 : 19 : import com.google.gerrit.common.Nullable; 20 : import com.google.gerrit.entities.PatchSet; 21 : import com.google.gerrit.server.CurrentUser; 22 : import com.google.gerrit.server.query.change.ChangeData; 23 : import com.google.gerrit.server.query.change.InternalChangeQuery; 24 : import com.google.inject.Provider; 25 : import java.util.List; 26 : import java.util.Optional; 27 : 28 : /** 29 : * Status codes set on {@link com.google.gerrit.server.git.CodeReviewCommit}s by {@link 30 : * SubmitStrategy} implementations. 31 : */ 32 53 : public enum CommitMergeStatus { 33 53 : CLEAN_MERGE("Change has been successfully merged"), 34 : 35 53 : CLEAN_PICK("Change has been successfully cherry-picked"), 36 : 37 53 : CLEAN_REBASE("Change has been successfully rebased and submitted"), 38 : 39 53 : ALREADY_MERGED(""), 40 : 41 53 : PATH_CONFLICT( 42 : "Change could not be merged due to a path conflict.\n" 43 : + "\n" 44 : + "Please rebase the change locally and upload the rebased commit for review."), 45 : 46 53 : REBASE_MERGE_CONFLICT( 47 : "Change could not be merged due to a conflict.\n" 48 : + "\n" 49 : + "Please rebase the change locally and upload the rebased commit for review."), 50 : 51 53 : SKIPPED_IDENTICAL_TREE( 52 : "Marking change merged without cherry-picking to branch, as the resulting commit would be" 53 : + " empty."), 54 : 55 53 : MISSING_DEPENDENCY("Depends on change that was not submitted."), 56 : 57 53 : MANUAL_RECURSIVE_MERGE( 58 : "The change requires a local merge to resolve.\n" 59 : + "\n" 60 : + "Please merge (or rebase) the change locally and upload the resolution for review."), 61 : 62 53 : CANNOT_CHERRY_PICK_ROOT( 63 : "Cannot cherry-pick an initial commit onto an existing branch.\n" 64 : + "\n" 65 : + "Please merge the change locally and upload the merge commit for review."), 66 : 67 53 : CANNOT_REBASE_ROOT( 68 : "Cannot rebase an initial commit onto an existing branch.\n" 69 : + "\n" 70 : + "Please merge the change locally and upload the merge commit for review."), 71 : 72 53 : NOT_FAST_FORWARD( 73 : "Project policy requires all submissions to be a fast-forward.\n" 74 : + "\n" 75 : + "Please rebase the change locally and upload again for review."), 76 : 77 53 : EMPTY_COMMIT( 78 : "Change could not be merged because the commit is empty.\n" 79 : + "\n" 80 : + "Project policy requires all commits to contain modifications to at least one file."), 81 : 82 53 : FAST_FORWARD_INDEPENDENT_CHANGES( 83 : "Change could not be merged because the submission has two independent changes " 84 : + "with the same destination branch.\n" 85 : + "\n" 86 : + "Independent changes can't be submitted to the same destination branch with " 87 : + "FAST_FORWARD_ONLY submit strategy"); 88 : 89 : private final String description; 90 : 91 53 : CommitMergeStatus(String description) { 92 53 : this.description = description; 93 53 : } 94 : 95 : public String getDescription() { 96 53 : return description; 97 : } 98 : 99 : public static String createMissingDependencyMessage( 100 : @Nullable CurrentUser caller, 101 : Provider<InternalChangeQuery> queryProvider, 102 : String commit, 103 : String otherCommit) { 104 5 : List<ChangeData> changes = queryProvider.get().enforceVisibility(true).byCommit(otherCommit); 105 : 106 5 : if (changes.isEmpty()) { 107 1 : return String.format( 108 : "Commit %s depends on commit %s which cannot be merged." 109 : + " Is the change of this commit not visible to '%s' or was it deleted?", 110 1 : commit, otherCommit, caller != null ? caller.getLoggableName() : "<user-not-available>"); 111 5 : } else if (changes.size() == 1) { 112 5 : ChangeData cd = changes.get(0); 113 5 : if (cd.currentPatchSet().commitId().name().equals(otherCommit)) { 114 1 : return String.format( 115 : "Commit %s depends on commit %s of change %d which cannot be merged.", 116 1 : commit, otherCommit, cd.getId().get()); 117 : } 118 5 : Optional<PatchSet> patchSet = 119 5 : cd.patchSets().stream().filter(ps -> ps.commitId().name().equals(otherCommit)).findAny(); 120 5 : if (patchSet.isPresent()) { 121 5 : return String.format( 122 : "Commit %s depends on commit %s, which is outdated patch set %d of change %d." 123 : + " The latest patch set is %d.", 124 : commit, 125 : otherCommit, 126 5 : patchSet.get().id().get(), 127 5 : cd.getId().get(), 128 5 : cd.currentPatchSet().id().get()); 129 : } 130 : // should not happen, fall-back to default message 131 0 : return String.format( 132 : "Commit %s depends on commit %s of change %d which cannot be merged.", 133 0 : commit, otherCommit, cd.getId().get()); 134 : } else { 135 0 : return String.format( 136 : "Commit %s depends on commit %s of changes %s which cannot be merged.", 137 0 : commit, otherCommit, changes.stream().map(cd -> cd.getId().get()).collect(toSet())); 138 : } 139 : } 140 : }