Enable PathCodeOwners to return debug messages

To make the investigation of code owner config files via the Check Code
Owner REST endpoint easier, PathCodeOwners should provide debug
messages about matches per-file rules and imported code owner config
files. For this PathCodeOwners must be able to return messages in
addition to the PathCodeOwnersResult, use OptionalResultWithMessages for
this.

The actual messages in PathCodeOwners will be added by follow-up
changes.

Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: I3dc582da7f7ed46d273c79c6fbdb552a016250e8
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigHierarchy.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigHierarchy.java
index e9db8c8..6f5f7bc 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigHierarchy.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigHierarchy.java
@@ -131,7 +131,7 @@
         boolean visitFurtherCodeOwnerConfigs =
             codeOwnerConfigVisitor.visit(pathCodeOwners.get().getCodeOwnerConfig());
         boolean ignoreParentCodeOwners =
-            pathCodeOwners.get().resolveCodeOwnerConfig().ignoreParentCodeOwners();
+            pathCodeOwners.get().resolveCodeOwnerConfig().get().ignoreParentCodeOwners();
         if (ignoreParentCodeOwners) {
           parentCodeOwnersIgnoredCallback.accept(codeOwnerConfigKey);
         }
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java
index 31dda71..40864e3 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java
@@ -153,10 +153,12 @@
       logger.atFine().log(
           "resolve path code owners (code owner config = %s, path = %s)",
           codeOwnerConfig.key(), absolutePath);
-      PathCodeOwnersResult pathCodeOwnersResult =
+      OptionalResultWithMessages<PathCodeOwnersResult> pathCodeOwnersResult =
           pathCodeOwnersFactory.create(codeOwnerConfig, absolutePath).resolveCodeOwnerConfig();
       return resolve(
-          pathCodeOwnersResult.getPathCodeOwners(), pathCodeOwnersResult.unresolvedImports());
+          pathCodeOwnersResult.get().getPathCodeOwners(),
+          pathCodeOwnersResult.get().unresolvedImports(),
+          pathCodeOwnersResult.messages());
     }
   }
 
@@ -178,7 +180,10 @@
    * @see #resolve(CodeOwnerReference)
    */
   public CodeOwnerResolverResult resolve(Set<CodeOwnerReference> codeOwnerReferences) {
-    return resolve(codeOwnerReferences, /* unresolvedImports= */ ImmutableList.of());
+    return resolve(
+        codeOwnerReferences,
+        /* unresolvedImports= */ ImmutableList.of(),
+        /* pathCodeOwnersMessages= */ ImmutableList.of());
   }
 
   /**
@@ -186,16 +191,20 @@
    *
    * @param codeOwnerReferences the code owner references that should be resolved
    * @param unresolvedImports list of unresolved imports
+   * @param pathCodeOwnersMessages messages that were collected when resolving path code owners
    * @return the {@link CodeOwner} for the given code owner references
    * @see #resolve(CodeOwnerReference)
    */
   private CodeOwnerResolverResult resolve(
-      Set<CodeOwnerReference> codeOwnerReferences, List<UnresolvedImport> unresolvedImports) {
+      Set<CodeOwnerReference> codeOwnerReferences,
+      List<UnresolvedImport> unresolvedImports,
+      ImmutableList<String> pathCodeOwnersMessages) {
     requireNonNull(codeOwnerReferences, "codeOwnerReferences");
     requireNonNull(unresolvedImports, "unresolvedImports");
+    requireNonNull(pathCodeOwnersMessages, "pathCodeOwnersMessages");
     AtomicBoolean ownedByAllUsers = new AtomicBoolean(false);
     AtomicBoolean hasUnresolvedCodeOwners = new AtomicBoolean(false);
-    List<String> messages = new ArrayList<>();
+    List<String> messages = new ArrayList<>(pathCodeOwnersMessages);
     unresolvedImports.forEach(
         unresolvedImport -> messages.add(unresolvedImport.format(codeOwnersPluginConfiguration)));
     ImmutableSet<CodeOwner> codeOwners =
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/PathCodeOwners.java b/java/com/google/gerrit/plugins/codeowners/backend/PathCodeOwners.java
index 036c298..443b5ef 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/PathCodeOwners.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/PathCodeOwners.java
@@ -130,7 +130,7 @@
   private final Path path;
   private final PathExpressionMatcher pathExpressionMatcher;
 
-  private PathCodeOwnersResult pathCodeOwnersResult;
+  private OptionalResultWithMessages<PathCodeOwnersResult> pathCodeOwnersResult;
 
   private PathCodeOwners(
       CodeOwnerMetrics codeOwnerMetrics,
@@ -190,7 +190,7 @@
    *
    * @return the resolved code owner config
    */
-  public PathCodeOwnersResult resolveCodeOwnerConfig() {
+  public OptionalResultWithMessages<PathCodeOwnersResult> resolveCodeOwnerConfig() {
     if (this.pathCodeOwnersResult != null) {
       return this.pathCodeOwnersResult;
     }
@@ -234,7 +234,9 @@
       }
 
       this.pathCodeOwnersResult =
-          PathCodeOwnersResult.create(path, resolvedCodeOwnerConfig, unresolvedImports);
+          OptionalResultWithMessages.create(
+              PathCodeOwnersResult.create(path, resolvedCodeOwnerConfig, unresolvedImports),
+              ImmutableList.of());
       logger.atFine().log("path code owners result = %s", pathCodeOwnersResult);
       return this.pathCodeOwnersResult;
     }
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
index 874400c..7b43770 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
@@ -138,15 +138,17 @@
                   codeOwnerConfig.key().project(),
                   codeOwnerConfig.key().shortBranchName(),
                   codeOwnerConfigFilePath));
-          PathCodeOwnersResult pathCodeOwnersResult =
+          OptionalResultWithMessages<PathCodeOwnersResult> pathCodeOwnersResult =
               pathCodeOwnersFactory.create(codeOwnerConfig, absolutePath).resolveCodeOwnerConfig();
+          messages.addAll(pathCodeOwnersResult.messages());
           pathCodeOwnersResult
+              .get()
               .unresolvedImports()
               .forEach(
                   unresolvedImport ->
                       messages.add(unresolvedImport.format(codeOwnersPluginConfiguration)));
           Optional<CodeOwnerReference> codeOwnerReference =
-              pathCodeOwnersResult.getPathCodeOwners().stream()
+              pathCodeOwnersResult.get().getPathCodeOwners().stream()
                   .filter(cor -> cor.email().equals(email))
                   .findAny();
           if (codeOwnerReference.isPresent()) {
@@ -165,11 +167,11 @@
             }
           }
 
-          if (pathCodeOwnersResult.ignoreParentCodeOwners()) {
+          if (pathCodeOwnersResult.get().ignoreParentCodeOwners()) {
             messages.add("parent code owners are ignored");
           }
 
-          return !pathCodeOwnersResult.ignoreParentCodeOwners();
+          return !pathCodeOwnersResult.get().ignoreParentCodeOwners();
         });
 
     boolean isGlobalCodeOwner = isGlobalCodeOwner(branchResource.getNameKey());
diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/PathCodeOwnersTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/PathCodeOwnersTest.java
index 341b3a3..5490e2e 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/backend/PathCodeOwnersTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/PathCodeOwnersTest.java
@@ -208,8 +208,8 @@
     CodeOwnerConfig emptyCodeOwnerConfig = createCodeOwnerBuilder().build();
     PathCodeOwners pathCodeOwners =
         pathCodeOwnersFactory.create(emptyCodeOwnerConfig, Paths.get("/foo/bar/baz.md"));
-    assertThat(pathCodeOwners.resolveCodeOwnerConfig().getPathCodeOwners()).isEmpty();
-    assertThat(pathCodeOwners.resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().getPathCodeOwners()).isEmpty();
+    assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().hasUnresolvedImports()).isFalse();
   }
 
   @Test
@@ -220,7 +220,7 @@
             .build();
     PathCodeOwners pathCodeOwners =
         pathCodeOwnersFactory.create(codeOwnerConfig, Paths.get("/foo/bar/baz.md"));
-    assertThat(pathCodeOwners.resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
   }
@@ -258,7 +258,7 @@
               .build();
       PathCodeOwners pathCodeOwners =
           pathCodeOwnersFactory.create(codeOwnerConfig, Paths.get("/foo/bar/baz.md"));
-      assertThat(pathCodeOwners.resolveCodeOwnerConfig().getPathCodeOwners())
+      assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().getPathCodeOwners())
           .comparingElementsUsing(hasEmail())
           .containsExactly(admin.email(), user.email());
     }
@@ -279,7 +279,7 @@
               .build();
       PathCodeOwners pathCodeOwners =
           pathCodeOwnersFactory.create(codeOwnerConfig, Paths.get("/foo/bar/baz.md"));
-      assertThat(pathCodeOwners.resolveCodeOwnerConfig().getPathCodeOwners()).isEmpty();
+      assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().getPathCodeOwners()).isEmpty();
     }
   }
 
@@ -311,7 +311,7 @@
               .build();
       PathCodeOwners pathCodeOwners =
           pathCodeOwnersFactory.create(codeOwnerConfig, Paths.get("/foo/bar/baz.md"));
-      assertThat(pathCodeOwners.resolveCodeOwnerConfig().getPathCodeOwners())
+      assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().getPathCodeOwners())
           .comparingElementsUsing(hasEmail())
           .containsExactly(admin.email());
     }
@@ -345,7 +345,7 @@
               .build();
       PathCodeOwners pathCodeOwners =
           pathCodeOwnersFactory.create(codeOwnerConfig, Paths.get("/foo/bar/baz.md"));
-      assertThat(pathCodeOwners.resolveCodeOwnerConfig().getPathCodeOwners())
+      assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().getPathCodeOwners())
           .comparingElementsUsing(hasEmail())
           .containsExactly(admin.email(), user.email());
     }
@@ -380,7 +380,7 @@
               .build();
       PathCodeOwners pathCodeOwners =
           pathCodeOwnersFactory.create(codeOwnerConfig, Paths.get("/foo/bar/baz.md"));
-      assertThat(pathCodeOwners.resolveCodeOwnerConfig().getPathCodeOwners())
+      assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().getPathCodeOwners())
           .comparingElementsUsing(hasEmail())
           .containsExactly(admin.email(), user.email());
     }
@@ -393,7 +393,7 @@
         pathCodeOwnersFactory.create(
             createCodeOwnerBuilder().setIgnoreParentCodeOwners().build(),
             Paths.get("/foo/bar/baz.md"));
-    assertThat(pathCodeOwners.resolveCodeOwnerConfig().ignoreParentCodeOwners()).isTrue();
+    assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().ignoreParentCodeOwners()).isTrue();
   }
 
   @Test
@@ -403,7 +403,7 @@
         pathCodeOwnersFactory.create(
             createCodeOwnerBuilder().setIgnoreParentCodeOwners(false).build(),
             Paths.get("/foo/bar/baz.md"));
-    assertThat(pathCodeOwners.resolveCodeOwnerConfig().ignoreParentCodeOwners()).isFalse();
+    assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().ignoreParentCodeOwners()).isFalse();
   }
 
   @Test
@@ -419,7 +419,7 @@
                         .build())
                 .build(),
             Paths.get("/foo.md"));
-    assertThat(pathCodeOwners.resolveCodeOwnerConfig().ignoreParentCodeOwners()).isTrue();
+    assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().ignoreParentCodeOwners()).isTrue();
   }
 
   @Test
@@ -436,7 +436,7 @@
                         .build())
                 .build(),
             Paths.get("/foo.md"));
-    assertThat(pathCodeOwners.resolveCodeOwnerConfig().ignoreParentCodeOwners()).isFalse();
+    assertThat(pathCodeOwners.resolveCodeOwnerConfig().get().ignoreParentCodeOwners()).isFalse();
   }
 
   @Test
@@ -463,10 +463,10 @@
 
     // Expectation: we get the global code owner from the importing code owner config, the
     // non-resolveable import is silently ignored
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isTrue();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports()).isTrue();
   }
 
   @Test
@@ -509,10 +509,11 @@
 
     // Expectation: we get the global code owners from the importing and the imported code owner
     // config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -555,10 +556,11 @@
 
     // Expectation: we get the matching per-file code owners from the importing and the imported
     // code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -602,10 +604,11 @@
     // Expectation: we only get the matching per-file code owners from the importing code owner
     // config, the per-file code owners from the imported code owner config are not relevant since
     // they do not match
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -650,10 +653,11 @@
     // Expectation: we only get the matching per-file code owners from the importing code owner
     // config, the matching per-file code owners from the imported code owner config are not
     // relevant with import mode GLOBAL_CODE_OWNER_SETS_ONLY
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -699,11 +703,13 @@
     // the matching per-file code owner set in the imported code owner config has the
     // ignoreGlobalAndParentCodeOwners flag set to true which causes global code owners to be
     // ignored, in addition this flag causes parent code owners to be ignored
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().ignoreParentCodeOwners()).isTrue();
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().ignoreParentCodeOwners())
+        .isTrue();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -748,11 +754,13 @@
     // per-file code owners from the imported code owner config and its
     // ignoreGlobalAndParentCodeOwners flag are not relevant since the per-file code owner set does
     // not match
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().ignoreParentCodeOwners()).isFalse();
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().ignoreParentCodeOwners())
+        .isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -797,11 +805,13 @@
     // matching per-file code owners from the imported code owner config and its
     // ignoreGlobalAndParentCodeOwners flag are not relevant with import mode
     // GLOBAL_CODE_OWNER_SETS_ONLY
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().ignoreParentCodeOwners()).isFalse();
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().ignoreParentCodeOwners())
+        .isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -836,7 +846,8 @@
 
     // Expectation: ignoreParentCodeOwners is true because the ignoreParentCodeOwners flag in the
     // imported code owner config is set to true
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().ignoreParentCodeOwners()).isTrue();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().ignoreParentCodeOwners())
+        .isTrue();
   }
 
   @Test
@@ -873,7 +884,8 @@
 
     // Expectation: ignoreParentCodeOwners is false because the ignoreParentCodeOwners flag in the
     // imported code owner config is not relevant with import mode GLOBAL_CODE_OWNER_SETS_ONLY
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().ignoreParentCodeOwners()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().ignoreParentCodeOwners())
+        .isFalse();
   }
 
   @Test
@@ -931,10 +943,11 @@
 
     // Expectation: we get the global owners from the importing code owner config, the imported code
     // owner config and the code owner config that is imported by the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email(), user2.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -990,10 +1003,11 @@
     // Expectation: we get the global owners from the importing code owner config and the imported
     // code owner config but not the per file code owner from the code owner config that is imported
     // by the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1041,7 +1055,7 @@
 
     // Expectation: we get the global code owners from the importing and the imported code owner
     // config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
   }
@@ -1078,7 +1092,7 @@
     assertThat(pathCodeOwners).isPresent();
 
     // Expectation: we get the global owners from the importing and the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
   }
@@ -1125,7 +1139,7 @@
 
     // Expectation: we get the global owners from the importing and the imported code owner config
     // as they were defined at oldRevision
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
   }
@@ -1161,10 +1175,11 @@
     assertThat(pathCodeOwners).isPresent();
 
     // Expectation: we get the global owners from the importing and the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1191,10 +1206,10 @@
     assertThat(pathCodeOwners).isPresent();
 
     // Expectation: we get the global owners from the importing code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isTrue();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports()).isTrue();
   }
 
   @Test
@@ -1236,10 +1251,10 @@
     // Expectation: we get the global owners from the importing code owner config, the global code
     // owners from the imported code owner config are ignored since the project that contains the
     // code owner config is hidden
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isTrue();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports()).isTrue();
   }
 
   @Test
@@ -1267,10 +1282,10 @@
     assertThat(pathCodeOwners).isPresent();
 
     // Expectation: we get the global owners from the importing code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isTrue();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports()).isTrue();
   }
 
   @Test
@@ -1308,10 +1323,11 @@
     assertThat(pathCodeOwners).isPresent();
 
     // Expectation: we get the global owners from the importing and the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1356,10 +1372,11 @@
     assertThat(pathCodeOwners).isPresent();
 
     // Expectation: we get the global owners from the importing and the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1400,10 +1417,11 @@
     assertThat(pathCodeOwners).isPresent();
 
     // Expectation: we get the global owners from the importing and the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1446,10 +1464,11 @@
     assertThat(pathCodeOwners).isPresent();
 
     // Expectation: we get the global owners from the importing and the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1481,10 +1500,10 @@
 
     // Expectation: we get the per file code owner from the importing code owner config, the
     // non-resolveable per file import is silently ignored
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isTrue();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports()).isTrue();
   }
 
   @Test
@@ -1534,13 +1553,15 @@
     // Expectation: we get the per file code owners from the importing and the global code owner
     // from the imported code owner config, but not the per file code owner from the imported code
     // owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
 
     // Expectation: the ignoreParentCodeOwners flag from the imported code owner config is ignored
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().ignoreParentCodeOwners()).isFalse();
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().ignoreParentCodeOwners())
+        .isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1594,10 +1615,11 @@
 
     // Expectation: we get the global owners from the importing code owner config, the imported code
     // owner config and the code owner config that is imported by the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email(), user2.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1654,10 +1676,11 @@
     // Expectation: we get the global owners from the importing code owner config and the imported
     // code owner config, but not the per file code owner from the code owner config that is
     // imported by the imported code owner config
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(admin.email(), user.email());
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().hasUnresolvedImports()).isFalse();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().hasUnresolvedImports())
+        .isFalse();
   }
 
   @Test
@@ -1724,7 +1747,7 @@
             projectOperations.project(project).getHead("master"),
             Paths.get("/foo.xyz"));
     assertThat(pathCodeOwners).isPresent();
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners()).isEmpty();
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners()).isEmpty();
 
     // Expectation for foo.md file: code owners contains only user since foo.md only matches *.md
     pathCodeOwners =
@@ -1733,7 +1756,7 @@
             projectOperations.project(project).getHead("master"),
             Paths.get("/foo.md"));
     assertThat(pathCodeOwners).isPresent();
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(user.email());
 
@@ -1745,7 +1768,7 @@
             projectOperations.project(project).getHead("master"),
             Paths.get("/foo.txt"));
     assertThat(pathCodeOwners).isPresent();
-    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().getPathCodeOwners())
+    assertThat(pathCodeOwners.get().resolveCodeOwnerConfig().get().getPathCodeOwners())
         .comparingElementsUsing(hasEmail())
         .containsExactly(user2.email());
   }