Line data Source code
1 : // Copyright (C) 2014 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; 16 : 17 : import static com.google.common.collect.ImmutableSet.toImmutableSet; 18 : 19 : import com.google.gerrit.common.Nullable; 20 : import com.google.gerrit.entities.Account; 21 : import com.google.gerrit.entities.ChangeMessage; 22 : import com.google.gerrit.entities.PatchSet; 23 : import com.google.gerrit.extensions.common.ChangeMessageInfo; 24 : import com.google.gerrit.server.account.AccountLoader; 25 : import com.google.gerrit.server.notedb.ChangeNotes; 26 : import com.google.gerrit.server.notedb.ChangeUpdate; 27 : import com.google.gerrit.server.update.ChangeContext; 28 : import com.google.gerrit.server.util.AccountTemplateUtil; 29 : import com.google.inject.Inject; 30 : import com.google.inject.Singleton; 31 : import java.util.List; 32 : 33 : /** Utility functions to manipulate {@link ChangeMessage}. */ 34 : @Singleton 35 : public class ChangeMessagesUtil { 36 : public static final String AUTOGENERATED_TAG_PREFIX = "autogenerated:"; 37 : public static final String AUTOGENERATED_BY_GERRIT_TAG_PREFIX = 38 : AUTOGENERATED_TAG_PREFIX + "gerrit:"; 39 : 40 : public static final String TAG_ABANDON = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "abandon"; 41 : public static final String TAG_CHERRY_PICK_CHANGE = 42 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "cherryPickChange"; 43 : public static final String TAG_DELETE_ASSIGNEE = 44 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "deleteAssignee"; 45 : public static final String TAG_DELETE_REVIEWER = 46 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "deleteReviewer"; 47 : public static final String TAG_DELETE_VOTE = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "deleteVote"; 48 : public static final String TAG_MERGED = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "merged"; 49 : public static final String TAG_MOVE = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "move"; 50 : public static final String TAG_RESTORE = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "restore"; 51 : public static final String TAG_REVERT = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "revert"; 52 : public static final String TAG_SET_ASSIGNEE = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "setAssignee"; 53 : public static final String TAG_UPDATE_ATTENTION_SET = 54 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "updateAttentionSet"; 55 : public static final String TAG_SET_DESCRIPTION = 56 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "setPsDescription"; 57 : public static final String TAG_SET_HASHTAGS = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "setHashtag"; 58 : public static final String TAG_SET_PRIVATE = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "setPrivate"; 59 : public static final String TAG_SET_READY = 60 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "setReadyForReview"; 61 : public static final String TAG_SET_TOPIC = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "setTopic"; 62 : public static final String TAG_SET_WIP = AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "setWorkInProgress"; 63 : public static final String TAG_UNSET_PRIVATE = 64 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "unsetPrivate"; 65 : public static final String TAG_UPLOADED_PATCH_SET = 66 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "newPatchSet"; 67 : public static final String TAG_UPLOADED_WIP_PATCH_SET = 68 : AUTOGENERATED_BY_GERRIT_TAG_PREFIX + "newWipPatchSet"; 69 : 70 : private final AccountTemplateUtil accountTemplateUtil; 71 : 72 : @Inject 73 146 : ChangeMessagesUtil(AccountTemplateUtil accountTemplateUtil) { 74 146 : this.accountTemplateUtil = accountTemplateUtil; 75 146 : } 76 : 77 : /** 78 : * Sets {@code messageTemplate} and {@code tag}, that should be applied by the {@code update}. 79 : * 80 : * <p>The {@code messageTemplate} is persisted in storage and should not contain user identifiable 81 : * information. See {@link ChangeMessage}. 82 : * 83 : * @param update update that sets {@code messageTemplate}. 84 : * @param messageTemplate message in template form, that should be applied by the update. 85 : * @param tag tag that should be applied by the update. 86 : * @return message built from {@code messageTemplate}. Templates are replaced, so it might contain 87 : * user identifiable information. 88 : */ 89 : public String setChangeMessage( 90 : ChangeUpdate update, String messageTemplate, @Nullable String tag) { 91 103 : update.setChangeMessage(messageTemplate); 92 103 : update.setTag(tag); 93 103 : return accountTemplateUtil.replaceTemplates(messageTemplate); 94 : } 95 : 96 : /** See {@link #setChangeMessage(ChangeUpdate, String, String)}. */ 97 : public String setChangeMessage(ChangeContext ctx, String messageTemplate, @Nullable String tag) { 98 39 : return setChangeMessage( 99 39 : ctx.getUpdate(ctx.getChange().currentPatchSetId()), messageTemplate, tag); 100 : } 101 : 102 : public static String uploadedPatchSetTag(boolean workInProgress) { 103 103 : return workInProgress ? TAG_UPLOADED_WIP_PATCH_SET : TAG_UPLOADED_PATCH_SET; 104 : } 105 : 106 : /** 107 : * Returns {@link ChangeMessage}s from {@link ChangeNotes}, loads {@link ChangeNotes} from data 108 : * storage (cache or NoteDB), if it was not loaded yet. 109 : */ 110 : public List<ChangeMessage> byChange(ChangeNotes notes) { 111 103 : return notes.load().getChangeMessages(); 112 : } 113 : 114 : /** 115 : * Replace an existing change message with the provided new message. 116 : * 117 : * <p>The ID of a change message is different between NoteDb and ReviewDb. In NoteDb, it's the 118 : * commit SHA-1, but in ReviewDb it was generated randomly. Taking the target message as an index 119 : * rather than an ID allowed us to delete the message from both NoteDb and ReviewDb. 120 : * 121 : * @param update change update. 122 : * @param targetMessageId the id of the target change message. 123 : * @param newMessage the new message which is going to replace the old. 124 : */ 125 : public void replaceChangeMessage(ChangeUpdate update, String targetMessageId, String newMessage) { 126 1 : update.deleteChangeMessageByRewritingHistory(targetMessageId, newMessage); 127 1 : } 128 : 129 : /** 130 : * Determines whether the tag starts with the autogenerated prefix 131 : * 132 : * @param tag value of a tag, or null. 133 : */ 134 : public static boolean isAutogenerated(@Nullable String tag) { 135 65 : return tag != null && tag.startsWith(AUTOGENERATED_TAG_PREFIX); 136 : } 137 : 138 : public static boolean isAutogeneratedByGerrit(@Nullable String tag) { 139 12 : return tag != null && tag.startsWith(AUTOGENERATED_BY_GERRIT_TAG_PREFIX); 140 : } 141 : 142 : public static ChangeMessageInfo createChangeMessageInfo( 143 : ChangeMessage message, AccountLoader accountLoader) { 144 102 : PatchSet.Id patchNum = message.getPatchSetId(); 145 102 : ChangeMessageInfo cmi = new ChangeMessageInfo(); 146 102 : cmi.id = message.getKey().uuid(); 147 102 : cmi.author = accountLoader.get(message.getAuthor()); 148 102 : cmi.setDate(message.getWrittenOn()); 149 102 : cmi.message = message.getMessage(); 150 102 : cmi.tag = message.getTag(); 151 102 : cmi._revisionNumber = patchNum != null ? patchNum.get() : null; 152 102 : Account.Id realAuthor = message.getRealAuthor(); 153 102 : if (realAuthor != null) { 154 102 : cmi.realAuthor = accountLoader.get(realAuthor); 155 : } 156 102 : cmi.accountsInMessage = 157 102 : AccountTemplateUtil.parseTemplates(message.getMessage()).stream() 158 102 : .map(accountLoader::get) 159 102 : .collect(toImmutableSet()); 160 102 : return cmi; 161 : } 162 : 163 : /** 164 : * {@link ChangeMessage} is served in template form to {@link 165 : * com.google.gerrit.extensions.api.changes.ChangeApi}. Serve message with replaced templates to 166 : * the legacy {@link com.google.gerrit.extensions.api.changes.ChangeMessageApi} endpoints. 167 : * TODO(mariasavtchouk): remove this, after {@link 168 : * com.google.gerrit.extensions.api.changes.ChangeMessageApi} is deprecated (gate with 169 : * experiment). 170 : */ 171 : public ChangeMessageInfo createChangeMessageInfoWithReplacedTemplates( 172 : ChangeMessage message, AccountLoader accountLoader) { 173 7 : ChangeMessageInfo changeMessageInfo = createChangeMessageInfo(message, accountLoader); 174 7 : changeMessageInfo.message = accountTemplateUtil.replaceTemplates(message.getMessage()); 175 7 : return changeMessageInfo; 176 : } 177 : }