public Map convertToVcsRootProperties()

in git-server/src/main/java/jetbrains/buildServer/buildTriggers/vcs/git/GitUrlSupport.java [81:206]


  public Map<String, String> convertToVcsRootProperties(@NotNull VcsUrl url, @NotNull VcsOperationContext operationContext) throws VcsException {
    String scmName = getMavenScmName(url);
    if (scmName != null && !"git".equalsIgnoreCase(scmName) && !"ssh".equalsIgnoreCase(scmName)) //some other scm provider
      return null;

    String fetchUrl = getFetchUrl(url);
    String lowerCaseFetchUrl = StringUtil.toLowerCase(fetchUrl);

    if (!myConfig.isAllowFileUrl() && GitRemoteUrlInspector.isLocalFileAccess(fetchUrl)) {
      throw new VcsException("The git fetch URL most not be a local file URL");
    }

    URIish uri = parseURIish(fetchUrl);

    if (lowerCaseFetchUrl.startsWith("https://") && !lowerCaseFetchUrl.endsWith(".git") && !lowerCaseFetchUrl.endsWith(".git/")) {
      VcsHostingRepo gitlabRepo = WellKnownHostingsUtil.getGitlabRepo(uri);
      if (gitlabRepo != null) {
        // if repo ends with a backslash, but does not have ".git" suffix, we have to remove the backslash for JGit to work
        fetchUrl = StringUtil.removeTailingSlash(fetchUrl);
        // for GitLab we need to add .git suffix to the fetch URL, otherwise, for some reason JGit can't work with this repository (although regular git command works)
        fetchUrl = fetchUrl + ".git";
        uri = parseURIish(fetchUrl);
      }
    }

    final SProject curProject = myProjectManager == null ? null : myProjectManager.findProjectById(operationContext.getCurrentProjectId());

    Map<String, String> props = new HashMap<>(myGitSupport.getDefaultVcsProperties());
    props.put(Constants.FETCH_URL, fetchUrl);
    props.putAll(getAuthSettings(url, uri));

    // GitHub api does not seem to work with uri ending with trailing slash, but git works with it.
    // no need to remove "/" from actual uri stored in properties
    uri = uri.setPath(StringUtil.removeTailingSlash(uri.getPath()));

    VcsHostingRepo ghRepo = WellKnownHostingsUtil.getGitHubRepo(uri);
    if (ghRepo != null && curProject != null)
      refineGithubSettings(ghRepo, props, curProject);

    if (AuthenticationMethod.PRIVATE_KEY_DEFAULT.toString().equals(props.get(Constants.AUTH_METHOD))
        && curProject != null
        && isSsh(uri)) {
      ServerSshKeyManager serverSshKeyManager = getSshKeyManager();

      int numSshKeysTried = 0;

      if (serverSshKeyManager != null) {
        Credentials credentials = url.getCredentials();
        // if credentials are provided, trying to find matching key
        if (credentials != null) {
          TeamCitySshKey key = serverSshKeyManager.getKey(curProject, credentials.getUsername());
          if (key != null) {
            Map<String, String> propsCopy = new HashMap<>(props);
            propsCopy.put(Constants.AUTH_METHOD, AuthenticationMethod.TEAMCITY_SSH_KEY.toString());
            propsCopy.put(VcsRootSshKeyManager.VCS_ROOT_TEAMCITY_SSH_KEY_NAME, key.getName());

            if (key.isEncrypted()) {
              String passphrase = credentials.getPassword();
              if (StringUtil.isNotEmpty(passphrase)) {
                propsCopy.put(Constants.PASSPHRASE, passphrase);
              }
            }

            try {
              return testConnection(propsCopy, curProject);
            } catch (VcsException e) {
              // here we try to use the exact key, so if it does not fit - we fail the check
              if (isBranchRelatedError(e) || GitServerUtil.isAuthError(e) || fetchUrl.toLowerCase().contains("git")) throw e;
            }
          }
        }

        // SSH access, before using the default private key which may not be accessible on the agent,
        // let's iterate over all SSH keys of the current project, maybe we'll find a working one
        for (TeamCitySshKey key: serverSshKeyManager.getKeys(curProject)) {
          if (key.isEncrypted()) continue; // don't know password, so can't use it

          Map<String, String> propsCopy = new HashMap<>(props);
          propsCopy.put(Constants.AUTH_METHOD, AuthenticationMethod.TEAMCITY_SSH_KEY.toString());
          propsCopy.put(VcsRootSshKeyManager.VCS_ROOT_TEAMCITY_SSH_KEY_NAME, key.getName());

          try {
            numSshKeysTried++;
            return testConnection(propsCopy, curProject);
          } catch (VcsException e) {
            if (isBranchRelatedError(e)) throw e;
          }
        }
      }

      // could not find any valid keys, proceed with default SSH key
      try {
        return testConnection(props, curProject);
      } catch (VcsException e) {
        if (isBranchRelatedError(e)) throw e;

        String message = "Could not connect to the Git repository by SSH protocol.";
        if (numSshKeysTried > 0) {
          message += " Tried " + numSshKeysTried + " SSH " + StringUtil.pluralize("key", numSshKeysTried) +
                     " accessible from the current project.";
        } else {
          message += " Could not find an SSH key in the current project which would work with this Git repository.";
        }

        throw new VcsException(message + " Error message: " + e.getMessage(), e);
      }
    }

    final boolean defaultBranchKnown = props.get(Constants.BRANCH_NAME) != null;
    if (defaultBranchKnown) {
      //git protocol, or git scm provider
      if ("git".equalsIgnoreCase(scmName) || "git".equalsIgnoreCase(uri.getScheme()) || fetchUrl.endsWith(".git") || lowerCaseFetchUrl.endsWith(".git")) return props;
    }

    // need to guess default branch or
    // not SSH or URL does not end with .git, still try to connect just for the case
    try {
      return testConnection(props, curProject);
    } catch (VcsException e) {
      if (isBranchRelatedError(e) || GitServerUtil.isAuthError(e) || fetchUrl.toLowerCase().contains("git")) throw e;

      // probably not git
      Loggers.VCS.infoAndDebugDetails("Failed to recognize " + url.getUrl() + " as a git repository", e);
      return null;
    }
  }