]> source.dussan.org Git - jgit.git/commitdiff
RepoCommand: Copy manifest upstream into .gitmodules ref field 29/1195529/2
authorIvan Frade <ifrade@google.com>
Thu, 30 May 2024 21:04:56 +0000 (14:04 -0700)
committerIvan Frade <ifrade@google.com>
Thu, 30 May 2024 21:18:08 +0000 (14:18 -0700)
Project entries in the manifest with a specific sha1 as revision can
use the "upstream" field to report the ref pointing to that sha1. This
information is very valuable for downstream tools, as they can limit
their search for a blob to the relevant ref, but it gets lost in the
translation to .gitmodules.

Save the value of the upstream field when available/relevant in the
ref field of the .gitmodules entry.

Change-Id: I14a2395925618d5e6b34be85466e32f5ef8fbf6e

org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/BareSuperprojectWriterTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java
org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java

index c3b93879b28d8c512dbb93cb52201bd059d83a52..5065b5784042170cd2cf839d75a38f5bced7a5a2 100644 (file)
@@ -12,6 +12,7 @@ package org.eclipse.jgit.gitrepo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -22,6 +23,7 @@ import java.util.List;
 import org.eclipse.jgit.gitrepo.BareSuperprojectWriter.BareWriterConfig;
 import org.eclipse.jgit.gitrepo.RepoCommand.RemoteReader;
 import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.Repository;
@@ -67,6 +69,49 @@ public class BareSuperprojectWriterTest extends RepositoryTestCase {
                }
        }
 
+       @Test
+       public void write_setGitModulesContents_pinned() throws Exception {
+               try (Repository bareRepo = createBareRepository()) {
+                       RepoProject pinWithUpstream = new RepoProject("pinWithUpstream",
+                                       "path/x", "cbc0fae7e1911d27e1de37d364698dba4411c78b",
+                                       "remote", "");
+                       pinWithUpstream.setUrl("http://example.com/a");
+                       pinWithUpstream.setUpstream("branchX");
+
+                       RepoProject pinWithoutUpstream = new RepoProject(
+                                       "pinWithoutUpstream", "path/y",
+                                       "cbc0fae7e1911d27e1de37d364698dba4411c78b", "remote", "");
+                       pinWithoutUpstream.setUrl("http://example.com/b");
+
+                       RemoteReader mockRemoteReader = mock(RemoteReader.class);
+
+                       BareSuperprojectWriter w = new BareSuperprojectWriter(bareRepo,
+                                       null, "refs/heads/master", author, mockRemoteReader,
+                                       BareWriterConfig.getDefault(), List.of());
+
+                       RevCommit commit = w
+                                       .write(Arrays.asList(pinWithUpstream, pinWithoutUpstream));
+
+                       String contents = readContents(bareRepo, commit, ".gitmodules");
+                       Config cfg = new Config();
+                       cfg.fromText(contents);
+
+                       assertThat(cfg.getString("submodule", "pinWithUpstream", "path"),
+                                       is("path/x"));
+                       assertThat(cfg.getString("submodule", "pinWithUpstream", "url"),
+                                       is("http://example.com/a"));
+                       assertThat(cfg.getString("submodule", "pinWithUpstream", "ref"),
+                                       is("branchX"));
+
+                       assertThat(cfg.getString("submodule", "pinWithoutUpstream", "path"),
+                                       is("path/y"));
+                       assertThat(cfg.getString("submodule", "pinWithoutUpstream", "url"),
+                                       is("http://example.com/b"));
+                       assertThat(cfg.getString("submodule", "pinWithoutUpstream", "ref"),
+                                       nullValue());
+               }
+       }
+
        @Test
        public void write_setExtraContents() throws Exception {
                try (Repository bareRepo = createBareRepository()) {
index ca6f2e10537f0ffeff21c9441ab0d894b17b47a4..3162e7910b2c1c4c1d123f4a3c8bf17ed1b7bc66 100644 (file)
@@ -1171,6 +1171,94 @@ public class RepoCommandTest extends RepositoryTestCase {
                }
        }
 
+       @Test
+       public void testRecordRemoteBranch_pinned() throws Exception {
+               Repository remoteDb = createBareRepository();
+               Repository tempDb = createWorkRepository();
+
+               StringBuilder xmlContent = new StringBuilder();
+               xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+                               .append("<manifest>")
+                               .append("<remote name=\"remote1\" fetch=\".\" />")
+                               .append("<default revision=\"master\" remote=\"remote1\" />")
+                               .append("<project path=\"pin-noupstream\"")
+                               .append("  name=\"pin-noupstream\"")
+                               .append("  revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />")
+                               .append("<project path=\"pin-upstream\"")
+                               .append("  name=\"pin-upstream\"")
+                               .append("  upstream=\"branchX\"")
+                               .append("  revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />")
+                               .append("</manifest>");
+               JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
+                               xmlContent.toString());
+
+               RepoCommand command = new RepoCommand(remoteDb);
+               command.setPath(
+                               tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
+                               .setURI(rootUri).setRecordRemoteBranch(true).call();
+               // Clone it
+               File directory = createTempDirectory("testBareRepo");
+               try (Repository localDb = Git.cloneRepository().setDirectory(directory)
+                               .setURI(remoteDb.getDirectory().toURI().toString()).call()
+                               .getRepository();) {
+                       // The .gitmodules file should exist
+                       File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
+                       assertTrue("The .gitmodules file should exist",
+                                       gitmodules.exists());
+                       FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED);
+                       c.load();
+                       assertEquals("Pinned submodule with upstream records the ref",
+                                       "branchX", c.getString("submodule", "pin-upstream", "ref"));
+                       assertNull("Pinned submodule without upstream don't have ref",
+                                       c.getString("submodule", "pin-noupstream", "ref"));
+               }
+       }
+
+       @Test
+       public void testRecordRemoteBranch_pinned_nameConflict() throws Exception {
+               Repository remoteDb = createBareRepository();
+               Repository tempDb = createWorkRepository();
+
+               StringBuilder xmlContent = new StringBuilder();
+               xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+                               .append("<manifest>")
+                               .append("<remote name=\"remote1\" fetch=\".\" />")
+                               .append("<default revision=\"master\" remote=\"remote1\" />")
+                               .append("<project path=\"pin-upstream\"")
+                               .append("  name=\"pin-upstream\"")
+                               .append("  upstream=\"branchX\"")
+                               .append("  revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />")
+                               .append("<project path=\"pin-upstream-name-conflict\"")
+                               .append("  name=\"pin-upstream\"")
+                               .append("  upstream=\"branchX\"")
+                               .append("  revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />")
+                               .append("</manifest>");
+               JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
+                               xmlContent.toString());
+
+               RepoCommand command = new RepoCommand(remoteDb);
+               command.setPath(
+                               tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
+                               .setURI(rootUri).setRecordRemoteBranch(true).call();
+               // Clone it
+               File directory = createTempDirectory("testBareRepo");
+               try (Repository localDb = Git.cloneRepository().setDirectory(directory)
+                               .setURI(remoteDb.getDirectory().toURI().toString()).call()
+                               .getRepository();) {
+                       // The .gitmodules file should exist
+                       File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
+                       assertTrue("The .gitmodules file should exist",
+                                       gitmodules.exists());
+                       FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED);
+                       c.load();
+                       assertEquals("Upstream is preserved in name conflict", "branchX",
+                                       c.getString("submodule", "pin-upstream/pin-upstream",
+                                                       "ref"));
+                       assertEquals("Upstream is preserved in name conflict (other side)",
+                                       "branchX", c.getString("submodule",
+                                                       "pin-upstream/pin-upstream-name-conflict", "ref"));
+               }
+       }
 
        @Test
        public void testRecordSubmoduleLabels() throws Exception {
index 3ce97a4ff71441bc6b458771752f34f34ee60651..d191e233992f2bf1d14ee39675ed3a981da43073 100644 (file)
@@ -156,6 +156,9 @@ class BareSuperprojectWriter {
                        ObjectId objectId;
                        if (ObjectId.isId(proj.getRevision())) {
                                objectId = ObjectId.fromString(proj.getRevision());
+                               if (config.recordRemoteBranch && proj.getUpstream() != null) {
+                                       cfg.setString("submodule", name, "ref", proj.getUpstream());
+                               }
                        } else {
                                objectId = callback.sha1(url, proj.getRevision());
                                if (objectId == null && !config.ignoreRemoteFailures) {
index 95c1c8b22ea82e3ee43487d9c1efb4c3da38d7cd..3aaef387f9fea7f925141c6c597e58cf6998845f 100644 (file)
@@ -615,6 +615,7 @@ public class RepoCommand extends GitCommand<RevCommit> {
                                p.setUrl(proj.getUrl());
                                p.addCopyFiles(proj.getCopyFiles());
                                p.addLinkFiles(proj.getLinkFiles());
+                               p.setUpstream(proj.getUpstream());
                                ret.add(p);
                        }
                }