RepositoryResolvedEvent: represent modifications as named arguments

The RepositoryResolvedEvent was added to record the modified arguments a rule
returned in a resolved file. As such, they were thought of as dicts in Starlark
terms. However, the message this event produces is most useful for users who
wish to update their WORKSPACE file by hand. So make it more easy to copy and
paste.

Change-Id: I71e193a896c1d07cde3d5c1ebe1eb44eca52b659
PiperOrigin-RevId: 234591760
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEvent.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEvent.java
index 60589f6..72926ee 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEvent.java
@@ -132,14 +132,14 @@
                   + rule.getName()
                   + "' indicated that a canonical reproducible form can be obtained by"
                   + " modifying arguments "
-                  + Printer.getPrinter().repr(diff.getFirst());
+                  + representModifications(diff.getFirst());
         } else {
           this.message =
               "Rule '"
                   + rule.getName()
                   + "' indicated that a canonical reproducible form can be obtained by"
                   + " modifying arguments "
-                  + Printer.getPrinter().repr(diff.getFirst())
+                  + representModifications(diff.getFirst())
                   + " and dropping "
                   + Printer.getPrinter().repr(diff.getSecond());
         }
@@ -216,4 +216,20 @@
     }
     return Pair.of(valuesChanged.build(), keysDropped.build());
   }
+
+  static String representModifications(Map<String, Object> changes) {
+    StringBuilder representation = new StringBuilder();
+    boolean isFirst = true;
+    for (Map.Entry<String, Object> entry : changes.entrySet()) {
+      if (!isFirst) {
+        representation.append(", ");
+      }
+      representation
+          .append(entry.getKey())
+          .append(" = ")
+          .append(Printer.getPrinter().repr(entry.getValue()));
+      isFirst = false;
+    }
+    return representation.toString();
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEventTest.java b/src/test/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEventTest.java
index 7444e53..c5cb6bc 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEventTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEventTest.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.util.Pair;
 import java.util.List;
@@ -80,4 +81,20 @@
     assertThat(result.getFirst()).containsExactly("foo", "new", "bar", "otherValue");
     assertThat(result.getSecond()).isEmpty();
   }
+
+  @Test
+  public void testRepresentModifications() {
+    assertThat(
+            RepositoryResolvedEvent.representModifications(
+                ImmutableMap.<String, Object>of("a", "b", "c", "d")))
+        .isEqualTo("a = \"b\", c = \"d\"");
+    assertThat(
+            RepositoryResolvedEvent.representModifications(
+                ImmutableMap.<String, Object>of("a", 1, "b", 2)))
+        .isEqualTo("a = 1, b = 2");
+    assertThat(
+            RepositoryResolvedEvent.representModifications(
+                ImmutableMap.<String, Object>of("a", ImmutableList.<Integer>of(1, 2, 3))))
+        .isEqualTo("a = [1, 2, 3]");
+  }
 }