Merge "CodeOwnerConfigOperations: Add method to get file path of a code owner config"
diff --git a/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperations.java b/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperations.java
index 8f5f28e..4d7f536 100644
--- a/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperations.java
+++ b/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperations.java
@@ -91,6 +91,25 @@
     CodeOwnerConfig get();
 
     /**
+     * Retrieves the file path of the code owner config for use in the JGit API (where paths must
+     * not start with a '/').
+     *
+     * <p>Works regardless of whether the code owner config exists.
+     *
+     * @return the file path of the code owner config
+     */
+    String getJGitFilePath();
+
+    /**
+     * Retrieves the absolute file path of the code owner config.
+     *
+     * <p>Works regardless of whether the code owner config exists.
+     *
+     * @return the absolute file path of the code owner config
+     */
+    String getFilePath();
+
+    /**
      * Starts the fluent chain to update a code owner config. The returned builder can be used to
      * specify how the attributes of the code owner config should be modified. To update the code
      * owner config for real, {@link TestCodeOwnerConfigUpdate.Builder#update()} must be called.
diff --git a/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperationsImpl.java b/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperationsImpl.java
index fba2512..1e98136 100644
--- a/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperationsImpl.java
+++ b/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperationsImpl.java
@@ -16,15 +16,19 @@
 
 import static com.google.common.base.Preconditions.checkState;
 
+import com.google.gerrit.plugins.codeowners.JgitPath;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfigImportModification;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfigUpdate;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwnerSetModification;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwners;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwnersUpdate;
+import com.google.gerrit.plugins.codeowners.config.BackendConfig;
 import com.google.gerrit.server.ServerInitiated;
+import com.google.gerrit.server.project.ProjectCache;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import java.nio.file.Path;
 import java.util.Optional;
 
 /**
@@ -36,12 +40,19 @@
 public class CodeOwnerConfigOperationsImpl implements CodeOwnerConfigOperations {
   private final CodeOwners codeOwners;
   private final Provider<CodeOwnersUpdate> codeOwnersUpdate;
+  private final ProjectCache projectCache;
+  private final BackendConfig backendConfig;
 
   @Inject
   CodeOwnerConfigOperationsImpl(
-      CodeOwners codeOwners, @ServerInitiated Provider<CodeOwnersUpdate> codeOwnersUpdate) {
+      CodeOwners codeOwners,
+      @ServerInitiated Provider<CodeOwnersUpdate> codeOwnersUpdate,
+      ProjectCache projectCache,
+      BackendConfig backendConfig) {
     this.codeOwners = codeOwners;
     this.codeOwnersUpdate = codeOwnersUpdate;
+    this.projectCache = projectCache;
+    this.backendConfig = backendConfig;
   }
 
   @Override
@@ -114,6 +125,26 @@
     }
 
     @Override
+    public String getJGitFilePath() {
+      return JgitPath.of(filePath()).get();
+    }
+
+    @Override
+    public String getFilePath() {
+      return filePath().toString();
+    }
+
+    private Path filePath() {
+      if (projectCache.get(codeOwnerConfigKey.project()).isPresent()) {
+        return codeOwners.getFilePath(codeOwnerConfigKey);
+      }
+
+      // if the project doesn't exist, use the backend which is configured on host level to compute
+      // the file path
+      return backendConfig.getDefaultBackend().getFilePath(codeOwnerConfigKey);
+    }
+
+    @Override
     public TestCodeOwnerConfigUpdate.Builder forUpdate() {
       return TestCodeOwnerConfigUpdate.builder(this::updateCodeOwnerConfig);
     }
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwners.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwners.java
index 5f697d2..02a3d1e 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwners.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwners.java
@@ -20,6 +20,7 @@
 import com.google.gerrit.plugins.codeowners.config.CodeOwnersPluginConfiguration;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import java.nio.file.Path;
 import java.util.Optional;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.ObjectId;
@@ -73,6 +74,25 @@
   }
 
   /**
+   * Returns the absolute file path of the specified code owner config.
+   *
+   * <p>This method is useful to resolve the file path if the {@link CodeOwnerConfig.Key#fileName()}
+   * in the code owner config key is not set.
+   *
+   * <p>The specified code owner config may or may not exist.
+   *
+   * @param codeOwnerConfigKey the key of the code owner config for which the file path should be
+   *     returned
+   * @return the absolute file path of the specified code owner config
+   */
+  public Path getFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
+    requireNonNull(codeOwnerConfigKey, "codeOwnerConfigKey");
+    CodeOwnerBackend codeOwnerBackend =
+        codeOwnersPluginConfiguration.getBackend(codeOwnerConfigKey.branchNameKey());
+    return codeOwnerBackend.getFilePath(codeOwnerConfigKey);
+  }
+
+  /**
    * Checks whether the given exception was caused by a non-parseable code owner config ({@link
    * ConfigInvalidException}). If yes, the {@link ConfigInvalidException} is returned. If no, {@link
    * Optional#empty()} is returned.
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerConfigFilesIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerConfigFilesIT.java
index b163b1f..c1d7f0b 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerConfigFilesIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerConfigFilesIT.java
@@ -188,6 +188,8 @@
                 CodeOwnerConfigReference.create(
                     CodeOwnerConfigImportMode.ALL, "/not-a-code-owner-config"))
             .create();
+    String pathOfInvalidConfig1 =
+        codeOwnerConfigOperations.codeOwnerConfig(keyOfInvalidConfig1).getFilePath();
 
     CodeOwnerConfig.Key keyOfInvalidConfig2 =
         codeOwnerConfigOperations
@@ -198,6 +200,8 @@
             .addCodeOwnerEmail("unknown1@example.com")
             .addCodeOwnerEmail("unknown2@example.com")
             .create();
+    String pathOfInvalidConfig2 =
+        codeOwnerConfigOperations.codeOwnerConfig(keyOfInvalidConfig2).getFilePath();
 
     // Also create a code owner config files without issues.
     codeOwnerConfigOperations
@@ -212,25 +216,25 @@
         .containsExactly(
             "refs/heads/master",
                 ImmutableMap.of(
-                    getCodeOwnerConfigFilePath(keyOfInvalidConfig1),
-                        ImmutableList.of(
-                            error(
-                                String.format(
-                                    "invalid global import in '%s': '/not-a-code-owner-config' is"
-                                        + " not a code owner config file",
-                                    getCodeOwnerConfigFilePath(keyOfInvalidConfig1)))),
-                    getCodeOwnerConfigFilePath(keyOfInvalidConfig2),
-                        ImmutableList.of(
-                            error(
-                                String.format(
-                                    "code owner email 'unknown1@example.com' in '%s' cannot be"
-                                        + " resolved for admin",
-                                    getCodeOwnerConfigFilePath(keyOfInvalidConfig2))),
-                            error(
-                                String.format(
-                                    "code owner email 'unknown2@example.com' in '%s' cannot be"
-                                        + " resolved for admin",
-                                    getCodeOwnerConfigFilePath(keyOfInvalidConfig2))))),
+                    pathOfInvalidConfig1,
+                    ImmutableList.of(
+                        error(
+                            String.format(
+                                "invalid global import in '%s': '/not-a-code-owner-config' is"
+                                    + " not a code owner config file",
+                                pathOfInvalidConfig1))),
+                    pathOfInvalidConfig2,
+                    ImmutableList.of(
+                        error(
+                            String.format(
+                                "code owner email 'unknown1@example.com' in '%s' cannot be"
+                                    + " resolved for admin",
+                                pathOfInvalidConfig2)),
+                        error(
+                            String.format(
+                                "code owner email 'unknown2@example.com' in '%s' cannot be"
+                                    + " resolved for admin",
+                                pathOfInvalidConfig2)))),
             "refs/meta/config", ImmutableMap.of());
   }
 
@@ -350,6 +354,8 @@
                 CodeOwnerConfigReference.create(
                     CodeOwnerConfigImportMode.ALL, "/not-a-code-owner-config"))
             .create();
+    String pathOfInvalidConfig1 =
+        codeOwnerConfigOperations.codeOwnerConfig(keyOfInvalidConfig1).getFilePath();
 
     CodeOwnerConfig.Key keyOfInvalidConfig2 =
         codeOwnerConfigOperations
@@ -360,47 +366,49 @@
             .addCodeOwnerEmail("unknown1@example.com")
             .addCodeOwnerEmail("unknown2@example.com")
             .create();
+    String pathOfInvalidConfig2 =
+        codeOwnerConfigOperations.codeOwnerConfig(keyOfInvalidConfig2).getFilePath();
 
     assertThat(
             projectCodeOwnersApiFactory
                 .project(project)
                 .checkCodeOwnerConfigFiles()
                 .setBranches(ImmutableList.of("master"))
-                .setPath(getCodeOwnerConfigFilePath(keyOfInvalidConfig1))
+                .setPath(pathOfInvalidConfig1)
                 .check())
         .containsExactly(
             "refs/heads/master",
             ImmutableMap.of(
-                getCodeOwnerConfigFilePath(keyOfInvalidConfig1),
+                pathOfInvalidConfig1,
                 ImmutableList.of(
                     error(
                         String.format(
                             "invalid global import in '%s': '/not-a-code-owner-config' is"
                                 + " not a code owner config file",
-                            getCodeOwnerConfigFilePath(keyOfInvalidConfig1))))));
+                            pathOfInvalidConfig1)))));
 
     assertThat(
             projectCodeOwnersApiFactory
                 .project(project)
                 .checkCodeOwnerConfigFiles()
                 .setBranches(ImmutableList.of("master"))
-                .setPath(getCodeOwnerConfigFilePath(keyOfInvalidConfig2))
+                .setPath(pathOfInvalidConfig2)
                 .check())
         .containsExactly(
             "refs/heads/master",
             ImmutableMap.of(
-                getCodeOwnerConfigFilePath(keyOfInvalidConfig2),
+                pathOfInvalidConfig2,
                 ImmutableList.of(
                     error(
                         String.format(
                             "code owner email 'unknown1@example.com' in '%s' cannot be"
                                 + " resolved for admin",
-                            getCodeOwnerConfigFilePath(keyOfInvalidConfig2))),
+                            pathOfInvalidConfig2)),
                     error(
                         String.format(
                             "code owner email 'unknown2@example.com' in '%s' cannot be"
                                 + " resolved for admin",
-                            getCodeOwnerConfigFilePath(keyOfInvalidConfig2))))));
+                            pathOfInvalidConfig2)))));
   }
 
   @Test
@@ -427,6 +435,8 @@
             .folderPath("/foo/")
             .addCodeOwnerEmail("unknown1@example.com")
             .create();
+    String pathOfInvalidConfig2 =
+        codeOwnerConfigOperations.codeOwnerConfig(keyOfInvalidConfig2).getFilePath();
 
     CodeOwnerConfig.Key keyOfInvalidConfig3 =
         codeOwnerConfigOperations
@@ -436,6 +446,8 @@
             .folderPath("/foo/bar/")
             .addCodeOwnerEmail("unknown2@example.com")
             .create();
+    String pathOfInvalidConfig3 =
+        codeOwnerConfigOperations.codeOwnerConfig(keyOfInvalidConfig3).getFilePath();
 
     assertThat(
             projectCodeOwnersApiFactory
@@ -447,20 +459,20 @@
         .containsExactly(
             "refs/heads/master",
             ImmutableMap.of(
-                getCodeOwnerConfigFilePath(keyOfInvalidConfig2),
+                pathOfInvalidConfig2,
                 ImmutableList.of(
                     error(
                         String.format(
                             "code owner email 'unknown1@example.com' in '%s' cannot be"
                                 + " resolved for admin",
-                            getCodeOwnerConfigFilePath(keyOfInvalidConfig2)))),
-                getCodeOwnerConfigFilePath(keyOfInvalidConfig3),
+                            pathOfInvalidConfig2))),
+                codeOwnerConfigOperations.codeOwnerConfig(keyOfInvalidConfig3).getFilePath(),
                 ImmutableList.of(
                     error(
                         String.format(
                             "code owner email 'unknown2@example.com' in '%s' cannot be"
                                 + " resolved for admin",
-                            getCodeOwnerConfigFilePath(keyOfInvalidConfig3))))));
+                            pathOfInvalidConfig3)))));
   }
 
   private ConsistencyProblemInfo error(String message) {
@@ -472,10 +484,6 @@
     return projectCodeOwnersApiFactory.project(projectName).checkCodeOwnerConfigFiles().check();
   }
 
-  private String getCodeOwnerConfigFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
-    return backendConfig.getDefaultBackend().getFilePath(codeOwnerConfigKey).toString();
-  }
-
   private String getCodeOwnerConfigFileName() {
     CodeOwnerBackend backend = backendConfig.getDefaultBackend();
     if (backend instanceof FindOwnersBackend) {
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerConfigFilesInRevisionIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerConfigFilesInRevisionIT.java
index bc25394..9f4d64d 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerConfigFilesInRevisionIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerConfigFilesInRevisionIT.java
@@ -85,7 +85,8 @@
 
   private void testCodeOwnerConfigFileWithoutIssues() throws Exception {
     CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
-    String codeOwnerConfigPath = getCodeOwnerConfigFilePath(codeOwnerConfigKey);
+    String codeOwnerConfigPath =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath();
     String changeId =
         createChange(
                 "Add code owners",
@@ -112,7 +113,8 @@
 
   private void testNonParseableCodeOwnerConfigFile() throws Exception {
     CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
-    String codeOwnerConfigPath = getCodeOwnerConfigFilePath(codeOwnerConfigKey);
+    String codeOwnerConfigPath =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath();
 
     disableCodeOwnersForProject(project);
     String changeId =
@@ -149,7 +151,8 @@
 
   private void testCodeOwnerConfigFileWithIssues() throws Exception {
     CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
-    String codeOwnerConfigPath = getCodeOwnerConfigFilePath(codeOwnerConfigKey);
+    String codeOwnerConfigPath =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath();
     String unknownEmail1 = "non-existing-email@example.com";
     String unknownEmail2 = "another-unknown-email@example.com";
 
@@ -190,7 +193,8 @@
     TestAccount user2 = accountCreator.user2();
 
     CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
-    String codeOwnerConfigPath = getCodeOwnerConfigFilePath(codeOwnerConfigKey);
+    String codeOwnerConfigPath =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath();
 
     // Upload the change as user2 who cannot see 'admin' and 'user'.
     disableCodeOwnersForProject(project);
@@ -229,7 +233,8 @@
   public void nonModifiedCodeOwnerConfigFilesAreNotValidated() throws Exception {
     // Create a code owner config file with issues in the repository.
     CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
-    String codeOwnerConfigPath = getCodeOwnerConfigFilePath(codeOwnerConfigKey);
+    String codeOwnerConfigPath =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath();
     String unknownEmail1 = "non-existing-email@example.com";
     String unknownEmail2 = "another-unknown-email@example.com";
     disableCodeOwnersForProject(project);
@@ -250,7 +255,8 @@
 
     // Create a change that adds another code owner config file without issues.
     CodeOwnerConfig.Key codeOwnerConfigKey2 = createCodeOwnerConfigKey("/foo/");
-    String codeOwnerConfigPath2 = getCodeOwnerConfigFilePath(codeOwnerConfigKey2);
+    String codeOwnerConfigPath2 =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getFilePath();
     String changeId2 =
         createChange(
                 "Add code owners",
@@ -267,7 +273,8 @@
   @Test
   public void deletedCodeOwnerConfigFilesAreNotValidated() throws Exception {
     CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
-    String codeOwnerConfigPath = getCodeOwnerConfigFilePath(codeOwnerConfigKey);
+    String codeOwnerConfigPath =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath();
     disableCodeOwnersForProject(project);
     String changeId = createChangeWithFileDeletion(codeOwnerConfigPath);
     setCodeOwnersConfig(project, null, StatusConfig.KEY_DISABLED, "false");
@@ -278,8 +285,10 @@
   public void validateExactFile() throws Exception {
     CodeOwnerConfig.Key codeOwnerConfigKey1 = createCodeOwnerConfigKey("/");
     CodeOwnerConfig.Key codeOwnerConfigKey2 = createCodeOwnerConfigKey("/foo/");
-    String codeOwnerConfigPath1 = getCodeOwnerConfigFilePath(codeOwnerConfigKey1);
-    String codeOwnerConfigPath2 = getCodeOwnerConfigFilePath(codeOwnerConfigKey2);
+    String codeOwnerConfigPath1 =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath();
+    String codeOwnerConfigPath2 =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getFilePath();
     String unknownEmail1 = "non-existing-email@example.com";
     String unknownEmail2 = "another-unknown-email@example.com";
 
@@ -327,9 +336,12 @@
     CodeOwnerConfig.Key codeOwnerConfigKey1 = createCodeOwnerConfigKey("/");
     CodeOwnerConfig.Key codeOwnerConfigKey2 = createCodeOwnerConfigKey("/foo/");
     CodeOwnerConfig.Key codeOwnerConfigKey3 = createCodeOwnerConfigKey("/foo/bar/");
-    String codeOwnerConfigPath1 = getCodeOwnerConfigFilePath(codeOwnerConfigKey1);
-    String codeOwnerConfigPath2 = getCodeOwnerConfigFilePath(codeOwnerConfigKey2);
-    String codeOwnerConfigPath3 = getCodeOwnerConfigFilePath(codeOwnerConfigKey3);
+    String codeOwnerConfigPath1 =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath();
+    String codeOwnerConfigPath2 =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getFilePath();
+    String codeOwnerConfigPath3 =
+        codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey3).getFilePath();
     String unknownEmail1 = "non-existing-email@example.com";
     String unknownEmail2 = "another-unknown-email@example.com";
     String unknownEmail3 = "yet-another-unknown-email@example.com";
@@ -403,10 +415,6 @@
     return CodeOwnerConfig.Key.create(project, "master", folderPath);
   }
 
-  private String getCodeOwnerConfigFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
-    return backendConfig.getDefaultBackend().getFilePath(codeOwnerConfigKey).toString();
-  }
-
   private String format(CodeOwnerConfig codeOwnerConfig) throws Exception {
     if (backendConfig.getDefaultBackend() instanceof FindOwnersBackend) {
       return findOwnersCodeOwnerConfigParser.formatAsString(codeOwnerConfig);
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
index 320e720..ec0bf49 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
@@ -37,7 +37,6 @@
 import com.google.gerrit.extensions.common.MergeInput;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.git.ObjectIds;
-import com.google.gerrit.plugins.codeowners.JgitPath;
 import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersIT;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackend;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig;
@@ -91,7 +90,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(admin.email()))
@@ -107,7 +106,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(admin.email()))
@@ -140,13 +139,13 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.create(
             CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-            getCodeOwnerConfigFilePath(keyOfImportedCodeOwnerConfig));
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportedCodeOwnerConfig).getFilePath());
 
     // Create a code owner config with import and without issues.
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addImport(codeOwnerConfigReference)
@@ -181,7 +180,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(keyOfImportedCodeOwnerConfig))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(keyOfImportedCodeOwnerConfig)
+                    .getFilePath())
             .setProject(otherProject)
             .build();
 
@@ -189,7 +190,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addImport(codeOwnerConfigReference)
@@ -225,7 +226,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(keyOfImportedCodeOwnerConfig))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(keyOfImportedCodeOwnerConfig)
+                    .getFilePath())
             .setProject(otherProject)
             .setBranch(otherBranch)
             .build();
@@ -234,7 +237,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addImport(codeOwnerConfigReference)
@@ -266,7 +269,9 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(createCodeOwnerConfigKey("/"))).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(createCodeOwnerConfigKey("/"))
+                .getJGitFilePath(),
             "INVALID");
     assertOkWithHints(
         r,
@@ -280,7 +285,9 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(createCodeOwnerConfigKey("/"))).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(createCodeOwnerConfigKey("/"))
+                .getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(createCodeOwnerConfigKey("/"), TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(admin.email()))
@@ -300,7 +307,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(unknownEmail))
@@ -327,7 +334,7 @@
                     + "  ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
                 r.getChange().getId().get(),
                 unknownEmail,
-                getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+                codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
                 identifiedUserFactory.create(admin.id()).getLoggableName()));
   }
 
@@ -337,7 +344,8 @@
     // delete afterwards.
     disableCodeOwnersForProject(project);
 
-    String path = JgitPath.of(getCodeOwnerConfigFilePath(createCodeOwnerConfigKey("/"))).get();
+    String path =
+        codeOwnerConfigOperations.codeOwnerConfig(createCodeOwnerConfigKey("/")).getJGitFilePath();
     PushOneCommit.Result r = createChange("Add code owners", path, "INVALID");
     r.assertOkStatus();
 
@@ -363,7 +371,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             "INVALID");
     r.assertOkStatus();
 
@@ -374,14 +382,14 @@
     r =
         createChange(
             "Update code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             "STILL INVALID");
     assertOkWithWarnings(
         r,
         "invalid code owner config files",
         String.format(
             "invalid code owner config file '%s':\n  %s",
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
             getParsingErrorMessage(
                 ImmutableMap.of(
                     FindOwnersBackend.class,
@@ -402,7 +410,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             "INVALID");
     r.assertOkStatus();
 
@@ -415,7 +423,7 @@
     r =
         createChange(
             "Update code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(
@@ -428,12 +436,12 @@
         String.format(
             "code owner email '%s' in '%s' cannot be resolved for %s",
             unknownEmail1,
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
             identifiedUserFactory.create(admin.id()).getLoggableName()),
         String.format(
             "code owner email '%s' in '%s' cannot be resolved for %s",
             unknownEmail2,
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
             identifiedUserFactory.create(admin.id()).getLoggableName()));
   }
 
@@ -450,7 +458,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(unknownEmail))
@@ -465,7 +473,7 @@
     r =
         createChange(
             "Update code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(
@@ -477,7 +485,7 @@
         String.format(
             "code owner email '%s' in '%s' cannot be resolved for %s",
             unknownEmail,
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
             identifiedUserFactory.create(admin.id()).getLoggableName()));
   }
 
@@ -488,14 +496,14 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             "INVALID");
     assertErrorWithMessages(
         r,
         "invalid code owner config files",
         String.format(
             "invalid code owner config file '%s':\n  %s",
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
             getParsingErrorMessage(
                 ImmutableMap.of(
                     FindOwnersBackend.class,
@@ -515,9 +523,9 @@
             testRepo,
             "Add code owners",
             ImmutableMap.of(
-                JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey1)).get(),
+                codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getJGitFilePath(),
                 "INVALID",
-                JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey2)).get(),
+                codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getJGitFilePath(),
                 "ALSO-INVALID"));
     PushOneCommit.Result r = push.to("refs/for/master");
     assertErrorWithMessages(
@@ -525,7 +533,7 @@
         "invalid code owner config files",
         String.format(
             "invalid code owner config file '%s':\n  %s",
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey1),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath(),
             getParsingErrorMessage(
                 ImmutableMap.of(
                     FindOwnersBackend.class,
@@ -534,7 +542,7 @@
                     "1:8: expected \"{\""))),
         String.format(
             "invalid code owner config file '%s':\n  %s",
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey2),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getFilePath(),
             getParsingErrorMessage(
                 ImmutableMap.of(
                     FindOwnersBackend.class,
@@ -552,7 +560,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(
@@ -565,12 +573,12 @@
         String.format(
             "code owner email '%s' in '%s' cannot be resolved for %s",
             unknownEmail1,
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
             identifiedUserFactory.create(admin.id()).getLoggableName()),
         String.format(
             "code owner email '%s' in '%s' cannot be resolved for %s",
             unknownEmail2,
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
             identifiedUserFactory.create(admin.id()).getLoggableName()));
   }
 
@@ -584,7 +592,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(
@@ -596,7 +604,8 @@
         "invalid code owner config files",
         String.format(
             "the domain of the code owner email '%s' in '%s' is not allowed for" + " code owners",
-            emailWithNonAllowedDomain, getCodeOwnerConfigFilePath(codeOwnerConfigKey)));
+            emailWithNonAllowedDomain,
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath()));
   }
 
   @Test
@@ -612,7 +621,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(unknownEmail1))
@@ -628,7 +637,7 @@
     r =
         createChange(
             "Update code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(
@@ -645,7 +654,7 @@
             String.format(
                 "code owner email '%s' in '%s' cannot be resolved for %s",
                 unknownEmail2,
-                getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+                codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
                 identifiedUserFactory.create(admin.id()).getLoggableName())));
 
     // the pre-existing issue is returned as warning
@@ -654,7 +663,7 @@
             "warning: commit %s: code owner email '%s' in '%s' cannot be resolved for %s",
             abbreviatedCommit,
             unknownEmail1,
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
             identifiedUserFactory.create(admin.id()).getLoggableName()));
 
     r.assertNotMessage("hint");
@@ -673,7 +682,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(unknownEmail))
@@ -700,7 +709,7 @@
                     + "  ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
                 r.getChange().getId().get(),
                 unknownEmail,
-                getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+                codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
                 identifiedUserFactory.create(admin.id()).getLoggableName()));
   }
 
@@ -724,7 +733,7 @@
         createChange(
             user2,
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(admin.email()))
@@ -752,7 +761,7 @@
                     + "  ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
                 r.getChange().getId().get(),
                 admin.email(),
-                getCodeOwnerConfigFilePath(codeOwnerConfigKey),
+                codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
                 identifiedUserFactory.create(user2.id()).getLoggableName()));
   }
 
@@ -771,7 +780,7 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(codeOwnerConfigKey)).get(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
             format(
                 CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
                     .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(user.email()))
@@ -816,8 +825,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(
-                    CodeOwnerConfig.Key.create(nonExistingProject, "master", "/")))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(CodeOwnerConfig.Key.create(nonExistingProject, "master", "/"))
+                    .getFilePath())
             .setProject(nonExistingProject)
             .build();
     CodeOwnerConfig codeOwnerConfig =
@@ -827,7 +837,9 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getJGitFilePath(),
             format(codeOwnerConfig));
     assertErrorWithMessages(
         r,
@@ -835,7 +847,7 @@
         String.format(
             "invalid %s import in '%s': project '%s' not found",
             importType.getType(),
-            getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig),
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportingCodeOwnerConfig).getFilePath(),
             nonExistingProject.get()));
   }
 
@@ -875,8 +887,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(
-                    CodeOwnerConfig.Key.create(nonVisibleProject, "master", "/")))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(CodeOwnerConfig.Key.create(nonVisibleProject, "master", "/"))
+                    .getFilePath())
             .setProject(nonVisibleProject)
             .build();
     CodeOwnerConfig codeOwnerConfig =
@@ -887,7 +900,9 @@
         createChange(
             user,
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getJGitFilePath(),
             format(codeOwnerConfig));
     assertErrorWithMessages(
         r,
@@ -895,7 +910,7 @@
         String.format(
             "invalid %s import in '%s': project '%s' not found",
             importType.getType(),
-            getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig),
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportingCodeOwnerConfig).getFilePath(),
             nonVisibleProject.get()));
   }
 
@@ -933,8 +948,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(
-                    CodeOwnerConfig.Key.create(hiddenProject, "master", "/")))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(CodeOwnerConfig.Key.create(hiddenProject, "master", "/"))
+                    .getFilePath())
             .setProject(hiddenProject)
             .build();
     CodeOwnerConfig codeOwnerConfig =
@@ -944,7 +960,9 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getJGitFilePath(),
             format(codeOwnerConfig));
     assertErrorWithMessages(
         r,
@@ -952,7 +970,7 @@
         String.format(
             "invalid %s import in '%s': project '%s' has state 'hidden' that doesn't permit read",
             importType.getType(),
-            getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig),
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportingCodeOwnerConfig).getFilePath(),
             hiddenProject.get()));
   }
 
@@ -977,8 +995,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(
-                    CodeOwnerConfig.Key.create(otherProject, "non-existing", "/")))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(CodeOwnerConfig.Key.create(otherProject, "non-existing", "/"))
+                    .getFilePath())
             .setProject(otherProject)
             .setBranch("non-existing")
             .build();
@@ -989,7 +1008,9 @@
     PushOneCommit.Result r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getJGitFilePath(),
             format(codeOwnerConfig));
     assertErrorWithMessages(
         r,
@@ -997,7 +1018,7 @@
         String.format(
             "invalid %s import in '%s': branch 'non-existing' not found in project '%s'",
             importType.getType(),
-            getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig),
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportingCodeOwnerConfig).getFilePath(),
             otherProject.get()));
   }
 
@@ -1038,7 +1059,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(CodeOwnerConfig.Key.create(otherProject, "master", "/")))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(CodeOwnerConfig.Key.create(otherProject, "master", "/"))
+                    .getFilePath())
             .setProject(otherProject)
             .setBranch("master")
             .build();
@@ -1050,7 +1073,9 @@
         createChange(
             user,
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getJGitFilePath(),
             format(codeOwnerConfig));
     assertErrorWithMessages(
         r,
@@ -1058,7 +1083,7 @@
         String.format(
             "invalid %s import in '%s': branch 'master' not found in project '%s'",
             importType.getType(),
-            getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig),
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportingCodeOwnerConfig).getFilePath(),
             otherProject.get()));
   }
 
@@ -1091,7 +1116,9 @@
         createChange(
             user,
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getJGitFilePath(),
             format(codeOwnerConfig));
     assertErrorWithMessages(
         r,
@@ -1099,7 +1126,10 @@
         String.format(
             "invalid %s import in '%s':"
                 + " 'non-code-owner-config.txt' is not a code owner config file",
-            importType.getType(), getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)));
+            importType.getType(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getFilePath()));
   }
 
   @Test
@@ -1124,7 +1154,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(keyOfNonExistingCodeOwnerConfig))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(keyOfNonExistingCodeOwnerConfig)
+                    .getFilePath())
             .build();
     CodeOwnerConfig codeOwnerConfig =
         createCodeOwnerConfigWithImport(
@@ -1134,7 +1166,9 @@
         createChange(
             user,
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getJGitFilePath(),
             format(codeOwnerConfig));
     assertErrorWithMessages(
         r,
@@ -1142,8 +1176,10 @@
         String.format(
             "invalid %s import in '%s': '%s' does not exist (project = %s, branch = master)",
             importType.getType(),
-            getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig),
-            getCodeOwnerConfigFilePath(keyOfNonExistingCodeOwnerConfig),
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportingCodeOwnerConfig).getFilePath(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfNonExistingCodeOwnerConfig)
+                .getFilePath(),
             project.get()));
   }
 
@@ -1173,7 +1209,9 @@
     PushOneCommit.Result r =
         createChange(
             "Add invalid code owner config",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportedCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportedCodeOwnerConfig)
+                .getJGitFilePath(),
             "INVALID");
     r.assertOkStatus();
     approve(r.getChangeId());
@@ -1187,7 +1225,9 @@
     CodeOwnerConfigReference codeOwnerConfigReference =
         CodeOwnerConfigReference.builder(
                 CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
-                getCodeOwnerConfigFilePath(keyOfImportedCodeOwnerConfig))
+                codeOwnerConfigOperations
+                    .codeOwnerConfig(keyOfImportedCodeOwnerConfig)
+                    .getFilePath())
             .build();
     CodeOwnerConfig codeOwnerConfig =
         createCodeOwnerConfigWithImport(
@@ -1196,7 +1236,9 @@
     r =
         createChange(
             "Add code owners",
-            JgitPath.of(getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig)).get(),
+            codeOwnerConfigOperations
+                .codeOwnerConfig(keyOfImportingCodeOwnerConfig)
+                .getJGitFilePath(),
             format(codeOwnerConfig));
     assertErrorWithMessages(
         r,
@@ -1204,8 +1246,8 @@
         String.format(
             "invalid %s import in '%s': '%s' is not parseable (project = %s, branch = master)",
             importType.getType(),
-            getCodeOwnerConfigFilePath(keyOfImportingCodeOwnerConfig),
-            getCodeOwnerConfigFilePath(keyOfImportedCodeOwnerConfig),
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportingCodeOwnerConfig).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(keyOfImportedCodeOwnerConfig).getFilePath(),
             project.get()));
   }
 
@@ -1280,10 +1322,6 @@
     return CodeOwnerConfig.Key.create(project, "master", folderPath);
   }
 
-  private String getCodeOwnerConfigFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
-    return backendConfig.getDefaultBackend().getFilePath(codeOwnerConfigKey).toString();
-  }
-
   private String format(CodeOwnerConfig codeOwnerConfig) throws Exception {
     if (backendConfig.getDefaultBackend() instanceof FindOwnersBackend) {
       return findOwnersCodeOwnerConfigParser.formatAsString(codeOwnerConfig);
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/GetCodeOwnerConfigFilesIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/GetCodeOwnerConfigFilesIT.java
index 88b8421..0489c38 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/GetCodeOwnerConfigFilesIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/GetCodeOwnerConfigFilesIT.java
@@ -88,9 +88,9 @@
                 .codeOwnerConfigFiles()
                 .paths())
         .containsExactly(
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey1),
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey2),
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey3))
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey3).getFilePath())
         .inOrder();
   }
 
@@ -123,8 +123,8 @@
                 .codeOwnerConfigFiles()
                 .paths())
         .containsExactly(
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey2),
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey1))
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath())
         .inOrder();
   }
 
@@ -157,8 +157,8 @@
                 .codeOwnerConfigFiles()
                 .paths())
         .containsExactly(
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey1),
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey2))
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getFilePath())
         .inOrder();
   }
 
@@ -202,7 +202,8 @@
                 .branch("master")
                 .codeOwnerConfigFiles()
                 .paths())
-        .containsExactly(getCodeOwnerConfigFilePath(codeOwnerConfigKey));
+        .containsExactly(
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath());
   }
 
   @Test
@@ -269,9 +270,9 @@
                 .withEmail(admin.email())
                 .paths())
         .containsExactly(
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey2),
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey4),
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey5))
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey4).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey5).getFilePath())
         .inOrder();
 
     assertThat(
@@ -282,9 +283,9 @@
                 .withEmail(user.email())
                 .paths())
         .containsExactly(
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey1),
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey3),
-            getCodeOwnerConfigFilePath(codeOwnerConfigKey4))
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey3).getFilePath(),
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey4).getFilePath())
         .inOrder();
 
     assertThat(
@@ -294,7 +295,8 @@
                 .codeOwnerConfigFiles()
                 .withEmail(user2.email())
                 .paths())
-        .containsExactly(getCodeOwnerConfigFilePath(codeOwnerConfigKey5));
+        .containsExactly(
+            codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey5).getFilePath());
 
     assertThat(
             projectCodeOwnersApiFactory
@@ -306,10 +308,6 @@
         .isEmpty();
   }
 
-  private String getCodeOwnerConfigFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
-    return backendConfig.getDefaultBackend().getFilePath(codeOwnerConfigKey).toString();
-  }
-
   private String getCodeOwnerConfigFileName() {
     CodeOwnerBackend backend = backendConfig.getDefaultBackend();
     if (backend instanceof FindOwnersBackend) {
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/restapi/BUILD b/javatests/com/google/gerrit/plugins/codeowners/acceptance/restapi/BUILD
index a95810e..42c221e 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/restapi/BUILD
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/restapi/BUILD
@@ -16,6 +16,7 @@
         "//javatests/com/google/gerrit/acceptance/rest/util",
         "//plugins/code-owners:code-owners__plugin",
         "//plugins/code-owners/java/com/google/gerrit/plugins/codeowners/acceptance",
+        "//plugins/code-owners/java/com/google/gerrit/plugins/codeowners/acceptance/testsuite",
         "//plugins/code-owners/java/com/google/gerrit/plugins/codeowners/testing",
     ],
 )
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/restapi/GetCodeOwnerStatusRestIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/restapi/GetCodeOwnerStatusRestIT.java
index 364c743..8788ddb 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/restapi/GetCodeOwnerStatusRestIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/restapi/GetCodeOwnerStatusRestIT.java
@@ -22,8 +22,8 @@
 import com.google.gerrit.plugins.codeowners.JgitPath;
 import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersIT;
 import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest;
+import com.google.gerrit.plugins.codeowners.acceptance.testsuite.CodeOwnerConfigOperations;
 import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig;
-import com.google.gerrit.plugins.codeowners.config.BackendConfig;
 import com.google.gerrit.plugins.codeowners.config.StatusConfig;
 import org.junit.Before;
 import org.junit.Test;
@@ -41,11 +41,12 @@
  * extend {@link AbstractCodeOwnersIT}.
  */
 public class GetCodeOwnerStatusRestIT extends AbstractCodeOwnersTest {
-  private BackendConfig backendConfig;
+  private CodeOwnerConfigOperations codeOwnerConfigOperations;
 
   @Before
   public void setUpCodeOwnersPlugin() throws Exception {
-    backendConfig = plugin.getSysInjector().getInstance(BackendConfig.class);
+    codeOwnerConfigOperations =
+        plugin.getSysInjector().getInstance(CodeOwnerConfigOperations.class);
   }
 
   @Test
@@ -66,7 +67,8 @@
 
   @Test
   public void cannotGetStatusIfCodeOwnerConfigIsInvalid() throws Exception {
-    String filePath = getCodeOwnerConfigFilePath(createCodeOwnerConfigKey("/"));
+    String filePath =
+        codeOwnerConfigOperations.codeOwnerConfig(createCodeOwnerConfigKey("/")).getFilePath();
     disableCodeOwnersForProject(project);
     String changeId =
         createChange("Add code owners", JgitPath.of(filePath).get(), "INVALID").getChangeId();
@@ -89,8 +91,4 @@
   private CodeOwnerConfig.Key createCodeOwnerConfigKey(String folderPath) {
     return CodeOwnerConfig.Key.create(project, "master", folderPath);
   }
-
-  private String getCodeOwnerConfigFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
-    return backendConfig.getDefaultBackend().getFilePath(codeOwnerConfigKey).toString();
-  }
 }
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperationsImplTest.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperationsImplTest.java
index d872186..542fc3d 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperationsImplTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/testsuite/CodeOwnerConfigOperationsImplTest.java
@@ -23,6 +23,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.truth.Truth8;
 import com.google.gerrit.entities.BranchNameKey;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.entities.RefNames;
 import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest;
 import com.google.gerrit.plugins.codeowners.acceptance.testsuite.CodeOwnerConfigOperations.PerCodeOwnerConfigOperations;
@@ -580,6 +581,64 @@
         .isEqualTo(String.format("code owner config %s does not exist", codeOwnerConfigKey));
   }
 
+  @Test
+  public void getJGitFilePath() throws Exception {
+    CodeOwnerConfig.Key codeOwnerConfigKey =
+        codeOwnerConfigOperations
+            .newCodeOwnerConfig()
+            .project(project)
+            .branch("master")
+            .folderPath("/foo/")
+            .addCodeOwnerEmail(admin.email())
+            .create();
+    assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath())
+        .isEqualTo("foo/OWNERS");
+  }
+
+  @Test
+  public void getFilePath() throws Exception {
+    CodeOwnerConfig.Key codeOwnerConfigKey =
+        codeOwnerConfigOperations
+            .newCodeOwnerConfig()
+            .project(project)
+            .branch("master")
+            .folderPath("/foo/")
+            .addCodeOwnerEmail(admin.email())
+            .create();
+    assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath())
+        .isEqualTo("/foo/OWNERS");
+  }
+
+  @Test
+  public void getJGitFilePath_nonExistingCodeOwnerConfig() throws Exception {
+    CodeOwnerConfig.Key codeOwnerConfigKey = CodeOwnerConfig.Key.create(project, "master", "/foo/");
+    assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath())
+        .isEqualTo("foo/OWNERS");
+  }
+
+  @Test
+  public void getFilePath_nonExistingCodeOwnerConfig() throws Exception {
+    CodeOwnerConfig.Key codeOwnerConfigKey = CodeOwnerConfig.Key.create(project, "master", "/foo/");
+    assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath())
+        .isEqualTo("/foo/OWNERS");
+  }
+
+  @Test
+  public void getJGitFilePath_nonExistingProject() throws Exception {
+    CodeOwnerConfig.Key codeOwnerConfigKey =
+        CodeOwnerConfig.Key.create(Project.nameKey("non-existing"), "master", "/foo/");
+    assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath())
+        .isEqualTo("foo/OWNERS");
+  }
+
+  @Test
+  public void getFilePath_nonExistingProject() throws Exception {
+    CodeOwnerConfig.Key codeOwnerConfigKey =
+        CodeOwnerConfig.Key.create(Project.nameKey("non-existing"), "master", "/foo/");
+    assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath())
+        .isEqualTo("/foo/OWNERS");
+  }
+
   private CodeOwnerConfig getCodeOwnerConfigFromServer(CodeOwnerConfig.Key codeOwnerConfigKey) {
     return codeOwners
         .getFromCurrentRevision(codeOwnerConfigKey)