Support reading gitlinks For the submodule migration, Chrome and skia autorollers need to read gitlinks without local checkouts. Provide that functionality through gitiles. Google-Bug-Id: b/261589090 Change-Id: I961278c80d482fae871521759d0f239d07ed2cda
diff --git a/java/com/google/gitiles/GitlinkJsonData.java b/java/com/google/gitiles/GitlinkJsonData.java new file mode 100644 index 0000000..00b1d0c --- /dev/null +++ b/java/com/google/gitiles/GitlinkJsonData.java
@@ -0,0 +1,36 @@ +// Copyright (C) 2023 Google LLC. All Rights Reserved. +// +// 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.gitiles; + +/** Submodule data to be returned to the client as JSON. */ +class GitlinkJsonData { + static class Gitlink { + String repo; + String url; + String revision; + String path; + } + + static Gitlink toJsonData(String repo, String url, String revision, String path) { + Gitlink gitlink = new Gitlink(); + gitlink.repo = repo; + gitlink.url = url; + gitlink.revision = revision; + gitlink.path = path; + return gitlink; + } + + private GitlinkJsonData() {} +}
diff --git a/java/com/google/gitiles/PathServlet.java b/java/com/google/gitiles/PathServlet.java index 4054332..9475ae7 100644 --- a/java/com/google/gitiles/PathServlet.java +++ b/java/com/google/gitiles/PathServlet.java
@@ -178,6 +178,8 @@ writeTreeText(req, res, wr); break; case GITLINK: + writeCommitText(req, res, wr); + break; default: throw new GitilesRequestFailureException(FailureReason.UNSUPPORTED_OBJECT_TYPE); } @@ -226,6 +228,16 @@ } } + private void writeCommitText(HttpServletRequest req, HttpServletResponse res, WalkResult wr) + throws IOException { + setTypeHeader(res, wr.type.mode.getObjectType()); + setModeHeader(res, wr.type); + try (Writer writer = startRenderText(req, res); + OutputStream out = BaseEncoding.base64().encodingStream(writer)) { + wr.tw.getObjectId(0).copyTo(out); + } + } + @Override protected void doGetJson(HttpServletRequest req, HttpServletResponse res) throws IOException { GitilesView view = ViewFilter.getView(req); @@ -263,8 +275,18 @@ TreeJsonData.toJsonData(wr.id, wr.tw, includeSizes, recursive), TreeJsonData.Tree.class); break; - case EXECUTABLE_FILE: case GITLINK: + renderJson( + req, + res, + GitlinkJsonData.toJsonData( + view.getRepositoryName(), + getGitlinkRemoteUrl(req, wr), + wr.tw.getObjectId(0).name(), + wr.path), + GitlinkJsonData.Gitlink.class); + break; + case EXECUTABLE_FILE: case SYMLINK: default: throw new GitilesRequestFailureException(FailureReason.UNSUPPORTED_OBJECT_TYPE); @@ -589,6 +611,29 @@ private void showGitlink(HttpServletRequest req, HttpServletResponse res, WalkResult wr) throws IOException { + String remoteUrl = getGitlinkRemoteUrl(req, wr); + Map<String, Object> data = Maps.newHashMap(); + data.put("sha", ObjectId.toString(wr.id)); + data.put("remoteUrl", remoteUrl); + + // TODO(dborowitz): Guess when we can put commit SHAs in the URL. + String httpUrl = resolveHttpUrl(remoteUrl); + if (httpUrl != null) { + data.put("httpUrl", httpUrl); + } + + // TODO(sop): Allow caching links by SHA-1 when no S cookie is sent. + renderHtml( + req, + res, + PATH_DETAIL, + ImmutableMap.of( + "title", ViewFilter.getView(req).getPathPart(), + "type", FileType.GITLINK.toString(), + "data", data)); + } + + private String getGitlinkRemoteUrl(HttpServletRequest req, WalkResult wr) throws IOException { GitilesView view = ViewFilter.getView(req); String modulesUrl; String remoteUrl = null; @@ -607,26 +652,7 @@ } catch (ConfigInvalidException e) { throw new IOException(e); } - - Map<String, Object> data = Maps.newHashMap(); - data.put("sha", ObjectId.toString(wr.id)); - data.put("remoteUrl", remoteUrl != null ? remoteUrl : modulesUrl); - - // TODO(dborowitz): Guess when we can put commit SHAs in the URL. - String httpUrl = resolveHttpUrl(remoteUrl); - if (httpUrl != null) { - data.put("httpUrl", httpUrl); - } - - // TODO(sop): Allow caching links by SHA-1 when no S cookie is sent. - renderHtml( - req, - res, - PATH_DETAIL, - ImmutableMap.of( - "title", view.getPathPart(), - "type", FileType.GITLINK.toString(), - "data", data)); + return remoteUrl != null ? remoteUrl : modulesUrl; } private static String resolveHttpUrl(String remoteUrl) {
diff --git a/javatests/com/google/gitiles/PathServletTest.java b/javatests/com/google/gitiles/PathServletTest.java index 68b1e3e..ad9d43e 100644 --- a/javatests/com/google/gitiles/PathServletTest.java +++ b/javatests/com/google/gitiles/PathServletTest.java
@@ -21,6 +21,7 @@ import com.google.common.io.BaseEncoding; import com.google.common.net.HttpHeaders; import com.google.gitiles.FileJsonData.File; +import com.google.gitiles.GitlinkJsonData.Gitlink; import com.google.gitiles.TreeJsonData.Tree; import com.google.template.soy.data.SoyListData; import com.google.template.soy.data.restricted.StringData; @@ -248,7 +249,7 @@ } @Test - public void nonBlobText() throws Exception { + public void commitText() throws Exception { String gitmodules = "[submodule \"gitiles\"]\n" + " path = gitiles\n" @@ -268,8 +269,12 @@ }) .create(); + assertThat(buildBlob("/repo/+/master/gitiles", "160000")).isEqualTo(gitilesSha); + } + + @Test + public void notFoundText() throws Exception { assertNotFound("/repo/+/master/nonexistent", "format=text"); - assertNotFound("/repo/+/master/gitiles", "format=text"); } @Test @@ -383,6 +388,34 @@ } @Test + public void commitJson() throws Exception { + String gitmodules = + "[submodule \"gitiles\"]\n" + + " path = gitiles\n" + + " url = https://gerrit.googlesource.com/gitiles\n"; + final String gitilesSha = "2b2f34bba3c2be7e2506ce6b1f040949da350cf9"; + repo.branch("master") + .commit() + .add("foo/bar", "contents") + .add(".gitmodules", gitmodules) + .edit( + new PathEdit("gitiles") { + @Override + public void apply(DirCacheEntry ent) { + ent.setFileMode(FileMode.GITLINK); + ent.setObjectId(ObjectId.fromString(gitilesSha)); + } + }) + .create(); + + Gitlink commit = buildJson(Gitlink.class, "/repo/+/master/gitiles"); + assertThat(commit.repo).isEqualTo("repo"); + assertThat(commit.url).isEqualTo("https://gerrit.googlesource.com/gitiles"); + assertThat(commit.revision).isEqualTo(gitilesSha); + assertThat(commit.path).isEqualTo("gitiles"); + } + + @Test public void allowOrigin() throws Exception { repo.branch("master").commit().add("foo", "contents").create(); FakeHttpServletResponse res = buildText("/repo/+/master/foo");