Merge lp:~cjwatson/launchpad/git-ref-remote-lp-non-production into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18814
Proposed branch: lp:~cjwatson/launchpad/git-ref-remote-lp-non-production
Merge into: lp:launchpad
Diff against target: 121 lines (+82/-6)
2 files modified
lib/lp/code/model/gitref.py (+37/-6)
lib/lp/code/model/tests/test_gitref.py (+45/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/git-ref-remote-lp-non-production
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+357827@code.launchpad.net

Commit message

Allow fetching blobs from repositories hosted on git.launchpad.net from non-production Launchpad instances.

Description of the change

This makes life easier when doing e.g. snap build QA on dogfood.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/model/gitref.py'
2--- lib/lp/code/model/gitref.py 2018-10-22 12:43:55 +0000
3+++ lib/lp/code/model/gitref.py 2018-10-25 15:18:55 +0000
4@@ -702,6 +702,25 @@
5 return response.content
6
7
8+def _fetch_blob_from_launchpad(repository_url, ref_path, filename):
9+ repo_path = urlsplit(repository_url).path.strip("/")
10+ try:
11+ response = urlfetch(
12+ "https://git.launchpad.net/%s/plain/%s" % (
13+ repo_path, quote(filename)),
14+ params={"h": ref_path})
15+ except requests.RequestException as e:
16+ if (e.response is not None and
17+ e.response.status_code == requests.codes.NOT_FOUND):
18+ raise GitRepositoryBlobNotFound(
19+ repository_url, filename, rev=ref_path)
20+ else:
21+ raise GitRepositoryScanFault(
22+ "Failed to get file from Git repository at %s: %s" %
23+ (repository_url, str(e)))
24+ return response.content
25+
26+
27 @implementer(IGitRef)
28 @provider(IGitRefRemoteSet)
29 class GitRefRemote(GitRefMixin):
30@@ -800,17 +819,29 @@
31 # dispatch a build job or a code import or something like that to do
32 # so. For now, we just special-case some providers where we know
33 # how to fetch a blob on its own.
34- repository = getUtility(IGitLookup).getByUrl(self.repository_url)
35- if repository is not None:
36- # This is one of our own repositories. Doing this by URL seems
37- # gratuitously complex, but apparently we already have some
38- # examples of this on production.
39- return repository.getBlob(filename, rev=self.path)
40 url = urlsplit(self.repository_url)
41 if (url.hostname == "github.com" and
42 len(url.path.strip("/").split("/")) == 2):
43 return _fetch_blob_from_github(
44 self.repository_url, self.path, filename)
45+ if (url.hostname == "git.launchpad.net" and
46+ config.vhost.mainsite.hostname != "launchpad.net"):
47+ # Even if this isn't launchpad.net, we can still retrieve files
48+ # from git.launchpad.net by URL, as a QA convenience. (We check
49+ # config.vhost.mainsite.hostname rather than
50+ # config.codehosting.git_*_root because the dogfood instance
51+ # points git_*_root to git.launchpad.net but doesn't share the
52+ # production database.)
53+ return _fetch_blob_from_launchpad(
54+ self.repository_url, self.path, filename)
55+ codehosting_host = urlsplit(config.codehosting.git_anon_root).hostname
56+ if url.hostname == codehosting_host:
57+ repository = getUtility(IGitLookup).getByUrl(self.repository_url)
58+ if repository is not None:
59+ # This is one of our own repositories. Doing this by URL
60+ # seems gratuitously complex, but apparently we already have
61+ # some examples of this on production.
62+ return repository.getBlob(filename, rev=self.path)
63 raise GitRepositoryBlobUnsupportedRemote(self.repository_url)
64
65 @property
66
67=== modified file 'lib/lp/code/model/tests/test_gitref.py'
68--- lib/lp/code/model/tests/test_gitref.py 2018-10-16 15:29:37 +0000
69+++ lib/lp/code/model/tests/test_gitref.py 2018-10-25 15:18:55 +0000
70@@ -344,6 +344,51 @@
71 self.assertEqual(expected_calls, hosting_fixture.getBlob.calls)
72
73 @responses.activate
74+ def test_remote_launchpad_production_branch(self):
75+ ref = self.factory.makeGitRefRemote(
76+ repository_url="https://git.launchpad.net/~owner/+git/name",
77+ path="refs/heads/path")
78+ responses.add(
79+ "GET",
80+ "https://git.launchpad.net/~owner/+git/name/plain/dir/file"
81+ "?h=refs%2Fheads%2Fpath",
82+ body=b"foo")
83+ self.assertEqual(b"foo", ref.getBlob("dir/file"))
84+
85+ @responses.activate
86+ def test_remote_launchpad_production_HEAD(self):
87+ ref = self.factory.makeGitRefRemote(
88+ repository_url="https://git.launchpad.net/~owner/+git/name",
89+ path="HEAD")
90+ responses.add(
91+ "GET",
92+ "https://git.launchpad.net/~owner/+git/name/plain/dir/file?h=HEAD",
93+ body=b"foo")
94+ self.assertEqual(b"foo", ref.getBlob("dir/file"))
95+
96+ @responses.activate
97+ def test_remote_launchpad_production_404(self):
98+ ref = self.factory.makeGitRefRemote(
99+ repository_url="https://git.launchpad.net/~owner/+git/name",
100+ path="HEAD")
101+ responses.add(
102+ "GET",
103+ "https://git.launchpad.net/~owner/+git/name/plain/dir/file?h=HEAD",
104+ status=404)
105+ self.assertRaises(GitRepositoryBlobNotFound, ref.getBlob, "dir/file")
106+
107+ @responses.activate
108+ def test_remote_launchpad_production_error(self):
109+ ref = self.factory.makeGitRefRemote(
110+ repository_url="https://git.launchpad.net/~owner/+git/name",
111+ path="HEAD")
112+ responses.add(
113+ "GET",
114+ "https://git.launchpad.net/~owner/+git/name/plain/dir/file?h=HEAD",
115+ status=500)
116+ self.assertRaises(GitRepositoryScanFault, ref.getBlob, "dir/file")
117+
118+ @responses.activate
119 def test_remote_github_branch(self):
120 ref = self.factory.makeGitRefRemote(
121 repository_url="https://github.com/owner/name",