Line data Source code
1 : // Copyright (C) 2020 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.acceptance.testsuite.change; 16 : 17 : import com.google.auto.value.AutoValue; 18 : import com.google.common.collect.ImmutableList; 19 : import com.google.common.collect.ImmutableMap; 20 : import com.google.gerrit.acceptance.testsuite.ThrowingFunction; 21 : import com.google.gerrit.entities.Account; 22 : import com.google.gerrit.entities.Change; 23 : import com.google.gerrit.entities.Project; 24 : import com.google.gerrit.server.edit.tree.TreeModification; 25 : import java.util.Optional; 26 : import org.eclipse.jgit.lib.Constants; 27 : import org.eclipse.jgit.merge.MergeStrategy; 28 : 29 : /** Initial attributes of the change. If not provided, arbitrary values will be used. */ 30 : @AutoValue 31 14 : public abstract class TestChangeCreation { 32 : public abstract Optional<Project.NameKey> project(); 33 : 34 : public abstract String branch(); 35 : 36 : public abstract Optional<Account.Id> owner(); 37 : 38 : public abstract Optional<String> topic(); 39 : 40 : public abstract ImmutableMap<String, Short> approvals(); 41 : 42 : public abstract String commitMessage(); 43 : 44 : public abstract ImmutableList<TreeModification> treeModifications(); 45 : 46 : public abstract Optional<ImmutableList<TestCommitIdentifier>> parents(); 47 : 48 : public abstract MergeStrategy mergeStrategy(); 49 : 50 : abstract ThrowingFunction<TestChangeCreation, Change.Id> changeCreator(); 51 : 52 : public static Builder builder(ThrowingFunction<TestChangeCreation, Change.Id> changeCreator) { 53 14 : return new AutoValue_TestChangeCreation.Builder() 54 14 : .changeCreator(changeCreator) 55 14 : .branch(Constants.R_HEADS + Constants.MASTER) 56 14 : .commitMessage("A test change") 57 : // Which value we choose here doesn't matter. All relevant code paths set the desired value. 58 14 : .mergeStrategy(MergeStrategy.OURS) 59 14 : .approvals(ImmutableMap.of()); 60 : } 61 : 62 : @AutoValue.Builder 63 14 : public abstract static class Builder { 64 : /** Target project/Repository of the change. Must be an existing project. */ 65 : public abstract Builder project(Project.NameKey project); 66 : 67 : /** 68 : * Target branch of the change. Neither needs to exist nor needs to point to an actual commit. 69 : */ 70 : public abstract Builder branch(String branch); 71 : 72 : /** The change owner. Must be an existing user account. */ 73 : public abstract Builder owner(Account.Id owner); 74 : 75 : /** The topic to add this change to. */ 76 : public abstract Builder topic(String topic); 77 : 78 : /** 79 : * The approvals to apply to this change. Map of label name to value. All approvals will be 80 : * granted by the uploader. 81 : */ 82 : public abstract Builder approvals(ImmutableMap<String, Short> approvals); 83 : 84 : /** 85 : * The commit message. The message may contain a {@code Change-Id} footer but does not need to. 86 : * If the footer is absent, it will be generated. 87 : */ 88 : public abstract Builder commitMessage(String commitMessage); 89 : 90 : /** Modified file of the change. The file content is specified via the returned builder. */ 91 : public FileContentBuilder<Builder> file(String filePath) { 92 7 : return new FileContentBuilder<>(this, filePath, 0, treeModificationsBuilder()::add); 93 : } 94 : 95 : /** 96 : * Modified file of the change. The file content is specified via the returned builder. The 97 : * second parameter indicates the git file mode for the modified file if it has been changed. 98 : * 99 : * @see org.eclipse.jgit.lib.FileMode 100 : */ 101 : public FileContentBuilder<Builder> file(String filePath, int newGitFileMode) { 102 0 : return new FileContentBuilder<>( 103 0 : this, filePath, newGitFileMode, treeModificationsBuilder()::add); 104 : } 105 : 106 : abstract ImmutableList.Builder<TreeModification> treeModificationsBuilder(); 107 : 108 : /** 109 : * Parent commit of the change. The commit can be specified via various means in the returned 110 : * builder. 111 : */ 112 : public ParentBuilder<Builder> childOf() { 113 3 : return new ParentBuilder<>(parentCommit -> parents(ImmutableList.of(parentCommit))); 114 : } 115 : 116 : /** 117 : * Parent commits of the change. Each parent commit can be specified via various means in the 118 : * returned builder. The order of the parents matters and is preserved (first parent commit in 119 : * fluent change -> first parent of the change). 120 : * 121 : * <p>This method will automatically merge the parent commits and use the resulting commit as 122 : * base for the change. Use {@link #file(String)} for additional file adjustments on top of that 123 : * merge commit. 124 : * 125 : * <p><strong>Note:</strong> If this method fails with a merge conflict, use {@link 126 : * #mergeOfButBaseOnFirst()} instead and specify all other necessary file contents manually via 127 : * {@link #file(String)}. 128 : */ 129 : public ParentBuilder<MultipleParentBuilder<Builder>> mergeOf() { 130 3 : return new ParentBuilder<>(parent -> mergeBuilder(MergeStrategy.RECURSIVE, parent)); 131 : } 132 : 133 : /** 134 : * Parent commits of the change. Each parent commit can be specified via various means in the 135 : * returned builder. The order of the parents matters and is preserved (first parent commit in 136 : * fluent change -> first parent of the change). 137 : * 138 : * <p>This method will use the first specified parent commit as base for the resulting change. 139 : * This approach is especially useful if merging the parents is not possible. 140 : */ 141 : public ParentBuilder<MultipleParentBuilder<Builder>> mergeOfButBaseOnFirst() { 142 2 : return new ParentBuilder<>(parent -> mergeBuilder(MergeStrategy.OURS, parent)); 143 : } 144 : 145 : MultipleParentBuilder<Builder> mergeBuilder( 146 : MergeStrategy mergeStrategy, TestCommitIdentifier parent) { 147 4 : mergeStrategy(mergeStrategy); 148 4 : return new MultipleParentBuilder<>(this::parents, parent); 149 : } 150 : 151 : abstract Builder parents(ImmutableList<TestCommitIdentifier> parents); 152 : 153 : abstract Builder mergeStrategy(MergeStrategy mergeStrategy); 154 : 155 : abstract Builder changeCreator(ThrowingFunction<TestChangeCreation, Change.Id> changeCreator); 156 : 157 : abstract TestChangeCreation autoBuild(); 158 : 159 : /** 160 : * Creates the change. 161 : * 162 : * @return the {@code Change.Id} of the created change 163 : */ 164 : public Change.Id create() { 165 14 : TestChangeCreation changeUpdate = autoBuild(); 166 14 : return changeUpdate.changeCreator().applyAndThrowSilently(changeUpdate); 167 : } 168 : } 169 : }