RepoCommand: Offer to set extra files in the destination repository

We want to save in the destination repository what manifest created its
structure. This helps to detect and debug failures in the manifest ->
superproject translations. The src commit should be easily readable from
the superproject tip.

Offer an API to write a file in the destination repository. RepoCommand
callers (e.g. gerrit supermanifest plugin) can use this to add a
file with the repo/ref/hash of the manifest.

Alternatives considered to write the source repo/ref/hash:

  * .gitattributes of the .gitmodules file. Some updates in the manifest
    don't touch the .gitmodules (e.g. a linkfile change), so it can fall
    out of sync.

  * commit message. Caller would need to follow the commit history to
    find the latest modification by repo command. This is not helpful
    e.g. for build bots that want to get the value in one call.

Change-Id: I113662734a7ccd39cbc60b46ad3f73038c807682
This commit is contained in:
Ivan Frade 2021-11-23 14:42:01 -08:00
parent dee4240ce8
commit dba66dbfce
3 changed files with 72 additions and 4 deletions

View File

@ -50,7 +50,7 @@ public void write_setGitModulesContents() throws Exception {
BareSuperprojectWriter w = new BareSuperprojectWriter(bareRepo,
null, "refs/heads/master", author, mockRemoteReader,
BareWriterConfig.getDefault());
BareWriterConfig.getDefault(), List.of());
RevCommit commit = w.write(Arrays.asList(repoProject));
@ -66,6 +66,31 @@ public void write_setGitModulesContents() throws Exception {
}
}
@Test
public void write_setExtraContents() throws Exception {
try (Repository bareRepo = createBareRepository()) {
RepoProject repoProject = new RepoProject("subprojectX", "path/to",
"refs/heads/branch-x", "remote", "");
repoProject.setUrl("http://example.com/a");
RemoteReader mockRemoteReader = mock(RemoteReader.class);
when(mockRemoteReader.sha1("http://example.com/a",
"refs/heads/branch-x"))
.thenReturn(ObjectId.fromString(SHA1_A));
BareSuperprojectWriter w = new BareSuperprojectWriter(bareRepo,
null, "refs/heads/master", author, mockRemoteReader,
BareWriterConfig.getDefault(),
List.of(new BareSuperprojectWriter.ExtraContent("x",
"extra-content")));
RevCommit commit = w.write(Arrays.asList(repoProject));
String contents = readContents(bareRepo, commit, "x");
assertThat(contents, is("extra-content"));
}
}
private String readContents(Repository repo, RevCommit commit,
String path) throws Exception {
String idStr = commit.getId().name() + ":" + path;

View File

@ -71,6 +71,8 @@ class BareSuperprojectWriter {
private final PersonIdent author;
private List<ExtraContent> extraContents;
static class BareWriterConfig {
boolean ignoreRemoteFailures = false;
@ -88,10 +90,22 @@ private BareWriterConfig() {
}
}
static class ExtraContent {
final String path;
final String content;
ExtraContent(String path, String content) {
this.path = path;
this.content = content;
}
}
BareSuperprojectWriter(Repository repo, URI targetUri,
String targetBranch,
PersonIdent author, RemoteReader callback,
BareWriterConfig config) {
BareWriterConfig config,
List<ExtraContent> extraContents) {
assert (repo.isBare());
this.repo = repo;
this.targetUri = targetUri;
@ -99,6 +113,7 @@ private BareWriterConfig() {
this.author = author;
this.callback = callback;
this.config = config;
this.extraContents = extraContents;
}
RevCommit write(List<RepoProject> repoProjects)
@ -244,6 +259,16 @@ private void prepareIndex(List<RepoProject> projects, DirCache index,
builder.add(dcEntryAttr);
}
for (ExtraContent ec : extraContents) {
DirCacheEntry extraDcEntry = new DirCacheEntry(ec.path);
ObjectId oid = inserter.insert(Constants.OBJ_BLOB,
ec.content.getBytes(UTF_8));
extraDcEntry.setObjectId(oid);
extraDcEntry.setFileMode(FileMode.REGULAR_FILE);
builder.add(extraDcEntry);
}
builder.finish();
}

View File

@ -28,6 +28,7 @@
import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.gitrepo.BareSuperprojectWriter.ExtraContent;
import org.eclipse.jgit.gitrepo.ManifestParser.IncludedFileReader;
import org.eclipse.jgit.gitrepo.internal.RepoText;
import org.eclipse.jgit.internal.JGitText;
@ -79,6 +80,8 @@ public class RepoCommand extends GitCommand<RevCommit> {
private ProgressMonitor monitor;
private final List<ExtraContent> extraContents = new ArrayList<>();
/**
* A callback to get ref sha1 of a repository from its uri.
*
@ -509,6 +512,22 @@ public RepoCommand setIncludedFileReader(IncludedFileReader reader) {
return this;
}
/**
* Create a file with the given content in the destination repository
*
* @param path
* where to create the file in the destination repository
* @param contents
* content for the create file
* @return this command
*
* @since 6.1
*/
public RepoCommand addToDestination(String path, String contents) {
this.extraContents.add(new ExtraContent(path, contents));
return this;
}
/** {@inheritDoc} */
@Override
public RevCommit call() throws GitAPIException {
@ -550,7 +569,7 @@ public RevCommit call() throws GitAPIException {
targetBranch,
author == null ? new PersonIdent(repo) : author,
callback == null ? new DefaultRemoteReader() : callback,
bareWriterConfig);
bareWriterConfig, extraContents);
return writer.write(renamedProjects);
}
@ -663,5 +682,4 @@ static URI relativize(URI current, URI target) {
return URI.create(j.toString());
}
}