Add --path parameter to GetPatch

Adds path parameter to GetPatch.java for fetching a diff of a specific
file.

Also includes a unit test for the path parameter.

Feature: Issue 4669
Change-Id: Id211fff3b6d9ba6ae16835253f2d328ccf7b5020
This commit is contained in:
Kasper Nilsson
2016-10-17 15:04:33 -07:00
parent 247fa2388e
commit 81448072fb
6 changed files with 74 additions and 12 deletions

View File

@@ -3477,6 +3477,9 @@ Query parameter `download` (e.g. `/changes/.../patch?download`)
will suggest the browser save the patch as `commitsha1.diff.base64`,
for later processing by command line tools.
If the `path` parameter is set, the returned content is a diff of the single
file that the path refers to.
[[submit-preview]]
=== Submit Preview
--

View File

@@ -52,15 +52,7 @@ public class PushOneCommit {
public static final String SUBJECT = "test commit";
public static final String FILE_NAME = "a.txt";
public static final String FILE_CONTENT = "some content";
public static final String PATCH =
"From %s Mon Sep 17 00:00:00 2001\n" +
"From: Administrator <admin@example.com>\n" +
"Date: %s\n" +
"Subject: [PATCH] test commit\n" +
"\n" +
"Change-Id: %s\n" +
"---\n" +
"\n" +
public static final String PATCH_FILE_ONLY =
"diff --git a/a.txt b/a.txt\n" +
"new file mode 100644\n" +
"index 0000000..f0eec86\n" +
@@ -69,6 +61,15 @@ public class PushOneCommit {
"@@ -0,0 +1 @@\n" +
"+some content\n" +
"\\ No newline at end of file\n";
public static final String PATCH =
"From %s Mon Sep 17 00:00:00 2001\n" +
"From: Administrator <admin@example.com>\n" +
"Date: %s\n" +
"Subject: [PATCH] test commit\n" +
"\n" +
"Change-Id: %s\n" +
"---\n" +
"\n" + PATCH_FILE_ONLY;
public interface Factory {
PushOneCommit create(

View File

@@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.PushOneCommit.FILE_CONTENT;
import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
import static com.google.gerrit.acceptance.PushOneCommit.PATCH;
import static com.google.gerrit.acceptance.PushOneCommit.PATCH_FILE_ONLY;
import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
import static com.google.gerrit.reviewdb.client.Patch.COMMIT_MSG;
import static com.google.gerrit.reviewdb.client.Patch.MERGE_LIST;
@@ -58,6 +59,7 @@ import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ETagView;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
@@ -922,6 +924,24 @@ public class RevisionIT extends AbstractDaemonTest {
String.format(PATCH, r.getCommit().name(), date, r.getChangeId()));
}
@Test
public void patchWithPath() throws Exception {
PushOneCommit.Result r = createChange();
ChangeApi changeApi = gApi.changes()
.id(r.getChangeId());
BinaryResult bin = changeApi
.revision(r.getCommit().name())
.patch(FILE_NAME);
ByteArrayOutputStream os = new ByteArrayOutputStream();
bin.writeTo(os);
String res = new String(os.toByteArray(), UTF_8);
assertThat(res).isEqualTo(PATCH_FILE_ONLY);
exception.expect(ResourceNotFoundException.class);
exception.expectMessage("File not found: nonexistent-file.");
changeApi.revision(r.getCommit().name()).patch("nonexistent-file");
}
@Test
public void actions() throws Exception {
PushOneCommit.Result r = createChange();

View File

@@ -72,6 +72,7 @@ public interface RevisionApi {
* Returns patch of revision.
*/
BinaryResult patch() throws RestApiException;
BinaryResult patch(String path) throws RestApiException;
Map<String, ActionInfo> actions() throws RestApiException;
@@ -252,6 +253,11 @@ public interface RevisionApi {
throw new NotImplementedException();
}
@Override
public BinaryResult patch(String path) throws RestApiException {
throw new NotImplementedException();
}
@Override
public Map<String, ActionInfo> actions() throws RestApiException {
throw new NotImplementedException();

View File

@@ -462,6 +462,15 @@ class RevisionApiImpl implements RevisionApi {
}
}
@Override
public BinaryResult patch(String path) throws RestApiException {
try {
return getPatch.setPath(path).apply(revision);
} catch (IOException e) {
throw new RestApiException("Cannot get patch", e);
}
}
@Override
public Map<String, ActionInfo> actions() throws RestApiException {
return revisionActions.apply(revision).value();

View File

@@ -18,6 +18,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -30,6 +31,7 @@ import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.kohsuke.args4j.Option;
import java.io.IOException;
@@ -43,20 +45,25 @@ import java.util.zip.ZipOutputStream;
public class GetPatch implements RestReadView<RevisionResource> {
private final GitRepositoryManager repoManager;
private final String FILE_NOT_FOUND = "File not found: %s.";
@Option(name = "--zip")
private boolean zip;
@Option(name = "--download")
private boolean download;
@Option(name = "--path")
private String path;
@Inject
GetPatch(GitRepositoryManager repoManager) {
this.repoManager = repoManager;
}
@Override
public BinaryResult apply(RevisionResource rsrc)
throws ResourceConflictException, IOException {
public BinaryResult apply(RevisionResource rsrc) throws
ResourceConflictException, IOException, ResourceNotFoundException {
Project.NameKey project = rsrc.getControl().getProject().getNameKey();
final Repository repo = repoManager.openRepository(project);
boolean close = true;
@@ -93,9 +100,15 @@ public class GetPatch implements RestReadView<RevisionResource> {
}
private void format(OutputStream out) throws IOException {
out.write(formatEmailHeader(commit).getBytes(UTF_8));
// Only add header if no path is specified
if (path == null) {
out.write(formatEmailHeader(commit).getBytes(UTF_8));
}
try (DiffFormatter fmt = new DiffFormatter(out)) {
fmt.setRepository(repo);
if (path != null) {
fmt.setPathFilter(PathFilter.create(path));
}
fmt.format(base.getTree(), commit.getTree());
fmt.flush();
}
@@ -108,6 +121,11 @@ public class GetPatch implements RestReadView<RevisionResource> {
}
};
if (path != null && bin.asString().isEmpty()) {
throw new ResourceNotFoundException(
String.format(FILE_NOT_FOUND, path));
}
if (zip) {
bin.disableGzip()
.setContentType("application/zip")
@@ -134,6 +152,11 @@ public class GetPatch implements RestReadView<RevisionResource> {
}
}
public GetPatch setPath(String path) {
this.path = path;
return this;
}
private static String formatEmailHeader(RevCommit commit) {
StringBuilder b = new StringBuilder();
PersonIdent author = commit.getAuthorIdent();