Unify code used in updateSources() and canCheckout() methods
authorDmitry Neverov <dmitry.neverov@gmail.com>
Mon, 24 Apr 2017 15:54:22 +0000 (17:54 +0200)
committerDmitry Neverov <dmitry.neverov@gmail.com>
Mon, 24 Apr 2017 15:54:22 +0000 (17:54 +0200)
Drop old checkout rules validation, it is obsolete since some exclude
rules are supported with help of sparse checkout.

git-agent/src/jetbrains/buildServer/buildTriggers/vcs/git/agent/GitAgentVcsSupport.java
git-tests/src/jetbrains/buildServer/buildTriggers/vcs/git/tests/AutoCheckoutTest.java

index adef8025d17c2e53f5f6f6a8a19f216fb909b0eb..3736da3ac77d8ee901fac17c0d7fa0c74a8344da 100644 (file)
@@ -83,7 +83,7 @@ public class GitAgentVcsSupport extends AgentVcsSupport implements UpdateByCheck
     AgentPluginConfig config = myConfigFactory.createConfig(build, root);
     Map<String, String> env = getGitCommandEnv(config, build);
     GitFactory gitFactory = myGitMetaFactory.createFactory(mySshService, config, getLogger(build, config), build.getBuildTempDirectory(), env, new BuildContext(build));
-    Pair<CheckoutMode, File> targetDirAndMode = getTargetDirAndMode(config, root, rules, checkoutDirectory);
+    Pair<CheckoutMode, File> targetDirAndMode = getTargetDirAndMode(config, rules, checkoutDirectory);
     CheckoutMode mode = targetDirAndMode.first;
     File targetDir = targetDirAndMode.second;
     Updater updater;
@@ -118,12 +118,14 @@ public class GitAgentVcsSupport extends AgentVcsSupport implements UpdateByCheck
       return AgentCheckoutAbility.noVcsClientOnAgent(e.getMessage());
     }
 
-    try {
-      boolean validSparseCheckout = canUseSparseCheckout(config) && getSingleTargetDirForSparseCheckout(checkoutRules) != null;
-      if (!validSparseCheckout)
-        validateCheckoutRules(vcsRoot, checkoutRules);
-    } catch (VcsException e) {
-      return AgentCheckoutAbility.notSupportedCheckoutRules(e.getMessage());
+    Pair<CheckoutMode, String> pathAndMode = getTargetPathAndMode(checkoutRules);
+    String targetDir = pathAndMode.second;
+    if (targetDir == null) {
+      return AgentCheckoutAbility.notSupportedCheckoutRules("Unsupported rules for agent-side checkout: " + checkoutRules.getAsString());
+    }
+
+    if (pathAndMode.first == CheckoutMode.SPARSE_CHECKOUT && !canUseSparseCheckout(config)) {
+      return AgentCheckoutAbility.notSupportedCheckoutRules("Cannot perform sparse checkout using git " + config.getGitExec().getVersion());
     }
 
     try {
@@ -135,12 +137,12 @@ public class GitAgentVcsSupport extends AgentVcsSupport implements UpdateByCheck
 
     List<VcsRootEntry> gitEntries = getGitRootEntries(build);
     if (gitEntries.size() > 1) {
-      String targetDir = getTargetDir(config, checkoutRules);
       for (VcsRootEntry entry : gitEntries) {
         VcsRoot otherRoot = entry.getVcsRoot();
         if (vcsRoot.equals(otherRoot))
           continue;
-        if (targetDir != null && targetDir.equals(getTargetDir(config, entry.getCheckoutRules())))
+        String entryPath = getTargetPathAndMode(entry.getCheckoutRules()).second;
+        if (targetDir.equals(entryPath))
           return AgentCheckoutAbility.canNotCheckout("Cannot checkout VCS root '" + vcsRoot.getName() + "' into the same directory as VCS root '" + otherRoot.getName() + "'");
       }
     }
@@ -149,16 +151,6 @@ public class GitAgentVcsSupport extends AgentVcsSupport implements UpdateByCheck
   }
 
 
-  @Nullable
-  private String getTargetDir(@NotNull AgentPluginConfig config, @NotNull CheckoutRules rules) {
-    if (isRequireSparseCheckout(rules)) {
-      return canUseSparseCheckout(config) ? getSingleTargetDirForSparseCheckout(rules) : null;
-    } else {
-      return rules.map("");
-    }
-  }
-
-
   private boolean isRequireSparseCheckout(@NotNull CheckoutRules rules) {
     if (!rules.getExcludeRules().isEmpty())
       return true;
@@ -187,70 +179,45 @@ public class GitAgentVcsSupport extends AgentVcsSupport implements UpdateByCheck
   }
 
 
-  /**
-   * Check if specified checkout rules are supported
-   * @param root root for which rules are checked
-   * @param rules rules to check
-   * @throws VcsException rules are not supported
-   */
-  private void validateCheckoutRules(@NotNull final VcsRoot root, @NotNull final CheckoutRules rules) throws VcsException {
-    if (rules.getExcludeRules().size() != 0) {
-      throw new VcsException("Exclude rules are not supported for agent checkout for the git (" + rules.getExcludeRules().size() +
-                             " rule(s) detected) for VCS Root '" + root.getName() + "'");
-    }
-    if (rules.getIncludeRules().size() > 1) {
-      throw new VcsException("At most one include rule is supported for agent checkout for the git (" + rules.getIncludeRules().size() +
-                             " rule(s) detected) for VCS Root '" + root.getName() + "'");
-    }
-    if (rules.getIncludeRules().size() == 1) {
-      IncludeRule ir = rules.getIncludeRules().get(0);
-      if (!".".equals(ir.getFrom()) && ir.getFrom().length() != 0) {
-        throw new VcsException("Agent checkout for the git supports only include rule of form '. => subdir', rule '" + ir.toDescriptiveString() +
-                               "' for VCS Root '" + root.getName() + "' is not supported");
-      }
+  @NotNull
+  private Pair<CheckoutMode, File> getTargetDirAndMode(@NotNull AgentPluginConfig config,
+                                                       @NotNull CheckoutRules rules,
+                                                       @NotNull File checkoutDir) throws VcsException {
+    Pair<CheckoutMode, String> pathAndMode = getTargetPathAndMode(rules);
+    String path = pathAndMode.second;
+    if (path == null) {
+      throw new VcsException("Unsupported checkout rules for agent-side checkout: " + rules.getAsString());
     }
-  }
 
+    boolean canUseSparseCheckout = canUseSparseCheckout(config);
+    if (pathAndMode.first == CheckoutMode.SPARSE_CHECKOUT && !canUseSparseCheckout) {
+      throw new VcsException("Cannot perform sparse checkout using git " + config.getGitExec().getVersion());
+    }
 
-  /**
-   * Get the destination directory creating it if it is missing
-   * @param root VCS root
-   * @param rules checkout rules
-   * @param checkoutDirectory checkout directory for the build
-   * @return the directory where vcs root should be checked out according to checkout rules
-   * @throws VcsException if the directory could not be located or created
-   */
-  private File getTargetDir(@NotNull final VcsRoot root, @NotNull final CheckoutRules rules, @NotNull final File checkoutDirectory) throws VcsException {
-    String path = rules.map("");
-    if (path == null)
-      throw new VcsException("The root path could not be mapped for VCS root '" + root.getName() + "'");
-
-    File directory = path.length() == 0 ? checkoutDirectory : new File(checkoutDirectory, path.replace('/', File.separatorChar));
-    if (!directory.exists()) {
+    File targetDir = path.length() == 0 ? checkoutDir : new File(checkoutDir, path.replace('/', File.separatorChar));
+    if (!targetDir.exists()) {
       //noinspection ResultOfMethodCallIgnored
-      directory.mkdirs();
-      if (!directory.exists())
-        throw new VcsException("The destination directory '" + directory + "' could not be created.");
+      targetDir.mkdirs();
+      if (!targetDir.exists())
+        throw new VcsException("Cannot create destination directory '" + targetDir + "'");
     }
-    return directory;
+
+    //Use sparse checkout mode if we can, without that switch from rules requiring sparse checkout
+    //to simple rules (e.g. to CheckoutRules.DEFAULT) doesn't work (run AgentSideSparseCheckoutTest.
+    //update_files_after_switching_to_default_rules). Probably it is a rare case when we checked out
+    //a repository using sparse checkout and then cannot use sparse checkout in the next build.
+    CheckoutMode mode = canUseSparseCheckout ? CheckoutMode.SPARSE_CHECKOUT : pathAndMode.first;
+    return Pair.create(mode, targetDir);
   }
 
 
   @NotNull
-  private Pair<CheckoutMode, File> getTargetDirAndMode(@NotNull AgentPluginConfig config,
-                                                       @NotNull VcsRoot root,
-                                                       @NotNull CheckoutRules rules,
-                                                       @NotNull File checkoutDir) throws VcsException {
-    if (canUseSparseCheckout(config)) {
-      String targetDir = getSingleTargetDirForSparseCheckout(rules);
-      if (targetDir != null) {
-        return Pair.create(CheckoutMode.SPARSE_CHECKOUT, new File(checkoutDir, targetDir));
-      }
+  private Pair<CheckoutMode, String> getTargetPathAndMode(@NotNull CheckoutRules rules) {
+    if (isRequireSparseCheckout(rules)) {
+      return Pair.create(CheckoutMode.SPARSE_CHECKOUT, getSingleTargetDirForSparseCheckout(rules));
+    } else {
+      return Pair.create(CheckoutMode.MAP_REPO_TO_DIR, rules.map(""));
     }
-
-    validateCheckoutRules(root, rules);
-    File targetDir = getTargetDir(root, rules, checkoutDir);
-    return Pair.create(CheckoutMode.MAP_REPO_TO_DIR, targetDir);
   }
 
   private boolean canUseSparseCheckout(@NotNull AgentPluginConfig config) {
index 30c7d9687d2ffaff71a4ecaff0b97a7ca9d7cebb..3aebb40bfc2d4ecdc537928074f19f78579dc151 100644 (file)
@@ -95,7 +95,7 @@ public class AutoCheckoutTest extends BaseRemoteRepositoryTest {
 
     AgentCheckoutAbility canCheckout = myVcsSupport.canCheckout(vcsRoot, new CheckoutRules("-:dir/q.txt"), build);
     then(canCheckout.getCanNotCheckoutReason().getType()).isEqualTo(AgentCanNotCheckoutReason.NOT_SUPPORTED_CHECKOUT_RULES);
-    then(canCheckout.getCanNotCheckoutReason().getDetails()).contains("Exclude rules are not supported for agent checkout");
+    then(canCheckout.getCanNotCheckoutReason().getDetails()).contains("Cannot perform sparse checkout using git " + GIT_WITH_SPARSE_CHECKOUT);
   }
 
   public void include_rule_with_mapping_is_used_without_sparse_checkout() throws IOException, VcsException {
@@ -107,11 +107,12 @@ public class AutoCheckoutTest extends BaseRemoteRepositoryTest {
 
     AgentCheckoutAbility canCheckout = myVcsSupport.canCheckout(vcsRoot, new CheckoutRules("+:a/b/c => d"), build);
     then(canCheckout.getCanNotCheckoutReason().getType()).isEqualTo(AgentCanNotCheckoutReason.NOT_SUPPORTED_CHECKOUT_RULES);
-    then(canCheckout.getCanNotCheckoutReason().getDetails()).contains("Agent checkout for the git supports only include rule of form '. => subdir'");
+    then(canCheckout.getCanNotCheckoutReason().getDetails()).contains("Unsupported rules for agent-side checkout: +:a/b/c => d");
   }
 
   public void git_version_does_not_support_sparse_checkout() throws IOException, VcsException {
-    myVcsSupport =  vcsSupportWithFakeGitOfVersion(GIT_WITH_SPARSE_CHECKOUT.previousVersion());
+    GitVersion gitVersion = GIT_WITH_SPARSE_CHECKOUT.previousVersion();
+    myVcsSupport =  vcsSupportWithFakeGitOfVersion(gitVersion);
 
     VcsRoot vcsRoot = vcsRootWithAgentGitPath("git");
     AgentRunningBuild build = runningBuild().sharedConfigParams(PluginConfigImpl.USE_SPARSE_CHECKOUT, "true")
@@ -119,7 +120,18 @@ public class AutoCheckoutTest extends BaseRemoteRepositoryTest {
 
     AgentCheckoutAbility canCheckout = myVcsSupport.canCheckout(vcsRoot, new CheckoutRules("-:dir/q.txt"), build);
     then(canCheckout.getCanNotCheckoutReason().getType()).isEqualTo(AgentCanNotCheckoutReason.NOT_SUPPORTED_CHECKOUT_RULES);
-    then(canCheckout.getCanNotCheckoutReason().getDetails()).contains("Exclude rules are not supported for agent checkout");
+    then(canCheckout.getCanNotCheckoutReason().getDetails()).contains("Cannot perform sparse checkout using git " + gitVersion);
+  }
+
+  public void git_version_does_not_support_sparse_checkout_default_rules() throws IOException, VcsException {
+    GitVersion gitVersion = GIT_WITH_SPARSE_CHECKOUT.previousVersion();
+    myVcsSupport =  vcsSupportWithFakeGitOfVersion(gitVersion);
+
+    VcsRoot vcsRoot = vcsRootWithAgentGitPath("git");
+    AgentRunningBuild build = runningBuild().sharedConfigParams(PluginConfigImpl.USE_SPARSE_CHECKOUT, "true").addRoot(vcsRoot).build();
+
+    AgentCheckoutAbility canCheckout = myVcsSupport.canCheckout(vcsRoot, CheckoutRules.DEFAULT, build);
+    then(canCheckout.getCanNotCheckoutReason()).isNull();
   }
 
   public void should_check_auth_method() throws Exception {