Merge branch 'Indore-2017.1.x'
[teamcity/git-plugin.git] / git-server / src / jetbrains / buildServer / buildTriggers / vcs / git / GitUrlSupport.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package jetbrains.buildServer.buildTriggers.vcs.git;
18
19 import jetbrains.buildServer.util.positioning.PositionAware;
20 import jetbrains.buildServer.util.positioning.PositionConstraint;
21 import jetbrains.buildServer.vcs.*;
22 import jetbrains.buildServer.vcs.impl.VcsRootImpl;
23 import org.eclipse.egit.github.core.Repository;
24 import org.eclipse.egit.github.core.client.GitHubClient;
25 import org.eclipse.egit.github.core.service.RepositoryService;
26 import org.eclipse.jgit.transport.URIish;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29
30 import java.io.IOException;
31 import java.net.URISyntaxException;
32 import java.util.HashMap;
33 import java.util.Map;
34
35 /**
36  * @author dmitry.neverov
37  */
38 public class GitUrlSupport implements UrlSupport, PositionAware {
39
40   private final GitVcsSupport myGitSupport;
41
42   public GitUrlSupport(@NotNull GitVcsSupport gitSupport) {
43     myGitSupport = gitSupport;
44   }
45
46   @Nullable
47   public Map<String, String> convertToVcsRootProperties(@NotNull VcsUrl url) throws VcsException {
48     String scmName = getMavenScmName(url);
49     if (scmName != null && !"git".equals(scmName) && !"ssh".equals(scmName)) //some other scm provider
50       return null;
51
52     String fetchUrl = getFetchUrl(url);
53
54     URIish uri;
55     try {
56       uri = new URIish(fetchUrl);
57     } catch (URISyntaxException e) {
58       throw new VcsException(e.getMessage(), e);
59     }
60
61     if (fetchUrl.startsWith("https://") && !fetchUrl.endsWith(".git")) {
62       VcsHostingRepo gitlabRepo = WellKnownHostingsUtil.getGitlabRepo(uri);
63       if (gitlabRepo != null) {
64         // 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)
65         fetchUrl = fetchUrl + ".git";
66       }
67     }
68
69     Map<String, String> props = new HashMap<>(myGitSupport.getDefaultVcsProperties());
70     props.put(Constants.FETCH_URL, fetchUrl);
71     props.putAll(getAuthSettings(url, uri));
72
73     VcsHostingRepo ghRepo = WellKnownHostingsUtil.getGitHubRepo(uri);
74     if (ghRepo != null)
75       refineGithubSettings(ghRepo, props);
76
77     if ("git".equals(scmName) || "git".equals(uri.getScheme()) || uri.getPath().endsWith(".git")) //git protocol, or git scm provider, or .git suffix
78       return props;
79
80     try {
81       myGitSupport.testConnection(new VcsRootImpl(-1, Constants.VCS_NAME, props));
82       return props;
83     } catch (VcsException e) {
84       if (GitServerUtil.isAuthError(e))
85         throw e;
86       return null; // probably not git
87     }
88   }
89
90   private void refineGithubSettings(@NotNull VcsHostingRepo ghRepo, @NotNull Map<String, String> props) {
91     GitHubClient client = new GitHubClient();
92     AuthSettings auth = new AuthSettings(props);
93     if (auth.getAuthMethod() == AuthenticationMethod.PASSWORD && auth.getUserName() != null && auth.getPassword() != null) {
94       client.setCredentials(auth.getUserName(), auth.getPassword());
95     }
96     try {
97       Repository r = new RepositoryService(client).getRepository(ghRepo.owner(), ghRepo.repoName());
98       props.put(Constants.BRANCH_NAME, GitUtils.expandRef(r.getMasterBranch()));
99     } catch (IOException e) {
100       //ignore, cannot refine settings
101     }
102   }
103
104   @NotNull
105   private Map<String, String> getAuthSettings(@NotNull VcsUrl url, @NotNull URIish uri) {
106     Map<String, String> authSettings = new HashMap<String, String>();
107     authSettings.put(Constants.AUTH_METHOD, getAuthMethod(url, uri).toString());
108     Credentials credentials = url.getCredentials();
109     if (credentials != null) {
110       authSettings.put(Constants.USERNAME, credentials.getUsername());
111       authSettings.put(Constants.PASSWORD, credentials.getPassword());
112     } else {
113       authSettings.put(Constants.USERNAME, uri.getUser());
114     }
115     return authSettings;
116   }
117
118   private AuthenticationMethod getAuthMethod(@NotNull VcsUrl url, @NotNull URIish uri) {
119     if (isScpSyntax(uri) || "ssh".equals(uri.getScheme()))
120       return AuthenticationMethod.PRIVATE_KEY_DEFAULT;
121     if (url.getCredentials() != null)
122       return AuthenticationMethod.PASSWORD;
123     return AuthenticationMethod.ANONYMOUS;
124   }
125
126   @Nullable
127   private String getMavenScmName(@NotNull VcsUrl url) {
128     MavenVcsUrl mavenUrl = url.asMavenVcsUrl();
129     if (mavenUrl == null)
130       return null;
131     return mavenUrl.getProviderSchema();
132   }
133
134   @NotNull
135   private String getFetchUrl(@NotNull VcsUrl url) {
136     MavenVcsUrl mavenUrl = url.asMavenVcsUrl();
137     if (mavenUrl != null)
138       return mavenUrl.getProviderSpecificPart();
139     return url.getUrl();
140   }
141
142   private boolean isScpSyntax(URIish uriish) {
143     return uriish.getScheme() == null && uriish.isRemote();
144   }
145
146   @NotNull
147   public String getOrderId() {
148     return myGitSupport.getName();
149   }
150
151   @NotNull
152   public PositionConstraint getConstraint() {
153     return PositionConstraint.first(); // placed first to avoid problems with GitHub and SVN
154   }
155 }