2 * Copyright 2000-2018 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 package jetbrains.buildServer.buildTriggers.vcs.git.tests;
19 import com.intellij.openapi.util.SystemInfo;
20 import com.intellij.openapi.util.io.StreamUtil;
21 import jetbrains.buildServer.TempFiles;
22 import jetbrains.buildServer.TestInternalProperties;
23 import jetbrains.buildServer.agent.AgentRunningBuild;
24 import jetbrains.buildServer.agent.AgentRuntimeProperties;
25 import jetbrains.buildServer.buildTriggers.vcs.git.*;
26 import jetbrains.buildServer.buildTriggers.vcs.git.Constants;
27 import jetbrains.buildServer.buildTriggers.vcs.git.agent.*;
28 import jetbrains.buildServer.buildTriggers.vcs.git.agent.PluginConfigImpl;
29 import jetbrains.buildServer.buildTriggers.vcs.git.agent.command.FetchCommand;
30 import jetbrains.buildServer.buildTriggers.vcs.git.agent.command.LsRemoteCommand;
31 import jetbrains.buildServer.buildTriggers.vcs.git.agent.command.UpdateRefCommand;
32 import jetbrains.buildServer.buildTriggers.vcs.git.agent.command.impl.*;
33 import jetbrains.buildServer.buildTriggers.vcs.git.agent.errors.GitExecTimeout;
34 import jetbrains.buildServer.ssh.VcsRootSshKeyManager;
35 import jetbrains.buildServer.util.FileUtil;
36 import jetbrains.buildServer.util.TestFor;
37 import jetbrains.buildServer.vcs.CheckoutRules;
38 import jetbrains.buildServer.vcs.VcsException;
39 import jetbrains.buildServer.vcs.impl.VcsRootImpl;
40 import org.eclipse.jgit.api.Git;
41 import org.eclipse.jgit.lib.*;
42 import org.eclipse.jgit.revwalk.RevCommit;
43 import org.eclipse.jgit.transport.URIish;
44 import org.jetbrains.annotations.NotNull;
45 import org.jetbrains.annotations.Nullable;
46 import org.testng.SkipException;
47 import org.testng.annotations.AfterMethod;
48 import org.testng.annotations.BeforeMethod;
49 import org.testng.annotations.DataProvider;
50 import org.testng.annotations.Test;
53 import java.io.FileFilter;
54 import java.io.FileReader;
55 import java.io.IOException;
56 import java.lang.reflect.Method;
57 import java.util.HashMap;
60 import java.util.concurrent.atomic.AtomicInteger;
61 import java.util.regex.Matcher;
63 import static com.intellij.openapi.util.io.FileUtil.copyDir;
64 import static com.intellij.openapi.util.io.FileUtil.delete;
65 import static jetbrains.buildServer.buildTriggers.vcs.git.tests.GitTestUtil.dataFile;
66 import static jetbrains.buildServer.buildTriggers.vcs.git.tests.GitVersionProvider.getGitPath;
67 import static jetbrains.buildServer.buildTriggers.vcs.git.tests.VcsRootBuilder.vcsRoot;
68 import static jetbrains.buildServer.buildTriggers.vcs.git.tests.builders.AgentRunningBuildBuilder.runningBuild;
69 import static jetbrains.buildServer.util.FileUtil.writeFileAndReportErrors;
70 import static jetbrains.buildServer.util.Util.map;
71 import static org.assertj.core.api.BDDAssertions.then;
72 import static org.testng.AssertJUnit.*;
75 * @author dmitry.neverov
78 public class AgentVcsSupportTest {
80 private TempFiles myTempFiles;
81 private File myMainRepo;
82 private File myCheckoutDir;
83 private VcsRootImpl myRoot;
84 private int myVcsRootId = 0;
85 private GitAgentVcsSupport myVcsSupport;
86 private AgentRunningBuild myBuild;
87 private AgentSupportBuilder myBuilder;
90 public void setUp() throws Exception {
91 TestInternalProperties.init();
92 myTempFiles = new TempFiles();
94 File repositoriesDir = myTempFiles.createTempDir();
96 File masterRep = dataFile("repo.git");
97 myMainRepo = new File(repositoriesDir, "repo.git");
98 copyRepository(masterRep, myMainRepo);
100 File submoduleRep = dataFile("submodule.git");
101 copyRepository(submoduleRep, new File(repositoriesDir, "submodule.git"));
103 File submoduleRep2 = dataFile("sub-submodule.git");
104 copyRepository(submoduleRep2, new File(repositoriesDir, "sub-submodule.git"));
106 myCheckoutDir = myTempFiles.createTempDir();
107 myBuilder = new AgentSupportBuilder(myTempFiles);
108 myVcsSupport = myBuilder.build();
109 myBuild = createRunningBuild(true);
110 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).build();
115 protected void tearDown() throws Exception {
116 myTempFiles.cleanup();
120 @TestFor(issues = "TW-33401")
121 @Test(dataProvider = "mirrors")
122 public void should_not_remove_remote_tracking_branches(Boolean useMirrors) throws Exception {
123 VcsRootSshKeyManagerProvider provider = new VcsRootSshKeyManagerProvider() {
125 public VcsRootSshKeyManager getSshKeyManager() {
129 LoggingGitMetaFactory loggingFactory = new LoggingGitMetaFactory();
131 GitAgentVcsSupport git = myBuilder.setSshKeyProvider(provider).setGitMetaFactory(loggingFactory).build();
133 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.USE_MIRRORS, useMirrors.toString()));
135 git.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
136 loggingFactory.clear();
138 //we already have everything we need for this update, no fetch should be executed
139 git.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
141 assertFalse("Refs removed: " + loggingFactory.getInvokedMethods(UpdateRefCommand.class),
142 loggingFactory.getInvokedMethods(UpdateRefCommand.class).contains("delete"));
143 assertTrue("Redundant fetch", loggingFactory.getInvokedMethods(FetchCommand.class).isEmpty());
147 @TestFor(issues = "TW-42249")
148 public void should_not_invoke_fetch_in_working_dir_after_clean_checkout() throws Exception {
149 VcsRootSshKeyManagerProvider provider = new VcsRootSshKeyManagerProvider() {
151 public VcsRootSshKeyManager getSshKeyManager() {
155 LoggingGitMetaFactory loggingFactory = new LoggingGitMetaFactory();
156 GitAgentVcsSupport git = myBuilder.setSshKeyProvider(provider).setGitMetaFactory(loggingFactory).build();
158 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY,
159 PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY_ALTERNATES));
161 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(true).build();
162 git.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
164 assertEquals("Redundant fetch", 1, loggingFactory.getNumberOfCalls(FetchCommand.class));
168 @TestFor(issues = {"TW-42551", "TW-46857"})
169 public void should_set_remote_tracking_branch() throws Exception {
170 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY,
171 PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY_ALTERNATES));
173 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(true).build();
174 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
176 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
177 then(new BranchConfig(r.getConfig(), "master").getRemoteTrackingBranch()).isEqualTo("refs/remotes/origin/master");
180 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withBranch("personal-branch2").withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(true).build();
181 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "3df61e6f11a5a9b919cb3f786a83fdd09f058617", myCheckoutDir, build, false);
182 then(new BranchConfig(r.getConfig(), "personal-branch2").getRemoteTrackingBranch()).isEqualTo("refs/remotes/origin/personal-branch2");
186 @TestFor(issues = "TW-46854")
187 @Test(dataProvider = "mirrors")
188 public void should_update_remote_tracking_branch_in_case_of_fast_forward_update(boolean useMirrors) throws Exception {
189 File remoteRepo = myTempFiles.createTempDir();
191 copyRepository(dataFile("repo_for_fetch.2"), remoteRepo);
192 VcsRootImpl root = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(remoteRepo).withUseMirrors(useMirrors).build();
193 String buildBranchParam = GitUtils.getGitRootBranchParamName(root);
195 //run build in master branch
196 AgentRunningBuild build = createRunningBuild(map(buildBranchParam, "refs/heads/master"));
197 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "d47dda159b27b9a8c4cee4ce98e4435eb5b17168", myCheckoutDir, build, false);
199 //fast-forward update master to point to the same commit as master
200 Repository remote = new RepositoryBuilder().setGitDir(remoteRepo).build();
201 RefUpdate refUpdate = remote.updateRef("refs/heads/personal");
202 refUpdate.setNewObjectId(ObjectId.fromString("add81050184d3c818560bdd8839f50024c188586"));
205 //run build in personal branch
206 build = createRunningBuild(map(buildBranchParam, "refs/heads/personal"));
207 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "add81050184d3c818560bdd8839f50024c188586", myCheckoutDir, build, false);
209 //fast-forward update personal branch to point to the same commit as master
210 refUpdate = remote.updateRef("refs/heads/personal");
211 refUpdate.setNewObjectId(ObjectId.fromString("d47dda159b27b9a8c4cee4ce98e4435eb5b17168"));
214 //run build on updated personal branch
215 build = createRunningBuild(map(buildBranchParam, "refs/heads/personal"));
216 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "d47dda159b27b9a8c4cee4ce98e4435eb5b17168", myCheckoutDir, build, false);
218 //both branch and its remote-tracking branch should be updated
219 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
220 then(r.getAllRefs().get("refs/heads/personal").getObjectId().name()).isEqualTo("d47dda159b27b9a8c4cee4ce98e4435eb5b17168");
221 then(r.getAllRefs().get("refs/remotes/origin/personal").getObjectId().name()).isEqualTo("d47dda159b27b9a8c4cee4ce98e4435eb5b17168");
226 * Test work normally if .git/index.lock file exists
228 public void testRecoverIndexLock() throws Exception {
229 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD,
230 myCheckoutDir, myBuild, false);
232 //emulate incorrect git termination (in this it could leave index.lock file)
233 FileUtil.copy(new File(myCheckoutDir, ".git" + File.separator + "index"),
234 new File(myCheckoutDir, ".git" + File.separator + "index.lock"));
236 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.CUD1_VERSION, myCheckoutDir, myBuild, false);
241 * Test work normally if .git/refs/heads/<branch>.lock file exists
243 public void testRecoverRefLock() throws Exception {
244 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, myBuild, false);
246 String firstCommitInPatchTests = GitUtils.makeVersion("a894d7d58ffde625019a9ecf8267f5f1d1e5c341", 1245766034000L);
247 myRoot.addProperty(Constants.BRANCH_NAME, "patch-tests");
248 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), firstCommitInPatchTests, myCheckoutDir, myBuild, false);
250 myRoot.addProperty(Constants.BRANCH_NAME, "master");
251 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, myBuild, false);
253 //emulate incorrect git termination (in this it could leave refs/heads/<branch-name>.lock file)
254 FileUtil.createIfDoesntExist(new File(myCheckoutDir, ".git" + File.separator + GitUtils.expandRef("master") + ".lock"));
255 //should recover from locked ref if previous checkout was on the same branch:
256 myRoot.addProperty(Constants.BRANCH_NAME, "master");
257 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), firstCommitInPatchTests, myCheckoutDir, myBuild, false);
259 //emulate incorrect git termination (in this it could leave refs/heads/<branch-name>.lock file)
260 FileUtil.createIfDoesntExist(new File(myCheckoutDir, ".git" + File.separator + GitUtils.expandRef("patch-tests") + ".lock"));
261 //should recover from locked ref if previous checkout was on a different branch:
262 myRoot.addProperty(Constants.BRANCH_NAME, "patch-tests");
263 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), firstCommitInPatchTests, myCheckoutDir, myBuild, false);
267 @TestFor(issues = "TW-31381")
268 public void recover_from_ref_lock_during_fetch() throws Exception {
269 File repo = dataFile("repo_for_fetch.2.personal");
270 File remoteRepo = myTempFiles.createTempDir();
271 copyRepository(repo, remoteRepo);
273 final String fetchUrl = GitUtils.toURL(remoteRepo);
274 VcsRootImpl root = vcsRoot().withBranch("refs/heads/master").withAgentGitPath(getGitPath()).withFetchUrl(fetchUrl).build();
275 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "add81050184d3c818560bdd8839f50024c188586", myCheckoutDir, myBuild, false);
277 //update remote branch master
279 File updatedRepo = dataFile("repo_for_fetch.2");
280 copyRepository(updatedRepo, remoteRepo);
282 File mirror = myBuilder.getMirrorManager().getMirrorDir(fetchUrl);
283 FileUtil.createIfDoesntExist(new File(mirror, "refs/heads/master.lock"));
284 FileUtil.createIfDoesntExist(new File(myCheckoutDir, ".git/refs/heads/master.lock"));
285 FileUtil.createIfDoesntExist(new File(myCheckoutDir, ".git/refs/remotes/origin/master.lock"));
288 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "d47dda159b27b9a8c4cee4ce98e4435eb5b17168", myCheckoutDir, myBuild, false);
292 @TestFor(issues = "TW-31039")
293 @Test(dataProvider = "mirrors")
294 public void build_on_pull_request(Boolean useMirrors) throws Exception {
295 //Remote repo contains a pull request branch refs/changes/2/1 which is not under refs/heads/*,
296 //this branch points to a commit which is not reachable from the default branch in vcs root
297 //and from any other branches under refs/heads/.
299 //Ensure that once we pass a pull request branch name, checkout it successful
300 VcsRootImpl root = createRoot(myMainRepo, "master");
301 String pullRequestCommit = "ea5e05051fbfaa7d8da97586807b009cbfebae9d";
302 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.USE_MIRRORS, String.valueOf(useMirrors),
303 GitUtils.getGitRootBranchParamName(root), "refs/changes/2/1"));
304 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, pullRequestCommit, myCheckoutDir, build, false);
309 * Test checkout submodules on agent. Machine that runs this test should have git installed.
311 public void testSubmodulesCheckout() throws Exception {
312 myRoot.addProperty(Constants.BRANCH_NAME, "patch-tests");
313 myRoot.addProperty(Constants.SUBMODULES_CHECKOUT, SubmodulesCheckoutPolicy.CHECKOUT.name());
315 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.SUBMODULE_ADDED_VERSION,
316 myCheckoutDir, myBuild, false);
318 assertTrue(new File(myCheckoutDir, "submodule" + File.separator + "file.txt").exists());
323 * Test non-recursive submodules checkout: submodules of submodules are not retrieved
325 public void testSubSubmodulesCheckoutNonRecursive() throws Exception {
326 testSubSubmoduleCheckout(false);
331 * Test recursive submodules checkout: submodules of submodules are retrieved
333 public void testSubSubmodulesCheckoutRecursive() throws Exception {
334 testSubSubmoduleCheckout(true);
338 @TestFor(issues = "TW-27043")
339 public void clean_files_in_submodules() throws Exception {
340 //vcs root with submodules which cleans all untracked files on every build:
341 myRoot.addProperty(Constants.BRANCH_NAME, "sub-submodule");
342 myRoot.addProperty(Constants.SUBMODULES_CHECKOUT, SubmodulesCheckoutPolicy.CHECKOUT.name());
343 myRoot.addProperty(Constants.AGENT_CLEAN_FILES_POLICY, AgentCleanFilesPolicy.ALL_UNTRACKED.name());
344 myRoot.addProperty(Constants.AGENT_CLEAN_POLICY, AgentCleanPolicy.ALWAYS.name());
346 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "ce6044093939bb47283439d97a1c80f759669ff5", myCheckoutDir, myBuild, false);
348 //create untracked files inside submodules
349 File submoduleDir = new File(myCheckoutDir, "first-level-submodule");
350 File subSubmoduleDir = new File(submoduleDir, "sub-sub");
351 File untrackedFileSubmodule = new File(submoduleDir, "untracked");
352 File untrackedFileSubSubmodule = new File(subSubmoduleDir, "untracked");
353 assertTrue(untrackedFileSubmodule.createNewFile());
354 assertTrue(untrackedFileSubSubmodule.createNewFile());
356 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "ce6044093939bb47283439d97a1c80f759669ff5", myCheckoutDir, myBuild, false);
358 assertFalse(untrackedFileSubmodule.exists());
359 assertFalse(untrackedFileSubSubmodule.exists());
363 @DataProvider(name = "ignoredLongFileNames")
364 public Object[][] ignoredLongFileNames() {
365 return new Object[][] {{true}, {false}};
368 @TestFor(issues = "TW-35545")
369 @Test(dataProvider = "ignoredLongFileNames")
370 public void clean_files_with_long_names(Boolean filesWithLongNamesIgnored) throws Exception {
371 myRoot.addProperty(Constants.AGENT_CLEAN_FILES_POLICY, AgentCleanFilesPolicy.ALL_UNTRACKED.name());
372 myRoot.addProperty(Constants.AGENT_CLEAN_POLICY, AgentCleanPolicy.ALWAYS.name());
374 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, myBuild, false);
376 File dirWithLongName = new File(myCheckoutDir, "dirWithLongName");
377 for (int i = 0; i < 20; i++) {
378 dirWithLongName = new File(dirWithLongName, "dirWithLongName");
380 dirWithLongName.mkdirs();
382 File fileWithLongName = new File(dirWithLongName, "test");
383 writeFileAndReportErrors(fileWithLongName, "test");
385 if (filesWithLongNamesIgnored) {
386 File exclude = new File(myCheckoutDir, ".git/info/exclude".replaceAll("/", Matcher.quoteReplacement(File.separator)));
387 writeFileAndReportErrors(exclude, "dirWithLongName\n");
390 assertTrue(fileWithLongName.exists());
392 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, myBuild, false);
394 assertFalse(fileWithLongName.exists());
398 public void should_create_bare_repository_in_caches_dir() throws Exception {
399 File mirrorsDir = myBuilder.getAgentConfiguration().getCacheDirectory("git");
400 assertTrue(mirrorsDir.listFiles(new FileFilter() {
401 public boolean accept(File f) {
402 return f.isDirectory();
406 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, myBuild, false);
408 GitVcsRoot root = new GitVcsRoot(myBuilder.getMirrorManager(), myRoot);
409 File bareRepositoryDir = root.getRepositoryDir();
410 assertTrue(bareRepositoryDir.exists());
411 //check some dirs that should be present in the bare repository:
412 File objectsDir = new File(bareRepositoryDir, "objects");
413 assertTrue(new File(bareRepositoryDir, "info").exists());
414 assertTrue(objectsDir.exists());
415 assertTrue(new File(bareRepositoryDir, "refs").exists());
417 String config = FileUtil.loadTextAndClose(new FileReader(new File(bareRepositoryDir, "config")));
418 assertTrue(config.contains("[remote \"origin\"]"));
419 String remoteUrl = "url = " + root.getRepositoryFetchURL();
420 assertTrue(config.contains(remoteUrl));
422 File packDir = new File(objectsDir, "pack");
423 boolean looseObjectsExists = objectsDir.listFiles().length > 2;//2 - because there are 2 dirs there: info and pack
424 boolean packFilesExists = packDir.listFiles().length >=2; //at least one pack file with its index exists
425 boolean fetchWasDone = looseObjectsExists || packFilesExists;
426 assertTrue(fetchWasDone);
430 public void old_cloned_repository_should_use_local_mirror() throws Exception {
431 AgentRunningBuild buildBeforeUsingMirrors = createRunningBuild(false);
432 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, buildBeforeUsingMirrors, false);
433 AgentRunningBuild buildWithMirrorsEnabled = createRunningBuild(true);
434 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, buildWithMirrorsEnabled, false);
435 GitVcsRoot root = new GitVcsRoot(myBuilder.getMirrorManager(), myRoot);
436 String localMirrorUrl = new URIish(root.getRepositoryDir().toURI().toASCIIString()).toString();
437 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
438 assertEquals(root.getRepositoryFetchURL().toString(), r.getConfig().getString("url", localMirrorUrl, "insteadOf"));
442 public void do_not_use_mirror_if_agent_property_set_to_false() throws Exception {
443 AgentRunningBuild build2 = createRunningBuild(false);
444 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build2, false);
445 File gitConfigFile = new File(myCheckoutDir, ".git" + File.separator + "config");
446 String config = FileUtil.loadTextAndClose(new FileReader(gitConfigFile));
447 assertFalse(config, config.contains("insteadOf"));
451 public void stop_use_mirror_if_agent_property_changed_to_false() throws Exception {
452 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, myBuild, false);
454 AgentRunningBuild build2 = createRunningBuild(false);
455 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build2, false);
457 File gitConfigFile = new File(myCheckoutDir, ".git" + File.separator + "config");
458 String config = FileUtil.loadTextAndClose(new FileReader(gitConfigFile));
459 assertFalse(config, config.contains("insteadOf"));
463 public void stop_use_any_mirror_if_agent_property_changed_to_false() throws Exception {
464 AgentRunningBuild build2 = createRunningBuild(false);
465 GitVcsRoot root = new GitVcsRoot(myBuilder.getMirrorManager(), myRoot);
466 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build2, false);
469 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
470 StoredConfig config = r.getConfig();
471 config.setString("url", "/some/path", "insteadOf", root.getRepositoryFetchURL().toString());
474 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build2, false);
475 config = new RepositoryBuilder().setWorkTree(myCheckoutDir).build().getConfig();
476 assertTrue(config.getSubsections("url").isEmpty());
480 public void stop_using_alternates_when_mirrors_are_disabled_in_vcs_root_option() throws Exception {
481 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(true).build();
482 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, myBuild, false);
484 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(false).build();
485 AgentRunningBuild build2 = createRunningBuild(false);
486 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, build2, false);
488 assertFalse("Build uses alternates when they disabled in VCS root settings",
489 new File(myCheckoutDir, ".git/objects/info/alternates").exists());
493 public void stop_using_alternates_when_mirror_strategy_changed() throws Exception {
494 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(true).build();
495 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, myBuild, false);
497 AgentRunningBuild build2 = createRunningBuild(
498 map(PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY, PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY_MIRRORS_ONLY));
499 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, build2, false);
501 assertFalse("Build uses alternates when they disabled in VCS root settings",
502 new File(myCheckoutDir, ".git/objects/info/alternates").exists());
506 public void stop_using_mirrors_when_mirrors_are_disabled_in_vcs_root_option() throws Exception {
507 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(true).build();
508 AgentRunningBuild build1 = createRunningBuild(map(PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY, PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY_MIRRORS_ONLY));
509 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, build1, false);
511 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(false).build();
512 AgentRunningBuild build2 = createRunningBuild(false);
513 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, build2, false);
515 StoredConfig config = new RepositoryBuilder().setWorkTree(myCheckoutDir).build().getConfig();
516 assertTrue(config.getSubsections("url").isEmpty());
520 @TestFor(issues = "TW-25839")
521 public void update_should_not_fail_if_local_mirror_is_corrupted() throws Exception {
522 AgentRunningBuild buildWithMirrorsEnabled = createRunningBuild(true);
523 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, buildWithMirrorsEnabled, false);
525 //corrupt local mirror
526 GitVcsRoot root = new GitVcsRoot(myBuilder.getMirrorManager(), myRoot);
527 File mirror = myBuilder.getMirrorManager().getMirrorDir(root.getRepositoryFetchURL().toString());
528 File[] children = mirror.listFiles();
529 if (children != null) {
530 for (File child : children) {
535 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, buildWithMirrorsEnabled,
540 @TestFor(issues = "TW-29291")
541 public void shallow_clone_should_check_if_auxiliary_branch_already_exists() throws Exception {
542 AgentRunningBuild build = createRunningBuild(new HashMap<String, String>() {{
543 put(PluginConfigImpl.USE_MIRRORS, "true");
544 put(PluginConfigImpl.USE_SHALLOW_CLONE, "true");
546 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, build, true);
548 //manually create a branch tmp_branch_for_build with, it seems like it wasn't removed due to errors in previous checkouts
549 GitVcsRoot root = new GitVcsRoot(myBuilder.getMirrorManager(), myRoot);
550 File mirror = myBuilder.getMirrorManager().getMirrorDir(root.getRepositoryFetchURL().toString());
551 File emptyBranchFile = new File(mirror, "refs" + File.separator + "heads" + File.separator + "tmp_branch_for_build");
552 FileUtil.writeToFile(emptyBranchFile, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653\n".getBytes());
554 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, build, true);
558 public void when_fetch_for_mirror_failed_remove_it_and_try_again() throws Exception {
559 File repo = dataFile("repo_for_fetch.1");
560 File remoteRepo = myTempFiles.createTempDir();
561 copyRepository(repo, remoteRepo);
563 VcsRootImpl root = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(remoteRepo)).build();
565 AgentRunningBuild buildWithMirrors = createRunningBuild(true);
566 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "add81050184d3c818560bdd8839f50024c188586", myCheckoutDir, buildWithMirrors, false);
568 //create branch tmp in the mirror
569 File mirror = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(remoteRepo));
570 Repository r = new RepositoryBuilder().setBare().setGitDir(mirror).build();
571 RefUpdate update = r.updateRef("refs/heads/tmp");
572 update.setNewObjectId(ObjectId.fromString("add81050184d3c818560bdd8839f50024c188586"));
577 File updatedRepo = dataFile("repo_for_fetch.2.personal");
578 copyRepository(updatedRepo, remoteRepo);
580 //create branch tmp/1 in remote repo, so fetch will fail
581 r = new RepositoryBuilder().setBare().setGitDir(remoteRepo).build();
582 update = r.updateRef("refs/heads/tmp/1");
583 update.setNewObjectId(ObjectId.fromString("d47dda159b27b9a8c4cee4ce98e4435eb5b17168"));
587 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "d47dda159b27b9a8c4cee4ce98e4435eb5b17168", myCheckoutDir, buildWithMirrors, false);
591 public void should_handle_ref_pointing_to_invalid_object() throws Exception {
592 File repo = dataFile("repo_for_fetch.1");
593 File remoteRepo = myTempFiles.createTempDir();
594 copyRepository(repo, remoteRepo);
595 VcsRootImpl root = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(remoteRepo)).withUseMirrors(true).build();
598 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY, PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY_ALTERNATES));
599 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "add81050184d3c818560bdd8839f50024c188586", myCheckoutDir, build, false);
601 //create ref pointing to invalid object
602 File gitDir = new File(myCheckoutDir, ".git");
603 String invalidObject = "bba7fbcc200b4968e6abd2f7d475dc15306cafc1";
604 FileUtil.writeFile(new File(gitDir, "refs/heads/brokenRef"), invalidObject);
608 File updatedRepo = dataFile("repo_for_fetch.3");
609 copyRepository(updatedRepo, remoteRepo);
612 build = createRunningBuild(map(PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY, PluginConfigImpl.VCS_ROOT_MIRRORS_STRATEGY_ALTERNATES));
613 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "bba7fbcc200b4968e6abd2f7d475dc15306cafc6", myCheckoutDir, build, false);
614 then(new File(gitDir, "refs/heads/brokenRef")).doesNotExist();
618 @TestFor(issues = "TW-43884")
619 public void should_remap_mirror_if_its_fetch_and_remove_failed() throws Exception {
620 MockFS fs = new MockFS();
621 LoggingGitMetaFactory loggingFactory = new LoggingGitMetaFactory();
622 myVcsSupport = myBuilder.setGitMetaFactory(loggingFactory).setFS(fs).build();
624 File repo = dataFile("repo_for_fetch.1");
625 File remoteRepo = myTempFiles.createTempDir();
626 copyRepository(repo, remoteRepo);
628 //run build to prepare mirror
629 VcsRootImpl root = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(remoteRepo)).build();
630 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "add81050184d3c818560bdd8839f50024c188586", myCheckoutDir, createRunningBuild(true), false);
632 //update remote repo: add personal branch
634 File updatedRepo = dataFile("repo_for_fetch.2.personal");
635 copyRepository(updatedRepo, remoteRepo);
638 //make first fetch in local mirror to fail:
639 AtomicInteger invocationCount = new AtomicInteger(0);
640 loggingFactory.addCallback(FetchCommand.class.getName() + ".call", new GitCommandProxyCallback() {
642 public void call(final Method method, final Object[] args) throws VcsException {
643 if (invocationCount.getAndIncrement() == 0)
644 throw new VcsException("TEST ERROR");
647 File mirror = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(remoteRepo));
649 //try to fetch unknown branch, fetch fails and delete of the mirror also fails
650 //build should succeed anyway
651 fs.makeDeleteFail(mirror);
652 VcsRootImpl root2 = vcsRoot().withAgentGitPath(getGitPath()).withBranch("refs/heads/personal").withFetchUrl(GitUtils.toURL(remoteRepo)).build();
653 AgentRunningBuild build = runningBuild()
654 .useLocalMirrors(true)
655 .sharedConfigParams("teamcity.git.fetchMirrorRetryTimeouts", "")
657 myVcsSupport.updateSources(root2, CheckoutRules.DEFAULT, "d47dda159b27b9a8c4cee4ce98e4435eb5b17168", myCheckoutDir, build, false);
658 File mirrorAfterBuild = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(remoteRepo));
659 then(mirrorAfterBuild).isNotEqualTo(mirror);//repository was remapped to another dir
662 @TestFor(issues = "TW-56415")
663 public void should_retry_fetch_mirror() throws Exception {
664 MockFS fs = new MockFS();
665 LoggingGitMetaFactory loggingFactory = new LoggingGitMetaFactory();
666 myVcsSupport = myBuilder.setGitMetaFactory(loggingFactory).setFS(fs).build();
668 File repo = dataFile("repo_for_fetch.1");
669 File remoteRepo = myTempFiles.createTempDir();
670 copyRepository(repo, remoteRepo);
672 //run build to prepare mirror
673 VcsRootImpl root = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(remoteRepo)).build();
674 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "add81050184d3c818560bdd8839f50024c188586", myCheckoutDir, createRunningBuild(true), false);
676 //update remote repo: add personal branch
678 File updatedRepo = dataFile("repo_for_fetch.2.personal");
679 copyRepository(updatedRepo, remoteRepo);
682 //make first fetch in local mirror to fail:
683 AtomicInteger invocationCount = new AtomicInteger(0);
684 loggingFactory.addCallback(FetchCommand.class.getName() + ".call", new GitCommandProxyCallback() {
686 public void call(final Method method, final Object[] args) throws VcsException {
687 if (invocationCount.getAndIncrement() == 0)
688 throw new VcsException("TEST ERROR");
691 File mirror = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(remoteRepo));
693 //try to fetch unknown branch, first fetch fails, second succeeds. If it's not ensure that delete of the mirror also fails
694 //build should succeed anyway
695 fs.makeDeleteFail(mirror);
696 VcsRootImpl root2 = vcsRoot().withAgentGitPath(getGitPath()).withBranch("refs/heads/personal").withFetchUrl(GitUtils.toURL(remoteRepo)).build();
697 AgentRunningBuild build = runningBuild()
698 .useLocalMirrors(true)
699 .sharedConfigParams("teamcity.git.fetchMirrorRetryTimeouts", "0")
701 myVcsSupport.updateSources(root2, CheckoutRules.DEFAULT, "d47dda159b27b9a8c4cee4ce98e4435eb5b17168", myCheckoutDir, build, false);
702 File mirrorAfterBuild = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(remoteRepo));
703 then(mirrorAfterBuild).isEqualTo(mirror);//repository was remapped to another dir
707 //we run ls-remote during outdated refs cleanup which is needed to
708 //successfully checkout when ref a/b is renamed to A/b on win or mac (TW-28735).
709 //If we continue silently this can cause performance problems (TW-44944)
710 @TestFor(issues = "TW-44944")
711 public void should_fail_when_ls_remote_fails() throws Exception {
712 LoggingGitMetaFactory loggingFactory = new LoggingGitMetaFactory();
713 myVcsSupport = myBuilder.setGitMetaFactory(loggingFactory).build();
715 File repo = dataFile("repo_for_fetch.1");
716 File remoteRepo = myTempFiles.createTempDir();
717 copyRepository(repo, remoteRepo);
719 //run build to prepare working dir
720 VcsRootImpl root = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(remoteRepo)).build();
721 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "add81050184d3c818560bdd8839f50024c188586", myCheckoutDir, createRunningBuild(false), false);
723 loggingFactory.addCallback(LsRemoteCommand.class.getName() + ".call", new GitCommandProxyCallback() {
725 public void call(final Method method, final Object[] args) throws VcsException {
726 throw new VcsException("TEST ERROR");
730 //ls-remote will fail during this build
732 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "d47dda159b27b9a8c4cee4ce98e4435eb5b17168", myCheckoutDir, createRunningBuild(false), false);
734 } catch (VcsException e) {
740 public void do_not_delete_mirror_if_remote_ref_not_found() throws Exception {
741 MockFS fs = new MockFS();
742 myVcsSupport = myBuilder.setFS(fs).build();
744 File mirror = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(myMainRepo));
745 fs.makeDeleteFail(mirror);//if plugin will remove mirror it will fail and try to remap
746 myRoot = vcsRoot().withBranch("refs/heads/unknown").withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).build();
748 String unknownRevision = "abababababababababababababababababababab";
749 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, unknownRevision, myCheckoutDir, createRunningBuild(true), false);
750 fail("update on unknown branch should fail");
751 } catch (VcsException e) {
752 File mirrorAfterFailure = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(myMainRepo));
753 then(mirrorAfterFailure).isEqualTo(mirror);//failure should not cause delete or remap
758 public void do_not_delete_mirror_on_timeout() throws Exception {
759 MockFS fs = new MockFS();
760 myVcsSupport = myBuilder.setFS(fs).build();
762 String unreachableRepository = "git://some.org/unreachable.git";
763 File mirror = myBuilder.getMirrorManager().getMirrorDir(unreachableRepository);
764 fs.makeDeleteFail(mirror);//if plugin will remove mirror it will fail and try to remap
765 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(unreachableRepository).build();
767 String revision = "abababababababababababababababababababab";
768 AgentRunningBuild build = runningBuild().useLocalMirrors(true).sharedConfigParams("teamcity.git.idle.timeout.seconds", "1").build();
769 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, revision, myCheckoutDir, build, false);
770 fail("update on unreachable repository should fail");
771 } catch (VcsException e) {
772 if (e instanceof GitExecTimeout) {
773 File mirrorAfterFailure = myBuilder.getMirrorManager().getMirrorDir(unreachableRepository);
774 then(mirrorAfterFailure)
775 .overridingErrorMessage("Mirror changed after error " + e.toString())
776 .isEqualTo(mirror);//failure should not cause delete or remap
778 //on some platforms fetch from unknown host doesn't result in timeout error
779 throw new SkipException("Not a timeout error: " + e.toString());
785 @TestFor(issues = "TW-43884")
786 public void mirror_delete_can_be_disabled() throws Exception {
787 MockFS fs = new MockFS();
788 LoggingGitMetaFactory loggingFactory = new LoggingGitMetaFactory();
789 myVcsSupport = myBuilder.setGitMetaFactory(loggingFactory).setFS(fs).build();
791 File repo = dataFile("repo_for_fetch.1");
792 File remoteRepo = myTempFiles.createTempDir();
793 copyRepository(repo, remoteRepo);
795 //run build to prepare mirror
796 VcsRootImpl root = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(remoteRepo)).build();
797 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "add81050184d3c818560bdd8839f50024c188586", myCheckoutDir, createRunningBuild(true), false);
799 //update remote repo: add personal branch
801 File updatedRepo = dataFile("repo_for_fetch.2.personal");
802 copyRepository(updatedRepo, remoteRepo);
805 //create refs/heads/personal/1 so that incremental fetch will fail
806 AtomicInteger invocationCount = new AtomicInteger(0);
807 loggingFactory.addCallback(FetchCommand.class.getName() + ".call", new GitCommandProxyCallback() {
809 public void call(final Method method, final Object[] args) throws VcsException {
810 if (invocationCount.getAndIncrement() <= 1)
811 throw new VcsException("TEST ERROR");
814 File mirror = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(remoteRepo));
816 VcsRootImpl root2 = vcsRoot().withAgentGitPath(getGitPath()).withBranch("refs/heads/personal").withFetchUrl(GitUtils.toURL(remoteRepo)).build();
817 fs.makeDeleteFail(mirror);
819 AgentRunningBuild build = runningBuild()
820 .useLocalMirrors(true)
821 .sharedConfigParams(AgentRuntimeProperties.FAIL_ON_CLEAN_CHECKOUT, "true")
822 .sharedConfigParams("teamcity.git.fetchMirrorRetryTimeouts", "0")
824 myVcsSupport.updateSources(root2, CheckoutRules.DEFAULT, "d47dda159b27b9a8c4cee4ce98e4435eb5b17168", myCheckoutDir, build, false);
826 } catch (VcsException e) {
827 File mirrorAfterBuild = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(remoteRepo));
828 then(mirrorAfterBuild).isEqualTo(mirror);//should fail on first fetch attempt and not remap or delete the mirror
833 public void checkout_tag() throws Exception {
834 myRoot.addProperty(Constants.BRANCH_NAME, "refs/tags/v1.0");
835 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, myBuild, false);
837 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
838 Ref tagRef = r.getRef("refs/tags/v1.0");
839 assertNotNull(tagRef);
843 @TestFor(issues = "TW-38247")
844 public void checkout_revision_reachable_from_tag() throws Exception {
845 myRoot.addProperty(Constants.BRANCH_NAME, "refs/tags/v1.0");
846 String revisionInBuild = "2c7e90053e0f7a5dd25ea2a16ef8909ba71826f6";
847 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, revisionInBuild, myCheckoutDir, myBuild, false);
849 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
850 String workingDirRevision = r.getAllRefs().get("HEAD").getObjectId().name();
851 assertEquals("Wrong revision on agent", revisionInBuild, workingDirRevision);
855 public void do_not_create_branch_when_checkout_tag() throws Exception {
856 myRoot.addProperty(Constants.BRANCH_NAME, "refs/tags/v1.0");
857 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, myBuild, false);
859 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
860 Map<String, Ref> refs = r.getRefDatabase().getRefs("refs/");
861 assertTrue(refs.containsKey("tags/v1.0"));
862 assertTrue(refs.containsKey("tags/v0.7"));//it is reachable from refs/tags/v1.0
863 assertTrue(refs.containsKey("tags/v0.5"));//also reachable
864 assertEquals(3, refs.size());
868 @TestFor(issues = "TW-23707")
869 public void do_not_create_remote_branch_unexisting_in_remote_repository() throws Exception {
870 myRoot.addProperty(Constants.BRANCH_NAME, "refs/changes/1/1");
871 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "5711cbfe566b6c92e331f95d4b236483f4532eed", myCheckoutDir, myBuild, false);
872 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
873 assertEquals("5711cbfe566b6c92e331f95d4b236483f4532eed", r.getBranch());//checkout a detached commit
874 Map<String, Ref> refs = r.getAllRefs();
875 assertFalse(refs.containsKey("refs/heads/refs/changes/1/1"));
876 assertFalse(refs.containsKey("refs/remotes/origin/changes/1/1"));
880 public void checkout_tag_after_branch() throws Exception {
881 myRoot.addProperty(Constants.BRANCH_NAME, "sub-submodule");
882 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, myBuild, false);
884 myRoot.addProperty(Constants.BRANCH_NAME, "refs/tags/v1.0");
885 myVcsSupport.updateSources(myRoot, new CheckoutRules(""),
886 GitUtils.makeVersion("465ad9f630e451b9f2b782ffb09804c6a98c4bb9", 1289483394000L), myCheckoutDir, myBuild,
888 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
889 Ref headRef = r.getRef("HEAD");
890 assertEquals("465ad9f630e451b9f2b782ffb09804c6a98c4bb9", headRef.getObjectId().name());
894 public void should_checkout_tags_reachable_from_branch() throws Exception {
895 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, myBuild, false);
896 assertTagExists("refs/tags/v0.5");
897 assertTagExists("refs/tags/v1.0");
901 @Test(dataProvider = "mirrors")
902 public void deleted_tag_in_remote_repository_should_be_deleted_in_local_repository(Boolean useMirrors) throws Exception {
903 AgentRunningBuild build = createRunningBuild(useMirrors);
904 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build, false);
905 removeTag(myMainRepo, "refs/tags/v0.5");
907 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build, false);
908 assertNoTagExist("refs/tags/v0.5");
912 @Test(dataProvider = "mirrors")
913 public void updated_tag_in_remote_repository_should_be_updated_in_local_repository(Boolean useMirrors) throws Exception {
914 AgentRunningBuild build = createRunningBuild(useMirrors);
915 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build, false);
917 final String newCommit = "2c7e90053e0f7a5dd25ea2a16ef8909ba71826f6";
918 updateRef(myMainRepo, "refs/tags/v1.0", newCommit);
920 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build, false);
921 assertTagExists("refs/tags/v1.0");
922 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
923 Ref tag = r.getRef("refs/tags/v1.0");
924 assertEquals("Local tag is not updated", newCommit, tag.getObjectId().name());
928 @TestFor(issues = "TW-47805")
929 public void no_redundant_fetches_for_pull_requests() throws Exception {
930 LoggingGitMetaFactory loggingFactory = new LoggingGitMetaFactory();
931 myVcsSupport = myBuilder.setGitMetaFactory(loggingFactory).setFS(new MockFS()).build();
933 //create pull-request in remote repo
934 myRoot.addProperty(Constants.BRANCH_NAME, "refs/changes/1/1");
935 updateRef(myMainRepo, "refs/pull/1/head", "5711cbfe566b6c92e331f95d4b236483f4532eed");
937 //run build on pull-request
938 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "5711cbfe566b6c92e331f95d4b236483f4532eed", myCheckoutDir, myBuild, false);
941 int fetchesBefore = loggingFactory.getNumberOfCalls(FetchCommand.class);
942 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "5711cbfe566b6c92e331f95d4b236483f4532eed", myCheckoutDir, myBuild, false);
944 //there should be no fetches in the second build
945 int redundantFetches = loggingFactory.getNumberOfCalls(FetchCommand.class) - fetchesBefore;
946 then(redundantFetches).isEqualTo(0);
950 @Test(dataProvider = "mirrors")
951 public void fetch_all_heads(boolean useMirrors) throws Exception {
952 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.USE_MIRRORS, String.valueOf(useMirrors),
953 PluginConfigImpl.FETCH_ALL_HEADS, "true"));
955 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
957 Repository remoteRepo = new RepositoryBuilder().setBare().setGitDir(myMainRepo).build();
958 Set<String> remoteHeads = remoteRepo.getRefDatabase().getRefs("refs/heads/").keySet();
960 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
961 then(r.getRefDatabase().getRefs("refs/remotes/origin/").keySet()).containsAll(remoteHeads);
965 @TestFor(issues = "TW-50714")
966 @Test(dataProvider = "mirrors")
967 public void fetch_all_heads__non_head_ref(boolean useMirrors) throws Exception {
968 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.FETCH_ALL_HEADS, "true"));
970 myRoot = vcsRoot().withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).withUseMirrors(useMirrors).withBranch("refs/pull/1").build();
972 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "b896070465af79121c9a4eb5300ecff29453c164", myCheckoutDir, build, false);
976 @Test(dataProvider = "mirrors")
977 public void fetch_all_heads_before_build_branch(boolean useMirrors) throws Exception {
978 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.USE_MIRRORS, String.valueOf(useMirrors),
979 PluginConfigImpl.FETCH_ALL_HEADS, "beforeBuildBranch"));
981 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
983 Repository remoteRepo = new RepositoryBuilder().setBare().setGitDir(myMainRepo).build();
984 Set<String> remoteHeads = remoteRepo.getRefDatabase().getRefs("refs/heads/").keySet();
986 //local repo should contain all heads since build's commit wasn't on the agent
987 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
988 then(r.getRefDatabase().getRefs("refs/remotes/origin/").keySet()).containsAll(remoteHeads);
992 @Test(dataProvider = "mirrors")
993 public void fetch_all_heads_before_build_branch_commit_found(boolean useMirrors) throws Exception {
994 //run build to make sure commit is on the agent
995 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.USE_MIRRORS, String.valueOf(useMirrors)));
996 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
998 //run build with fetch_all_head before build's branch
999 build = createRunningBuild(map(PluginConfigImpl.USE_MIRRORS, String.valueOf(useMirrors),
1000 PluginConfigImpl.FETCH_ALL_HEADS, "beforeBuildBranch"));
1001 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
1003 //local repo shouldn't contain all heads since build commit was already on the agent and no fetch is required
1004 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
1005 then(r.getRefDatabase().getRefs("refs/remotes/origin/").keySet()).containsOnly("master");
1009 private void removeTag(@NotNull File dotGitDir, @NotNull String tagName) {
1010 delete(tagFile(dotGitDir, tagName));
1013 private void updateRef(@NotNull File dotGitDir, @NotNull String refName, @NotNull String commit) throws IOException {
1014 File tagFile = tagFile(dotGitDir, refName);
1015 FileUtil.writeToFile(tagFile, commit.getBytes());
1018 private File tagFile(@NotNull File dotGitDir, @NotNull String tagName) {
1019 return new File(dotGitDir, tagName.replaceAll("/", Matcher.quoteReplacement(File.separator)));
1022 private void assertNoTagExist(String tag) throws IOException {
1023 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
1024 assertNull("tag \'" + tag + "\' exists", r.getRef(tag));
1027 private void assertTagExists(String tag) throws IOException {
1028 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
1029 assertNotNull("tag \'" + tag + "\' doesn't exist", r.getRef(tag));
1032 @DataProvider(name = "mirrors")
1033 public Object[][] mirrors() {
1034 return new Object[][] {{true}, {false}};
1037 @Test(dataProvider = "mirrors")
1038 public void should_do_fetch_if_ref_is_outdated(Boolean useMirrors) throws Exception {
1039 AgentRunningBuild build = createRunningBuild(useMirrors);
1040 final File remote = myTempFiles.createTempDir();
1041 copyRepository(dataFile("repo_for_fetch.2.personal"), remote);
1042 VcsRootImpl masterRoot = createRoot(remote, "master");
1043 VcsRootImpl personalRoot = createRoot(remote, "personal");
1045 myVcsSupport.updateSources(personalRoot, new CheckoutRules(""), "d47dda159b27b9a8c4cee4ce98e4435eb5b17168@1303829462000", myCheckoutDir, build, false);
1046 myVcsSupport.updateSources(masterRoot, new CheckoutRules(""), "add81050184d3c818560bdd8839f50024c188586@1303829295000", myCheckoutDir, build, false);
1048 FileUtil.delete(remote);
1049 copyRepository(dataFile("repo_for_fetch.2"), remote);
1051 myVcsSupport.updateSources(masterRoot, new CheckoutRules(""), "d47dda159b27b9a8c4cee4ce98e4435eb5b17168@1303829462000", myCheckoutDir,
1056 @Test(dataProvider = "mirrors")
1057 public void test_update_on_revision_from_feature_branch(Boolean useMirrors) throws Exception {
1058 AgentRunningBuild build = createRunningBuild(useMirrors);
1059 final File remote = myTempFiles.createTempDir();
1060 copyRepository(dataFile("repo_for_fetch.2.personal"), remote);
1061 VcsRootImpl root = createRoot(remote, "master");
1062 String commitFromFeatureBranch = "d47dda159b27b9a8c4cee4ce98e4435eb5b17168";
1063 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, commitFromFeatureBranch, myCheckoutDir, build, false);
1067 @Test(dataProvider = "mirrors")
1068 public void should_use_branch_specified_in_build_parameter(Boolean useMirrors) throws Exception {
1069 final File remote = myTempFiles.createTempDir();
1070 copyRepository(dataFile("repo_for_fetch.2.personal"), remote);
1071 VcsRootImpl root = createRoot(remote, "master");
1073 AgentRunningBuild build = createRunningBuild(map(PluginConfigImpl.USE_MIRRORS, String.valueOf(useMirrors)));
1074 String commitFromFeatureBranch = "d47dda159b27b9a8c4cee4ce98e4435eb5b17168";
1075 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, commitFromFeatureBranch, myCheckoutDir, build, false);
1076 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
1077 assertEquals("master", r.getBranch());
1079 build = createRunningBuild(map(PluginConfigImpl.USE_MIRRORS, String.valueOf(useMirrors),
1080 GitUtils.getGitRootBranchParamName(root), "refs/heads/personal"));
1081 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, commitFromFeatureBranch, myCheckoutDir, build, false);
1082 r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
1083 assertEquals("personal", r.getBranch());
1088 public void test_shallow_clone() throws Exception {
1089 AgentRunningBuild build = createRunningBuild(new HashMap<String, String>() {{
1090 put(PluginConfigImpl.USE_MIRRORS, "true");
1091 put(PluginConfigImpl.USE_SHALLOW_CLONE, "true");
1093 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitVcsSupportTest.VERSION_TEST_HEAD, myCheckoutDir, build, false);
1097 @TestFor(issues = "TW-27677")
1098 public void shallow_clone_in_non_master_branch() throws Exception {
1099 AgentRunningBuild build = createRunningBuild(new HashMap<String, String>() {{
1100 put(PluginConfigImpl.USE_MIRRORS, "true");
1101 put(PluginConfigImpl.USE_SHALLOW_CLONE, "true");
1102 put(GitUtils.getGitRootBranchParamName(myRoot), "refs/heads/version-test");//build on non-master branch
1104 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "2276eaf76a658f96b5cf3eb25f3e1fda90f6b653", myCheckoutDir, build, false);
1108 @TestFor(issues = "TW-37122")
1109 public void shallow_clone_on_tag() throws Exception {
1110 myRoot.addProperty(Constants.BRANCH_NAME, "refs/tags/v1.0");
1111 AgentRunningBuild build = createRunningBuild(new HashMap<String, String>() {{
1112 put(PluginConfigImpl.USE_MIRRORS, "true");
1113 put(PluginConfigImpl.USE_SHALLOW_CLONE, "true");
1115 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, build, false);
1119 @TestFor(issues = "TW-20165")
1120 public void push_with_local_mirrors_should_go_to_original_repository() throws Exception {
1121 AgentRunningBuild build = createRunningBuild(true);
1122 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, GitUtils.makeVersion("465ad9f630e451b9f2b782ffb09804c6a98c4bb9", 1289483394000L), myCheckoutDir, build, false);
1124 final File fileToChange = new File(myCheckoutDir, "file");
1125 FileUtil.writeToFile(fileToChange, "text".getBytes());
1127 Repository r = new RepositoryBuilder().setWorkTree(myCheckoutDir).build();
1128 Git git = new Git(r);
1129 git.add().addFilepattern("file").call();
1130 RevCommit commitDuringTheBuild = git.commit().setMessage("Commit during the build").call();
1131 new PushCommand().run(getGitPath(), myCheckoutDir.getAbsolutePath());//push using native git, seems like jgit doesn't respect url.insteadOf settings
1133 Repository remote = new RepositoryBuilder().setGitDir(myMainRepo).build();
1134 assertTrue("Push didn't go to the remote repository", remote.hasObject(commitDuringTheBuild));
1138 @TestFor(issues = "TW-28735")
1139 public void fetch_branch_with_same_name_but_different_register() throws Exception {
1140 AgentRunningBuild buildWithMirrorsEnabled = createRunningBuild(true);
1141 myRoot = vcsRoot().withBranch("refs/heads/master").withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).build();
1142 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, buildWithMirrorsEnabled, false);
1144 //rename master->Master
1145 Repository r = new RepositoryBuilder().setGitDir(myMainRepo).build();
1146 r.renameRef("refs/heads/master", "refs/heads/Master").rename();
1148 myRoot = vcsRoot().withBranch("refs/heads/Master").withAgentGitPath(getGitPath()).withFetchUrl(GitUtils.toURL(myMainRepo)).build();
1149 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, buildWithMirrorsEnabled, false);
1153 @TestFor(issues = "TW-46266")
1154 public void should_not_use_custom_clone_on_server() throws Exception {
1155 File serverCustomCloneDir = myTempFiles.createTempDir();
1156 VcsRootImpl root = vcsRoot()
1157 .withAgentGitPath(getGitPath())
1158 .withFetchUrl(GitUtils.toURL(myMainRepo))
1159 .withRepositoryPathOnServer(serverCustomCloneDir.getCanonicalPath())
1162 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, createRunningBuild(true), false);
1164 then(serverCustomCloneDir.listFiles()).isEmpty();
1168 @TestFor(issues = "TW-44844")
1169 @Test(dataProviderClass = BaseRemoteRepositoryTest.class, dataProvider = "true,false")
1170 public void handle_files_marked_as_unchanged(boolean switchBranch) throws Exception {
1172 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "97442a720324a0bd092fb9235f72246dc8b345bc", myCheckoutDir, myBuild, false);
1175 File f = new File(myCheckoutDir, "dir/a.txt");
1176 writeFileAndReportErrors(f, "update by build script");
1178 //git update-index --no-assume-unchanged <file>
1179 Process updateIndex = new ProcessBuilder().directory(myCheckoutDir).command(getGitPath(), "update-index", "--assume-unchanged", "dir/a.txt").start();
1180 updateIndex.waitFor();
1181 if (updateIndex.exitValue() != 0) {
1182 fail("git update-index failed, exit code " + updateIndex.exitValue() +
1183 "\nstdout: " + StreamUtil.readText(updateIndex.getInputStream()) +
1184 "\nstderr: " + StreamUtil.readText(updateIndex.getErrorStream()));
1187 //update to commit which changes the file
1189 myBuild = createRunningBuild(map(GitUtils.getGitRootBranchParamName(myRoot), "refs/heads/personal-branch1"));
1190 myVcsSupport.updateSources(myRoot, CheckoutRules.DEFAULT, "ad4528ed5c84092fdbe9e0502163cf8d6e6141e7", myCheckoutDir, myBuild, false);
1191 then(FileUtil.readFile(f)).doesNotContain("update by build script");
1195 @TestFor(issues = "TW-40313")
1196 public void should_remove_orphaned_indexes() throws Exception {
1198 VcsRootImpl root = vcsRoot()
1199 .withAgentGitPath(getGitPath())
1200 .withFetchUrl(GitUtils.toURL(myMainRepo))
1203 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, createRunningBuild(true), false);
1205 //create orphaned idx files
1206 File mirror = myBuilder.getMirrorManager().getMirrorDir(GitUtils.toURL(myMainRepo));
1207 File idxInMirror = new File(new File(new File(mirror, "objects"), "pack"), "whatever.idx");
1208 FileUtil.writeFileAndReportErrors(idxInMirror, "whatever");
1209 File idxInCheckoutDir = new File(new File(new File(mirror, "objects"), "pack"), "whatever.idx");
1210 FileUtil.writeFileAndReportErrors(idxInCheckoutDir, "whatever");
1213 myVcsSupport.updateSources(root, CheckoutRules.DEFAULT, "465ad9f630e451b9f2b782ffb09804c6a98c4bb9", myCheckoutDir, createRunningBuild(true), false);
1215 //orphaned idx files are removed
1216 then(idxInCheckoutDir).doesNotExist();
1217 then(idxInMirror).doesNotExist();
1221 private VcsRootImpl createRoot(final File remote, final String branch) throws IOException {
1223 return new VcsRootImpl(myVcsRootId, new HashMap<String, String>() {{
1224 put(VcsRootImpl.VCS_NAME_PROP, Constants.VCS_NAME);
1225 put(VcsRootImpl.VCS_ROOT_NAME_PROP, "test" + myVcsRootId);
1226 put(Constants.FETCH_URL, GitUtils.toURL(remote));
1227 put(Constants.AGENT_GIT_PATH, getGitPath());
1228 put(Constants.BRANCH_NAME, branch);
1233 private void testSubSubmoduleCheckout(boolean recursiveSubmoduleCheckout) throws Exception {
1234 myRoot.addProperty(Constants.BRANCH_NAME, "sub-submodule");
1235 if (recursiveSubmoduleCheckout) {
1236 myRoot.addProperty(Constants.SUBMODULES_CHECKOUT, SubmodulesCheckoutPolicy.CHECKOUT.name());
1238 myRoot.addProperty(Constants.SUBMODULES_CHECKOUT, SubmodulesCheckoutPolicy.NON_RECURSIVE_CHECKOUT.name());
1241 myVcsSupport.updateSources(myRoot, new CheckoutRules(""), GitVcsSupportTest.AFTER_FIRST_LEVEL_SUBMODULE_ADDED_VERSION,
1242 myCheckoutDir, myBuild, false);
1244 assertTrue(new File(myCheckoutDir, "first-level-submodule" + File.separator + "submoduleFile.txt").exists());
1245 if (recursiveSubmoduleCheckout) {
1246 assertTrue(new File (myCheckoutDir, "first-level-submodule" + File.separator + "sub-sub" + File.separator + "file.txt").exists());
1247 assertTrue(new File (myCheckoutDir, "first-level-submodule" + File.separator + "sub-sub" + File.separator + "new file.txt").exists());
1249 assertFalse(new File (myCheckoutDir, "first-level-submodule" + File.separator + "sub-sub" + File.separator + "file.txt").exists());
1250 assertFalse(new File (myCheckoutDir, "first-level-submodule" + File.separator + "sub-sub" + File.separator + "new file.txt").exists());
1255 private AgentRunningBuild createRunningBuild(boolean useLocalMirrors) {
1256 return runningBuild().useLocalMirrors(useLocalMirrors).build();
1260 private AgentRunningBuild createRunningBuild(final Map<String, String> sharedConfigParameters) {
1261 return runningBuild().sharedConfigParams(sharedConfigParameters).build();
1265 private void copyRepository(File src, File dst) throws IOException {
1267 new File(dst, "refs" + File.separator + "heads").mkdirs();
1271 private class PushCommand {
1272 void run(String gitPath, String workDirectory) throws Exception {
1273 File tmpDir = new File(FileUtil.getTempDirectory());
1274 GitCommandLine cmd = new GitCommandLine(null, SystemInfo.isUnix ? new UnixScriptGen(tmpDir, new EscapeEchoArgumentUnix())
1275 : new WinScriptGen(tmpDir, new EscapeEchoArgumentWin()),
1278 GitProgressLogger.NO_OP,
1280 new HashMap<String, String>(),
1281 new NoBuildContext());
1282 cmd.setExePath(gitPath);
1283 cmd.setWorkingDirectory(new File(workDirectory));
1284 cmd.addParameters("push", "origin", "master");
1285 CommandUtil.runCommand(cmd);