Make the --other-branches configurable
Introduce a branchOrder section in the project.config in order
to define a branch order and automate the back/forward porting
of changes.
For now assume only one branchOrder section. For example:
[branchOrder]
branch = master
branch = stable-2.9
branch = stable-2.8
branch = stable-2.7
This format makes the ordering obvious (top-down) and complete: for any
two branches from the list the order is defined.
The --other-branches will rely on the branchOrder section in order to
find out a set of branches for which to check mergeability. With the
above example, If a change is pushed to the master branch then the
--other-branches option will test mergeability into the stable-2.9,
stable-2.8 and stable-2.7 branches. If the changed would be pushed to
the stable-2.8 then the --other-branches option would test mergeability
only into the stable-2.7 branch.
Change-Id: Ib806d7e4b5702fa2d8effd197829b729cad95432
diff --git a/Documentation/config-project-config.txt b/Documentation/config-project-config.txt
index 474893d..43ede06 100644
--- a/Documentation/config-project-config.txt
+++ b/Documentation/config-project-config.txt
@@ -198,6 +198,41 @@
documentation for a full list of available capabilities.
+[[branchOrder-section]]
+=== branchOrder section
+
+Defines a branch ordering which is used for backporting of changes.
+Backporting will be offered for a change (in the Gerrit UI) for all
+more stable branches where the change can merge cleanly.
+
+[[branchOrder.branch]]branchOrder.branch::
++
+A branch name, typically multiple values will be defined. The order of branch
+names in this section defines the branch order. The topmost is considered to be
+the least stable branch (typically the master branch) and the last one the
+most stable (typically the last maintained release branch).
+
+Example:
+
+----
+[branchOrder]
+ branch = master
+ branch = stable-2.9
+ branch = stable-2.8
+ branch = stable-2.7
+----
+
+The `branchOrder` section is inheritable. This is useful when multiple or all
+projects follow the same branch rules. A `branchOrder` section in a child
+project completely overrides any `branchOrder` section from a parent i.e. there
+is no merging of `branchOrder` sections. A present but empty `branchOrder`
+section removes all inherited branch order.
+
+Branches not listed in this section will not be included in the mergeability
+check. If the `branchOrder` section is not defined then the mergeability of a
+change into other branches will not be done.
+
+
[[file-groups]]
== The file +groups+
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
index e785736..f2c4adc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
@@ -24,12 +24,14 @@
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.git.BranchOrderSection;
import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeException;
import com.google.gerrit.server.git.strategy.SubmitStrategyFactory;
import com.google.gerrit.server.index.ChangeIndexer;
import com.google.gerrit.server.project.NoSuchProjectException;
+import com.google.gerrit.server.project.ProjectCache;
import com.google.gwtorm.server.AtomicUpdate;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -73,6 +75,7 @@
private final TestSubmitType.Get submitType;
private final GitRepositoryManager gitManager;
+ private final ProjectCache projectCache;
private final SubmitStrategyFactory submitStrategyFactory;
private final Provider<ReviewDb> db;
private final ChangeIndexer indexer;
@@ -82,11 +85,13 @@
@Inject
Mergeable(TestSubmitType.Get submitType,
GitRepositoryManager gitManager,
+ ProjectCache projectCache,
SubmitStrategyFactory submitStrategyFactory,
Provider<ReviewDb> db,
ChangeIndexer indexer) {
this.submitType = submitType;
this.gitManager = gitManager;
+ this.projectCache = projectCache;
this.submitStrategyFactory = submitStrategyFactory;
this.db = db;
this.indexer = indexer;
@@ -124,11 +129,17 @@
if (otherBranches) {
result.mergeableInto = new ArrayList<>();
- for (Ref r : refs.values()) {
- if (r.getName().startsWith(Constants.R_HEADS)
- && !r.getName().equals(ref.getName())) {
- if (isMergeable(change, ps, SubmitType.CHERRY_PICK, git, refs, r)) {
- result.mergeableInto.add(r.getName());
+ BranchOrderSection branchOrder =
+ projectCache.get(change.getProject()).getBranchOrderSection();
+ if (branchOrder != null) {
+ int prefixLen = Constants.R_HEADS.length();
+ for (String n : branchOrder.getMoreStable(ref.getName())) {
+ Ref other = refs.get(n);
+ if (other == null) {
+ continue;
+ }
+ if (isMergeable(change, ps, SubmitType.CHERRY_PICK, git, refs, other)) {
+ result.mergeableInto.add(other.getName().substring(prefixLen));
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java
new file mode 100644
index 0000000..c447d31
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java
@@ -0,0 +1,60 @@
+// Copyright (C) 2014 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.server.git;
+
+import com.google.common.collect.ImmutableList;
+
+import org.eclipse.jgit.lib.Constants;
+
+import java.util.List;
+
+public class BranchOrderSection {
+
+ /**
+ * Branch names ordered from least to the most stable.
+ *
+ * Typically the order will be like: master, stable-M.N, stable-M.N-1, ...
+ */
+ private final ImmutableList<String> order;
+
+ public BranchOrderSection(String[] order) {
+ if (order.length == 0) {
+ this.order = ImmutableList.of();
+ } else {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ for (String b : order) {
+ builder.add(fullName(b));
+ }
+ this.order = builder.build();
+ }
+ }
+
+ private static String fullName(String branch) {
+ if (branch.startsWith(Constants.R_HEADS)) {
+ return branch;
+ } else {
+ return Constants.R_HEADS + branch;
+ }
+ }
+
+ public List<String> getMoreStable(String branch) {
+ int i = order.indexOf(fullName(branch));
+ if (0 <= i) {
+ return order.subList(i + 1, order.size());
+ } else {
+ return ImmutableList.of();
+ }
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index d5dae8e..c4c1b7f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -95,6 +95,9 @@
private static final String ACCOUNTS = "accounts";
private static final String KEY_SAME_GROUP_VISIBILITY = "sameGroupVisibility";
+ private static final String BRANCH_ORDER = "branchOrder";
+ private static final String BRANCH = "branch";
+
private static final String CONTRIBUTOR_AGREEMENT = "contributor-agreement";
private static final String KEY_ACCEPTED = "accepted";
private static final String KEY_REQUIRE_CONTACT_INFORMATION = "requireContactInformation";
@@ -152,6 +155,7 @@
private AccountsSection accountsSection;
private Map<AccountGroup.UUID, GroupReference> groupsByUUID;
private Map<String, AccessSection> accessSections;
+ private BranchOrderSection branchOrderSection;
private Map<String, ContributorAgreement> contributorAgreements;
private Map<String, NotifyConfig> notifySections;
private Map<String, LabelType> labelSections;
@@ -242,6 +246,10 @@
return sort(accessSections.values());
}
+ public BranchOrderSection getBranchOrderSection() {
+ return branchOrderSection;
+ }
+
public void remove(AccessSection section) {
if (section != null) {
accessSections.remove(section.getName());
@@ -420,6 +428,7 @@
loadAccountsSection(rc, groupsByName);
loadContributorAgreements(rc, groupsByName);
loadAccessSections(rc, groupsByName);
+ loadBranchOrderSection(rc);
loadNotifySections(rc, groupsByName);
loadLabelSections(rc);
loadCommentLinkSections(rc);
@@ -570,6 +579,13 @@
}
}
+ private void loadBranchOrderSection(Config rc) {
+ if (rc.getSections().contains(BRANCH_ORDER)) {
+ branchOrderSection = new BranchOrderSection(
+ rc.getStringList(BRANCH_ORDER, null, BRANCH));
+ }
+ }
+
private List<PermissionRule> loadPermissionRules(Config rc, String section,
String subsection, String varName,
Map<String, GroupReference> groupsByName,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index f6b96d7..715419d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -40,6 +40,7 @@
import com.google.gerrit.server.account.GroupMembership;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.git.BranchOrderSection;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.ProjectLevelConfig;
@@ -445,6 +446,16 @@
return ImmutableList.copyOf(cls.values());
}
+ public BranchOrderSection getBranchOrderSection() {
+ for (ProjectState s : tree()) {
+ BranchOrderSection section = s.getConfig().getBranchOrderSection();
+ if (section != null) {
+ return section;
+ }
+ }
+ return null;
+ }
+
public ThemeInfo getTheme() {
ThemeInfo theme = this.theme;
if (theme == null) {