ChangeInfo: Add a field with the full branch name

The existing 'branch' field in ChangeInfo contains the short branch
name, unless the change is for a branch outside the 'refs/heads/'
namespace (e.g. 'refs/meta/config'). In this case it contains the full
branch name. This means all callers that need the full branch name must
have logic to prefix the branch name with 'refs/heads/' if it doesn't
start with 'refs/'. To make this simpler add a new 'full_branch' field
that always contains the full branch name.

Release-Notes: Add a field with the full branch name to ChangeInfo
Bug: Google b/450186704
Change-Id: I10d281579542dc955decc7af4d08e91d7ea5712f
Signed-off-by: Edwin Kempin <ekempin@google.com>
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index f3dc24a..233c514 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -7617,6 +7617,9 @@
 |`branch`             ||
 The name of the target branch. +
 The `refs/heads/` prefix is omitted.
+|`full_branch`             ||
+The full name of the target branch. +
+Always starts with `refs/`.
 |`subject`            ||
 The commit message of the change. Comment lines (beginning with `#`)
 will be removed. If the commit message contains a Change-Id (as a
diff --git a/java/com/google/gerrit/extensions/common/ChangeInfo.java b/java/com/google/gerrit/extensions/common/ChangeInfo.java
index 28d99de..c7b7054 100644
--- a/java/com/google/gerrit/extensions/common/ChangeInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeInfo.java
@@ -40,7 +40,21 @@
   public String tripletId;
 
   public String project;
+
+  /**
+   * The name of the target branch.
+   *
+   * <p>The {@code refs/heads/} prefix is omitted.
+   */
   public String branch;
+
+  /**
+   * The full name of the target branch.
+   *
+   * <p>Always starts with {@code refs/}.
+   */
+  public String fullBranch;
+
   public String topic;
 
   /**
diff --git a/java/com/google/gerrit/server/change/ActionJson.java b/java/com/google/gerrit/server/change/ActionJson.java
index 950d390..3bc3b6d 100644
--- a/java/com/google/gerrit/server/change/ActionJson.java
+++ b/java/com/google/gerrit/server/change/ActionJson.java
@@ -119,6 +119,7 @@
     ChangeInfo copy = new ChangeInfo();
     copy.project = changeInfo.project;
     copy.branch = changeInfo.branch;
+    copy.fullBranch = changeInfo.fullBranch;
     copy.topic = changeInfo.topic;
     copy.attentionSet =
         changeInfo.attentionSet == null ? null : ImmutableMap.copyOf(changeInfo.attentionSet);
diff --git a/java/com/google/gerrit/server/change/ChangeJson.java b/java/com/google/gerrit/server/change/ChangeJson.java
index 41e02ca..fb2db3a 100644
--- a/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/java/com/google/gerrit/server/change/ChangeJson.java
@@ -611,6 +611,7 @@
     if (c != null) {
       info.project = c.getProject().get();
       info.branch = c.getDest().shortName();
+      info.fullBranch = c.getDest().branch();
       info.topic = c.getTopic();
       info.changeId = c.getKey().get();
       info.subject = c.getSubject();
@@ -663,6 +664,7 @@
     Change in = cd.change();
     out.project = in.getProject().get();
     out.branch = in.getDest().shortName();
+    out.fullBranch = in.getDest().branch();
     out.currentRevisionNumber = in.currentPatchSetId().get();
     out.topic = in.getTopic();
     if (!cd.attentionSet().isEmpty()) {
@@ -1136,6 +1138,7 @@
     }
     info.project = c.getProject().get();
     info.branch = c.getDest().shortName();
+    info.fullBranch = c.getDest().branch();
     info.changeId = c.getKey().get();
     info._number = c.getId().get();
     info.subject = "***ERROR***";
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index dc1ee97..0801328 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -270,6 +270,7 @@
     assertThat(changeInfo.id).isEqualTo(change.project() + "~" + change.numericChangeId());
     assertThat(changeInfo.project).isEqualTo(change.project().get());
     assertThat(changeInfo.branch).isEqualTo(change.dest().shortName());
+    assertThat(changeInfo.fullBranch).isEqualTo(change.dest().branch());
     assertThat(changeInfo.status).isEqualTo(ChangeStatus.NEW);
     assertThat(changeInfo.subject).isEqualTo(change.subject());
     assertThat(changeInfo.submitType).isEqualTo(SubmitType.MERGE_IF_NECESSARY);
@@ -2796,7 +2797,8 @@
     in.project = project.get();
     ChangeInfo info = gApi.changes().create(in).get();
     assertThat(info.project).isEqualTo(in.project);
-    assertThat(RefNames.fullName(info.branch)).isEqualTo(RefNames.fullName(in.branch));
+    assertThat(info.branch).isEqualTo(Constants.MASTER);
+    assertThat(info.fullBranch).isEqualTo(RefNames.fullName(Constants.MASTER));
     assertThat(info.subject).isEqualTo(in.subject);
     assertThat(Iterables.getOnlyElement(info.messages).message).isEqualTo("Uploaded patch set 1.");
   }
@@ -3556,7 +3558,8 @@
     in.newBranch = true;
     ChangeInfo info = gApi.changes().create(in).get();
     assertThat(info.project).isEqualTo(in.project);
-    assertThat(RefNames.fullName(info.branch)).isEqualTo(RefNames.fullName(in.branch));
+    assertThat(info.branch).isEqualTo("foo");
+    assertThat(info.fullBranch).isEqualTo(RefNames.fullName("foo"));
     assertThat(info.subject).isEqualTo(in.subject);
     assertThat(Iterables.getOnlyElement(info.messages).message).isEqualTo("Uploaded patch set 1.");
   }