/* * Copyright (C) 2011, GitHub Inc. and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at * https://www.eclipse.org/org/documents/edl-v10.php. * * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.submodule; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.util.Collection; import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.InitCommand; import org.eclipse.jgit.api.SubmoduleAddCommand; import org.eclipse.jgit.api.SubmoduleUpdateCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheEditor; import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.junit.Test; /** * Unit tests of {@link SubmoduleUpdateCommand} */ public class SubmoduleUpdateTest extends RepositoryTestCase { private Repository submoduleRepo; private Git git; private AnyObjectId subRepoCommit2; private void createSubmoduleRepo() throws IOException, GitAPIException { File directory = createTempDirectory("submodule_repo"); InitCommand init = Git.init(); init.setDirectory(directory); init.call(); submoduleRepo = Git.open(directory).getRepository(); try (Git sub = Git.wrap(submoduleRepo)) { // commit something JGitTestUtil.writeTrashFile(submoduleRepo, "commit1.txt", "commit 1"); sub.add().addFilepattern("commit1.txt").call(); sub.commit().setMessage("commit 1").call().getId(); JGitTestUtil.writeTrashFile(submoduleRepo, "commit2.txt", "commit 2"); sub.add().addFilepattern("commit2.txt").call(); subRepoCommit2 = sub.commit().setMessage("commit 2").call().getId(); } } private void addSubmodule(String path) throws GitAPIException { SubmoduleAddCommand command = new SubmoduleAddCommand(db); command.setPath(path); String uri = submoduleRepo.getDirectory().toURI().toString(); command.setURI(uri); try (Repository repo = command.call()) { assertNotNull(repo); } git.add().addFilepattern(path).addFilepattern(Constants.DOT_GIT_MODULES) .call(); git.commit().setMessage("adding submodule").call(); recursiveDelete(new File(git.getRepository().getWorkTree(), path)); recursiveDelete( new File(new File(git.getRepository().getCommonDirectory(), Constants.MODULES), path)); } @Override public void setUp() throws Exception { super.setUp(); createSubmoduleRepo(); git = Git.wrap(db); // commit something writeTrashFile("initial.txt", "initial"); git.add().addFilepattern("initial.txt").call(); git.commit().setMessage("initial commit").call(); } public void updateModeClonedRestoredSubmoduleTemplate(String mode) throws Exception { String path = "sub"; addSubmodule(path); StoredConfig cfg = git.getRepository().getConfig(); if (mode != null) { cfg.load(); cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_UPDATE, mode); cfg.save(); } SubmoduleUpdateCommand update = new SubmoduleUpdateCommand(db); update.call(); try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { update.call(); assertEquals(subRepoCommit2.getName(), subGit.getRepository().getBranch()); } recursiveDelete(new File(db.getWorkTree(), path)); update.call(); try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { update.call(); assertEquals(subRepoCommit2.getName(), subGit.getRepository().getBranch()); } } @Test public void repositoryWithNoSubmodules() throws GitAPIException { SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db); Collection modules = command.call(); assertNotNull(modules); assertTrue(modules.isEmpty()); } @Test public void repositoryWithSubmodule() throws Exception { final String path = "sub"; addSubmodule(path); SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db); Collection updated = command.call(); assertNotNull(updated); assertEquals(1, updated.size()); assertEquals(path, updated.iterator().next()); try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { assertTrue(generator.next()); try (Repository subRepo = generator.getRepository()) { assertNotNull(subRepo); assertEquals(subRepoCommit2, subRepo.resolve(Constants.HEAD)); String worktreeDir = subRepo.getConfig().getString( ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_WORKTREE); assertEquals("../../../sub", worktreeDir); String gitdir = read( new File(subRepo.getWorkTree(), Constants.DOT_GIT)); assertEquals("gitdir: ../.git/modules/sub", gitdir); } } } @Test public void repositoryWithUnconfiguredSubmodule() throws IOException, GitAPIException { final ObjectId id = ObjectId .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"); final String path = "sub"; DirCache cache = db.lockDirCache(); DirCacheEditor editor = cache.editor(); editor.add(new PathEdit(path) { @Override public void apply(DirCacheEntry ent) { ent.setFileMode(FileMode.GITLINK); ent.setObjectId(id); } }); editor.commit(); FileBasedConfig modulesConfig = new FileBasedConfig( new File(db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_PATH, path); String url = "git://server/repo.git"; modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_URL, url); modulesConfig.save(); SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db); Collection updated = command.call(); assertNotNull(updated); assertTrue(updated.isEmpty()); } @Test public void repositoryWithInitializedSubmodule() throws IOException, GitAPIException { final ObjectId id = ObjectId .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"); final String path = "sub"; DirCache cache = db.lockDirCache(); DirCacheEditor editor = cache.editor(); editor.add(new PathEdit(path) { @Override public void apply(DirCacheEntry ent) { ent.setFileMode(FileMode.GITLINK); ent.setObjectId(id); } }); editor.commit(); try (Repository subRepo = Git.init().setBare(false) .setDirectory(new File(db.getWorkTree(), path)).call() .getRepository()) { assertNotNull(subRepo); } SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db); Collection updated = command.call(); assertNotNull(updated); assertTrue(updated.isEmpty()); } @Test public void updateModeMergeClonedRestoredSubmodule() throws Exception { updateModeClonedRestoredSubmoduleTemplate( ConfigConstants.CONFIG_KEY_MERGE); } @Test public void updateModeRebaseClonedRestoredSubmodule() throws Exception { updateModeClonedRestoredSubmoduleTemplate( ConfigConstants.CONFIG_KEY_REBASE); } @Test public void updateModeCheckoutClonedRestoredSubmodule() throws Exception { updateModeClonedRestoredSubmoduleTemplate( ConfigConstants.CONFIG_KEY_CHECKOUT); } @Test public void updateModeMissingClonedRestoredSubmodule() throws Exception { updateModeClonedRestoredSubmoduleTemplate(null); } @Test public void updateMode() throws Exception { String path = "sub"; addSubmodule(path); StoredConfig cfg = git.getRepository().getConfig(); cfg.load(); cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_UPDATE, ConfigConstants.CONFIG_KEY_REBASE); cfg.save(); SubmoduleUpdateCommand update = new SubmoduleUpdateCommand(db); update.call(); try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { CheckoutCommand checkout = subGit.checkout(); checkout.setName("master"); checkout.call(); update.call(); assertEquals("master", subGit.getRepository().getBranch()); } cfg.load(); cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_UPDATE, ConfigConstants.CONFIG_KEY_CHECKOUT); cfg.save(); update.call(); try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { assertEquals(subRepoCommit2.getName(), subGit.getRepository().getBranch()); } cfg.load(); cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_UPDATE, ConfigConstants.CONFIG_KEY_MERGE); cfg.save(); update.call(); try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { CheckoutCommand checkout = subGit.checkout(); checkout.setName("master"); checkout.call(); update.call(); assertEquals("master", subGit.getRepository().getBranch()); } } }