| // Copyright (C) 2020 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.acceptance.testsuite.change; |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.gerrit.acceptance.testsuite.ThrowingFunction; |
| import com.google.gerrit.entities.Account; |
| import com.google.gerrit.entities.Change; |
| import com.google.gerrit.entities.Project; |
| import com.google.gerrit.server.edit.tree.TreeModification; |
| import java.util.Optional; |
| import org.eclipse.jgit.lib.Constants; |
| import org.eclipse.jgit.merge.MergeStrategy; |
| |
| /** Initial attributes of the change. If not provided, arbitrary values will be used. */ |
| @AutoValue |
| public abstract class TestChangeCreation { |
| public abstract Optional<Project.NameKey> project(); |
| |
| public abstract String branch(); |
| |
| public abstract Optional<Account.Id> owner(); |
| |
| public abstract Optional<String> topic(); |
| |
| public abstract ImmutableMap<String, Short> approvals(); |
| |
| public abstract String commitMessage(); |
| |
| public abstract ImmutableList<TreeModification> treeModifications(); |
| |
| public abstract Optional<ImmutableList<TestCommitIdentifier>> parents(); |
| |
| public abstract MergeStrategy mergeStrategy(); |
| |
| abstract ThrowingFunction<TestChangeCreation, Change.Id> changeCreator(); |
| |
| public static Builder builder(ThrowingFunction<TestChangeCreation, Change.Id> changeCreator) { |
| return new AutoValue_TestChangeCreation.Builder() |
| .changeCreator(changeCreator) |
| .branch(Constants.R_HEADS + Constants.MASTER) |
| .commitMessage("A test change") |
| // Which value we choose here doesn't matter. All relevant code paths set the desired value. |
| .mergeStrategy(MergeStrategy.OURS) |
| .approvals(ImmutableMap.of()); |
| } |
| |
| @AutoValue.Builder |
| public abstract static class Builder { |
| /** Target project/Repository of the change. Must be an existing project. */ |
| public abstract Builder project(Project.NameKey project); |
| |
| /** |
| * Target branch of the change. Neither needs to exist nor needs to point to an actual commit. |
| */ |
| public abstract Builder branch(String branch); |
| |
| /** The change owner. Must be an existing user account. */ |
| public abstract Builder owner(Account.Id owner); |
| |
| /** The topic to add this change to. */ |
| public abstract Builder topic(String topic); |
| |
| /** |
| * The approvals to apply to this change. Map of label name to value. All approvals will be |
| * granted by the uploader. |
| */ |
| public abstract Builder approvals(ImmutableMap<String, Short> approvals); |
| |
| /** |
| * The commit message. The message may contain a {@code Change-Id} footer but does not need to. |
| * If the footer is absent, it will be generated. |
| */ |
| public abstract Builder commitMessage(String commitMessage); |
| |
| /** Modified file of the change. The file content is specified via the returned builder. */ |
| public FileContentBuilder<Builder> file(String filePath) { |
| return new FileContentBuilder<>(this, filePath, treeModificationsBuilder()::add); |
| } |
| |
| abstract ImmutableList.Builder<TreeModification> treeModificationsBuilder(); |
| |
| /** |
| * Parent commit of the change. The commit can be specified via various means in the returned |
| * builder. |
| */ |
| public ParentBuilder<Builder> childOf() { |
| return new ParentBuilder<>(parentCommit -> parents(ImmutableList.of(parentCommit))); |
| } |
| |
| /** |
| * Parent commits of the change. Each parent commit can be specified via various means in the |
| * returned builder. The order of the parents matters and is preserved (first parent commit in |
| * fluent change -> first parent of the change). |
| * |
| * <p>This method will automatically merge the parent commits and use the resulting commit as |
| * base for the change. Use {@link #file(String)} for additional file adjustments on top of that |
| * merge commit. |
| * |
| * <p><strong>Note:</strong> If this method fails with a merge conflict, use {@link |
| * #mergeOfButBaseOnFirst()} instead and specify all other necessary file contents manually via |
| * {@link #file(String)}. |
| */ |
| public ParentBuilder<MultipleParentBuilder<Builder>> mergeOf() { |
| return new ParentBuilder<>(parent -> mergeBuilder(MergeStrategy.RECURSIVE, parent)); |
| } |
| |
| /** |
| * Parent commits of the change. Each parent commit can be specified via various means in the |
| * returned builder. The order of the parents matters and is preserved (first parent commit in |
| * fluent change -> first parent of the change). |
| * |
| * <p>This method will use the first specified parent commit as base for the resulting change. |
| * This approach is especially useful if merging the parents is not possible. |
| */ |
| public ParentBuilder<MultipleParentBuilder<Builder>> mergeOfButBaseOnFirst() { |
| return new ParentBuilder<>(parent -> mergeBuilder(MergeStrategy.OURS, parent)); |
| } |
| |
| MultipleParentBuilder<Builder> mergeBuilder( |
| MergeStrategy mergeStrategy, TestCommitIdentifier parent) { |
| mergeStrategy(mergeStrategy); |
| return new MultipleParentBuilder<>(this::parents, parent); |
| } |
| |
| abstract Builder parents(ImmutableList<TestCommitIdentifier> parents); |
| |
| abstract Builder mergeStrategy(MergeStrategy mergeStrategy); |
| |
| abstract Builder changeCreator(ThrowingFunction<TestChangeCreation, Change.Id> changeCreator); |
| |
| abstract TestChangeCreation autoBuild(); |
| |
| /** |
| * Creates the change. |
| * |
| * @return the {@code Change.Id} of the created change |
| */ |
| public Change.Id create() { |
| TestChangeCreation changeUpdate = autoBuild(); |
| return changeUpdate.changeCreator().applyAndThrowSilently(changeUpdate); |
| } |
| } |
| } |