2 ~ Copyright 2000-2012 JetBrains s.r.o.
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
8 ~ http://www.apache.org/licenses/LICENSE-2.0
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.
17 <%@ page import="jetbrains.buildServer.buildTriggers.vcs.git.Constants" %>
18 <%@ page import="jetbrains.buildServer.buildTriggers.vcs.git.PluginConfigImpl" %>
19 <%@ page import="jetbrains.buildServer.serverSide.TeamCityProperties" %>
20 <%@ page import="jetbrains.buildServer.util.StringUtil" %>
21 <%@ page import="java.io.File" %>
22 <%@include file="/include.jsp" %>
23 <%@ taglib prefix="props" tagdir="/WEB-INF/tags/props" %>
24 <%@ taglib prefix="admin" tagdir="/WEB-INF/tags/admin" %>
26 <jsp:useBean id="propertiesBean" scope="request" type="jetbrains.buildServer.controllers.BasePropertiesBean"/>
27 <c:set var="gitPathEnv" value="<%= Constants.TEAMCITY_AGENT_GIT_PATH %>"/>
28 <c:set var="teamcitySshKeysEnabled" value="<%= PluginConfigImpl.isTeamcitySshKeysEnabled() %>"/>
29 <c:set var="showKnownHostsDbOption" value="<%= PluginConfigImpl.showKnownHostsDbOption() %>"/>
30 <c:set var="showCustomClonePath" value="<%= TeamCityProperties.getBoolean(Constants.CUSTOM_CLONE_PATH_ENABLED) &&
31 (TeamCityProperties.getBoolean(Constants.SHOW_CUSTOM_CLONE_PATH)
32 || !StringUtil.isEmpty(propertiesBean.getProperties().get(Constants.PATH))) %>"/>
34 .gitUsernameStyleHighlight {
35 color: rgb(97, 94, 192);
38 <script type="text/javascript">
39 uploadedKeySelected = function(encrypted) {
41 $j('#gitPassphraseRow').show();
43 $j('#secure\\:passphrase').val('');
44 $j('#gitPassphraseRow').hide();
48 <table class="runnerFormTable">
50 value='<%=new File(System.getProperty("user.home"), ".ssh"+File.separator+"config").getAbsolutePath() %>'/>
51 <l:settingsGroup title="General Settings">
53 <th><label for="url">Fetch URL: <l:star/></label></th>
54 <td><props:textProperty name="url" className="longField"/>
55 <jsp:include page="/admin/repositoryControls.html?projectId=${parentProject.externalId}&vcsType=git"/>
56 <div class="smallNote" style="margin: 0;">It is used for fetching data from the repository.</div>
57 <div id="fetchUrlCompatNote" class="smallNote error" style="margin: 0; display: none;"></div>
58 <span class="error" id="error_url"></span></td>
61 <th><label for="push_url">Push URL:</label></th>
62 <td><props:textProperty name="push_url" className="longField"/>
63 <div class="smallNote" style="margin: 0;">It is used for pushing tags to the remote repository.
64 If blank, the fetch url is used.
66 <div id="pushUrlCompatNote" class="smallNote error" style="margin: 0; display: none;"></div>
67 <span class="error" id="error_push_url"></span>
71 <th><label for="branch">Default branch: <l:star/></label></th>
73 <props:textProperty name="branch" className="longField"/>
74 <div class="smallNote" style="margin: 0">The main branch or tag to be monitored</div>
75 <span class="error" id="error_branch"></span>
78 <bs:branchSpecTableRow/>
79 <tr class="advancedSetting">
80 <th><label for="reportTagRevisions">Use tags as branches:</label></th>
82 <props:checkboxProperty name="reportTagRevisions"/>
83 <label for="reportTagRevisions">Enable to use tags in the branch specification</label>
86 <tr class="advancedSetting">
87 <th><label for="usernameStyle">Username style:</label></th>
88 <td><props:selectProperty name="usernameStyle" enableFilter="true" className="mediumField">
89 <props:option value="USERID">UserId</props:option>
90 <props:option value="NAME">Author Name</props:option>
91 <props:option value="FULL">Author Name and Email</props:option>
92 <props:option value="EMAIL">Author Email</props:option>
93 </props:selectProperty>
94 <div class="smallNote" style="margin: 0;">
95 Defines a way TeamCity binds VCS changes to the user. With
96 selected style and the following content of ~/.gitconfig:
97 <div style="font-weight: bold">[user]</div>
98 <div style="margin-left: 15px">name = <span id="gitConfigUserName">Joe Coder</span></div>
99 <div style="margin-left: 15px">email = <span id="gitConfigUserId">joe.coder</span><span id="gitConfigEmail">@acme.com</span></div>
100 you should enter <span id="usernameToEnter" class="gitUsernameStyleHighlight"></span> in
101 Version Control Username Settings in your profile.
103 Changing username style will affect only newly collected
104 changes. Old changes will continue to be stored with the style
105 that was active at the time of collecting changes.
109 <tr class="advancedSetting">
110 <th><label for="submoduleCheckout">Submodules:</label></th>
111 <td><props:selectProperty name="submoduleCheckout" enableFilter="true" className="mediumField">
112 <props:option value="IGNORE">Ignore</props:option>
113 <props:option value="CHECKOUT">Checkout</props:option>
114 </props:selectProperty>
115 <div class="smallNote" style="margin: 0">
116 Defines whether to checkout submodules
120 <tr class="advancedSetting">
121 <th><label for="userForTags">Username for tags/merge:</label></th>
122 <td><props:textProperty name="userForTags" className="longField"/>
123 <div class="smallNote" style="margin: 0">Format: Username <email></div>
127 <l:settingsGroup title="Authentication Settings">
129 <th><label for="authMethod">Authentication method:</label></th>
131 <props:selectProperty name="authMethod" onchange="gitSelectAuthentication(true)" enableFilter="true" className="mediumField">
132 <props:option value="ANONYMOUS">Anonymous</props:option>
133 <props:option value="PASSWORD">Password</props:option>
134 <optgroup label="Private Key">
135 <c:if test="${teamcitySshKeysEnabled}">
136 <props:option value="TEAMCITY_SSH_KEY">Uploaded Key</props:option>
138 <props:option value="PRIVATE_KEY_DEFAULT">Default Private Key</props:option>
139 <props:option value="PRIVATE_KEY_FILE">Custom Private Key</props:option>
141 </props:selectProperty>
142 <div id="defaultPrivateKeyNote" class="smallNote auth defaultKey" style="margin: 0">Uses mapping specified in the file
143 ${userHome} if that file exists.
145 <div id="authMethodCompatNote" class="smallNote" style="margin: 0; display: none;"></div>
148 <tr id="gitUsername" class="auth defaultKey customKey password uploadedKey">
149 <th><label for="username">Username:</label></th>
150 <td><props:textProperty name="username" className="longField"/>
151 <div class="smallNote" style="margin: 0">
152 Specify the username if there is no username in the clone URL. The username specified here overrides the username from the URL.
156 <tr id="gitPasswordRow" class="auth password">
157 <th><label for="secure:password">Password:</label></th>
158 <td><props:passwordProperty name="secure:password" className="longField"/></td>
160 <tr id="gitPrivateKeyRow" class="auth customKey">
161 <th><label for="privateKeyPath">Private key path: <l:star/></label></th>
162 <td><props:textProperty name="privateKeyPath" className="longField"/>
163 <div class="smallNote" style="margin: 0;">
164 Specify the path to the private key on the TeamCity server host.
166 <span class="error" id="error_privateKeyPath"></span>
169 <c:if test="${not empty vcsPropertiesBean.belongsToProject}">
170 <c:set var="projectId" value="${vcsPropertiesBean.belongsToProject.externalId}" scope="request"/>
172 <tr id="gitTeamCityKeyRow" class="auth uploadedKey">
173 <th><label for="teamcitySshKey">Uploaded Key: <l:star/></label></th>
175 <admin:sshKeys projectId="${projectId}" keySelectionCallback="uploadedKeySelected"/>
176 <span class="error" id="error_teamcitySshKey"></span>
179 <tr id="gitPassphraseRow" class="auth customKey">
180 <th><label for="secure:passphrase">Passphrase:</label></th>
181 <td><props:passwordProperty name="secure:passphrase" className="longField"/></td>
184 <c:when test="${showKnownHostsDbOption or not vcsPropertiesBean.propertiesBean.properties['ignoreKnownHosts']}">
185 <tr id="gitKnownHosts" class="advancedSetting">
186 <div class="auth defaultKey customKey uploadedKey">
187 <th><label for="ignoreKnownHosts">Ignore known hosts database:</label></th>
188 <td><props:checkboxProperty name="ignoreKnownHosts"/>
189 <c:out value="${vcsPropertiesBean.propertiesBean.properties['ignoreKnownHosts']}"/>
195 <props:hiddenProperty name="ignoreKnownHosts" value="true"/>
199 <l:settingsGroup title="Server Settings" className="advancedSetting">
200 <tr class="advancedSetting">
201 <td colspan="2">Settings that are used in case of server-side checkout.</td>
203 <tr class="advancedSetting">
205 <label for="serverSideAutoCrlf">Convert line-endings to CRLF:<bs:help file="Git" anchor="serverAutoCRLF"/></label>
208 <props:checkboxProperty name="serverSideAutoCrlf"/>
211 <c:if test="${showCustomClonePath}">
212 <tr class="advancedSetting">
213 <th><label for="path">Custom clone directory on server:<bs:help file="Git" anchor="customCloneDir"/></label></th>
214 <td><props:textProperty name="path" className="longField"/>
215 <div class="smallNote" style="margin: 0;">
216 A directory on the TeamCity server where a bare cloned repository is to be created. Leave blank to use the default path.
222 <l:settingsGroup title="Agent Settings" className="advancedSetting">
223 <tr class="advancedSetting">
224 <td colspan="2">Agent-specific settings that are used in case of agent checkout.<bs:help file="Git" anchor="agentSettings"/></td>
226 <tr class="advancedSetting">
227 <th><label for="agentGitPath">Path to Git: </label></th>
228 <td><props:textProperty name="agentGitPath" className="longField"/>
229 <div class="smallNote" style="margin: 0;">
230 The path to a git executable on the agent. If blank, the location set up in ${gitPathEnv} environment variable is used.
234 <tr class="advancedSetting">
235 <th><label for="agentCleanPolicy">Clean policy:</label></th>
236 <td><props:selectProperty name="agentCleanPolicy" enableFilter="true" className="mediumField">
237 <props:option value="ON_BRANCH_CHANGE">On Branch Change</props:option>
238 <props:option value="ALWAYS">Always</props:option>
239 <props:option value="NEVER">Never</props:option>
240 </props:selectProperty>
241 <div class="smallNote" style="margin: 0">
242 This option specifies when the "git clean" command is run on the agent.
246 <tr class="advancedSetting">
247 <th><label for="agentCleanFilesPolicy">Clean files policy:</label></th>
248 <td><props:selectProperty name="agentCleanFilesPolicy" enableFilter="true" className="mediumField">
249 <props:option value="ALL_UNTRACKED">All untracked files</props:option>
250 <props:option value="IGNORED_ONLY">All ignored untracked files</props:option>
251 <props:option value="NON_IGNORED_ONLY">All non-ignored untracked files</props:option>
252 </props:selectProperty>
253 <div class="smallNote" style="margin: 0">This option specifies which files will be removed when "git
254 clean" command is run on agent.
258 <tr class="advancedSetting">
259 <th><label for="useAlternates">Use mirrors:</label></th>
261 <props:checkboxProperty name="useAlternates"/>
262 <div class="smallNote" style="margin: 0" >
263 When this option is enabled, TeamCity creates a separate clone of the repository on each agent
264 and uses it in the checkout directory via git alternates.
270 <script type="text/javascript">
272 compatibleAuthMethods: {//protocol -> compatible auth methods
273 'git' : ['ANONYMOUS'],
274 'http' : ['ANONYMOUS', 'PASSWORD'],
275 'https' : ['ANONYMOUS', 'PASSWORD']
279 getProtocol: function($element) {
280 var url = $element.val();
282 if (url.startsWith('git://')) {
284 } else if (url.startsWith('http://')) {
286 } else if (url.startsWith('https://')) {
297 getAuthMethodName: function(authMethod) {
298 return $j("#authMethod option[value=" + authMethod + "]").text();
302 getCompatibleMethods: function(proto) {
304 return this.getAllAuthMethods();
306 var compat = this.compatibleAuthMethods[proto];
310 //no constraints for given protocol
311 return this.getAllAuthMethods();
317 getAllAuthMethods: function() {
319 $j('#authMethod option').each(function() {
320 result.push($j(this).val());
326 contains: function (arr, elem) {
327 return arr.indexOf(elem) != -1;
331 disableIncompatible: function (fetchCompatible, pushCompatible, selected) {
333 $j('#authMethod option').each(function() {
334 var method = $j(this).val();
335 if (method == selected || that.contains(fetchCompatible, method) && that.contains(pushCompatible, method)) {
336 $j(this).attr("disabled", false);
338 $j(this).attr("disabled", "disabled");
344 getLimitingProtocols: function (fetchProto, fetchCompatMethods, pushProto, pushCompatMethods) {
345 var allMethods = this.getAllAuthMethods();
346 var limitingProtocols = [];
347 if (fetchCompatMethods.length < allMethods.length) {
348 limitingProtocols.push("'" + fetchProto + "'");
350 if (pushCompatMethods.length < allMethods.length && pushProto != fetchProto) {
351 limitingProtocols.push("'" + pushProto + "'");
353 var size = limitingProtocols.length;
357 return (size == 1 ? "the " : "") + limitingProtocols.join(" and ") + " protocol" + (size > 1 ? "s" : "");
362 applyAuthConstraints: function () {
363 var selectedAuthMethod = $j('#authMethod').val();
364 var authMethodName = this.getAuthMethodName(selectedAuthMethod);
365 var fetchProto = this.getProtocol($j('#url'));
366 var pushProto = this.getProtocol($j('#push_url'));
368 var fetchCompatMethods = this.getCompatibleMethods(fetchProto);
369 var pushCompatMethods = this.getCompatibleMethods(pushProto);
370 var fetchCompatible = true;
371 var pushCompatible = true;
372 if (this.contains(fetchCompatMethods, selectedAuthMethod)) {
373 $j('#fetchUrlCompatNote').hide();
375 fetchCompatible = false;
376 $j('#fetchUrlCompatNote')
377 .text("The '" + authMethodName + "' authentication method is incompatible with the '" + fetchProto + "' protocol")
381 if (this.contains(pushCompatMethods, selectedAuthMethod)) {
382 $j('#pushUrlCompatNote').hide();
384 pushCompatible = false;
385 $j('#pushUrlCompatNote')
386 .text("The '" + authMethodName + "' authentication method is incompatible with the '" + pushProto + "' protocol")
390 this.disableIncompatible(fetchCompatMethods, pushCompatMethods, selectedAuthMethod);
392 if (!fetchCompatible || !pushCompatible) {
393 //incompatible method selected, show error
394 var protocol = !fetchCompatible ? fetchProto : pushProto;
395 var usage = !fetchCompatible ? "Fetch URL" : "Push URL";
396 $j('#authMethodCompatNote')
397 .text("Selected authentication method is incompatible with the '" + protocol + "' protocol (" + usage + ")")
401 var limitingProtocols = this.getLimitingProtocols(fetchProto, fetchCompatMethods, pushProto, pushCompatMethods);
402 if (limitingProtocols) {
403 //there are incompatible methods, show note
404 $j('#authMethodCompatNote').text("Authentication methods incompatible with " + limitingProtocols + " are disabled")
405 .removeClass('error')
408 //all methods are compatible, hide note
409 $j('#authMethodCompatNote').hide();
414 $j("#authMethod").ufd("changeOptions");
418 $j('#url').keyup(function() {Git.applyAuthConstraints();});
419 $j('#push_url').keyup(function() {Git.applyAuthConstraints();});
421 gitSelectAuthentication = function(resetHiddenFields) {
422 BS.Util.toggleDependentElements($('authMethod').value, 'auth', resetHiddenFields, {
423 PRIVATE_KEY_DEFAULT : 'defaultKey',
424 PRIVATE_KEY_FILE : 'customKey',
425 PASSWORD : 'password',
426 ANONYMOUS : 'anonymous',
427 TEAMCITY_SSH_KEY : 'uploadedKey'
429 Git.applyAuthConstraints();
430 BS.VisibilityHandlers.updateVisibility($('vcsRootProperties'));
432 gitSelectAuthentication(false);
434 illustrateUsernameStyle = function() {
435 var style = $j("#usernameStyle").val();
436 $j("#gitConfigUserName").removeClass("gitUsernameStyleHighlight");
437 $j("#gitConfigUserId").removeClass("gitUsernameStyleHighlight");
438 $j("#gitConfigEmail").removeClass("gitUsernameStyleHighlight");
439 if (style === "USERID") {
440 $j("#gitConfigUserId").addClass("gitUsernameStyleHighlight");
441 $j("#usernameToEnter").text("joe.coder");
442 } else if (style === "NAME") {
443 $j("#gitConfigUserName").addClass("gitUsernameStyleHighlight");
444 $j("#usernameToEnter").text("Joe Coder");
445 } else if (style === "FULL") {
446 $j("#gitConfigUserName").addClass("gitUsernameStyleHighlight");
447 $j("#gitConfigUserId").addClass("gitUsernameStyleHighlight");
448 $j("#gitConfigEmail").addClass("gitUsernameStyleHighlight");
449 $j("#usernameToEnter").text("Joe Coder <joe.coder@acme.com>");
450 } else if (style === "EMAIL") {
451 $j("#gitConfigUserId").addClass("gitUsernameStyleHighlight");
452 $j("#gitConfigEmail").addClass("gitUsernameStyleHighlight");
453 $j("#usernameToEnter").text("joe.coder@acme.com");
457 illustrateUsernameStyle();
459 $j("#usernameStyle").change(illustrateUsernameStyle);
461 $j(document).ready(function() {
462 if (BS.Repositories != null) {
463 BS.Repositories.installControls($('url'), function (repoInfo, cre) {
464 $('url').value = repoInfo.repositoryUrl;
466 $('authMethod').value = 'PASSWORD';
467 BS.jQueryDropdown($('authMethod')).ufd("changeOptions");
468 $('username').value = cre.oauthLogin;
469 gitSelectAuthentication(true);
473 $j('.listRepositoriesControls').hide();