From 257d70fc46ef192276a9512c7583dddbda7f6a03 Mon Sep 17 00:00:00 2001 From: Edwin Kempin Date: Thu, 28 Mar 2013 14:31:14 +0100 Subject: [PATCH] Support to get a revision as formatted git patch via REST Bug: issue 302 Change-Id: Iccdb5990683ad911259a79e977ec4c057078e4e1 Signed-off-by: Edwin Kempin --- Documentation/rest-api-changes.txt | 28 +++++ .../google/gerrit/server/change/GetPatch.java | 104 ++++++++++++++++++ .../google/gerrit/server/change/Module.java | 1 + 3 files changed, 133 insertions(+) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/change/GetPatch.java diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt index 09c7e115e0..b34af698fa 100644 --- a/Documentation/rest-api-changes.txt +++ b/Documentation/rest-api-changes.txt @@ -1268,6 +1268,34 @@ message is contained in the response body. "revision 674ac754f91e64a0efb8087e59a176484bd534d1 is not current revision" ---- +[[get-patch]] +Get Patch +~~~~~~~~~ +[verse] +'GET /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/patch' + +Gets the formatted patch for one revision. + +.Request +---- + GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/current/patch HTTP/1.0 +---- + +The formatted patch is returned as text wrapped in JSON. + +.Response +---- + HTTP/1.1 200 OK + Content-Disposition: attachment + Content-Type: application/json;charset=UTF-8 + + )]}' + "From 4cf8380e526b96de9a0ad50f745028fe416c4639 Tue, 02 Apr 2013 10:26:14 +0200\nFrom: John Doe \ + u003cjohn.doe@example.com\u003e\nDate: Thu, 28 Mar 2013 15:23:52 +0200\nSubject: [PATCH] Test Commit\n\n\n + diff--git a/a.txt b/a.txt\nindex bb0b141..e613f23 100644\n--- a/a.txt\n+++ b/a.txt\n@@ -1,5 +1,6 @@ + \n line1\n-line2\n line3\n line4\n+line4.1\n+line4.2\n line5\n" +---- + [[get-submit-type]] Get Submit Type ~~~~~~~~~~~~~~~ diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetPatch.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetPatch.java new file mode 100644 index 0000000000..2343cd1bbf --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetPatch.java @@ -0,0 +1,104 @@ +// Copyright (C) 2013 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.change; + +import static com.google.common.base.Charsets.UTF_8; + +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.GerritPersonIdent; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.inject.Inject; + +import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.lib.ObjectId; +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 java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Locale; + +public class GetPatch implements RestReadView { + private final GitRepositoryManager repoManager; + private final SimpleDateFormat df; + + @Inject + GetPatch(@GerritPersonIdent final PersonIdent gerritIdent, + GitRepositoryManager repoManager) { + this.repoManager = repoManager; + this.df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); + this.df.setCalendar(Calendar.getInstance(gerritIdent.getTimeZone(), Locale.US)); + } + + @Override + public String apply(RevisionResource rsrc) + throws ResourceNotFoundException, ResourceConflictException { + Project.NameKey project = rsrc.getControl().getProject().getNameKey(); + try { + Repository repo = repoManager.openRepository(project); + try { + RevWalk rw = new RevWalk(repo); + try { + RevCommit commit = + rw.parseCommit(ObjectId.fromString(rsrc.getPatchSet() + .getRevision().get())); + RevCommit[] parents = commit.getParents(); + if (parents.length > 1) { + throw new ResourceConflictException( + "Revision has more than 1 parent."); + } else if (parents.length == 0) { + throw new ResourceConflictException("Revision has no parent."); + } + rw.parseBody(parents[0]); + + StringBuilder b = new StringBuilder(); + appendHeader(b, commit); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + DiffFormatter f = new DiffFormatter(out); + f.setRepository(repo); + f.format(parents[0].getTree(), commit.getTree()); + f.flush(); + b.append(out.toString(UTF_8.name())); + return b.toString(); + } finally { + rw.release(); + } + } finally { + repo.close(); + } + } catch (IOException e) { + throw new ResourceNotFoundException(); + } + } + + private void appendHeader(StringBuilder b, RevCommit commit) { + PersonIdent author = commit.getAuthorIdent(); + b.append("From ").append(commit.getId().getName()).append(" ") + .append(df.format(Long.valueOf(System.currentTimeMillis()))).append("\n"); + b.append("From: ").append(author.getName()).append(" <").append(author.getEmailAddress()).append(">\n"); + b.append("Date: ").append(df.format(author.getWhen())).append("\n"); + b.append("Subject: [PATCH] ").append(commit.getShortMessage()); + String message = commit.getFullMessage().substring( + commit.getShortMessage().length()); + b.append(message).append("\n\n"); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java index 690faf3147..c061ec71a3 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java @@ -64,6 +64,7 @@ public class Module extends RestApiModule { post(REVISION_KIND, "review").to(PostReview.class); post(REVISION_KIND, "submit").to(Submit.class); get(REVISION_KIND, "submit_type").to(TestSubmitType.Get.class); + get(REVISION_KIND, "patch").to(GetPatch.class); post(REVISION_KIND, "test.submit_rule").to(TestSubmitRule.class); post(REVISION_KIND, "test.submit_type").to(TestSubmitType.class);