Merge ~cjwatson/launchpad:artifactory-pypi into launchpad:master
- Git
- lp:~cjwatson/launchpad
- artifactory-pypi
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | de9a1370945f3348ad8762721a898aa1f925d76a |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:artifactory-pypi |
Merge into: | launchpad:master |
Prerequisite: | ~cjwatson/launchpad:diskpool-add-source-version |
Diff against target: |
659 lines (+284/-57) 5 files modified
lib/lp/archivepublisher/artifactory.py (+21/-7) lib/lp/archivepublisher/config.py (+7/-2) lib/lp/archivepublisher/tests/test_artifactory.py (+207/-47) lib/lp/archivepublisher/tests/test_config.py (+37/-1) lib/lp/registry/interfaces/sourcepackage.py (+12/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jürgen Gmach | Approve | ||
Review via email: mp+423563@code.launchpad.net |
Commit message
Handle path changes to publish Python packages via Artifactory
Description of the change
Unlike .debs, Python packages (sdists and wheels) are published in <name>/<version>/ subdirectories.
To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) : | # |
review:
Approve
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/archivepublisher/artifactory.py b/lib/lp/archivepublisher/artifactory.py |
2 | index 53b43a6..5ce6460 100644 |
3 | --- a/lib/lp/archivepublisher/artifactory.py |
4 | +++ b/lib/lp/archivepublisher/artifactory.py |
5 | @@ -41,6 +41,21 @@ from lp.soyuz.interfaces.publishing import ( |
6 | ) |
7 | |
8 | |
9 | +def _path_for(archive: IArchive, rootpath: ArtifactoryPath, source_name: str, |
10 | + source_version: str, filename: Optional[str] = None) -> Path: |
11 | + repository_format = archive.repository_format |
12 | + if repository_format == ArchiveRepositoryFormat.DEBIAN: |
13 | + path = rootpath / poolify(source_name) |
14 | + elif repository_format == ArchiveRepositoryFormat.PYTHON: |
15 | + path = rootpath / source_name / source_version |
16 | + else: |
17 | + raise AssertionError( |
18 | + "Unsupported repository format: %r" % repository_format) |
19 | + if filename: |
20 | + path = path / filename |
21 | + return path |
22 | + |
23 | + |
24 | class ArtifactoryPoolEntry: |
25 | |
26 | def __init__(self, archive: IArchive, rootpath: ArtifactoryPath, |
27 | @@ -63,7 +78,9 @@ class ArtifactoryPoolEntry: |
28 | # the pool structure, and doing so would introduce significant |
29 | # complications in terms of having to keep track of components just |
30 | # in order to update an artifact's properties. |
31 | - return self.rootpath / poolify(self.source_name) / self.filename |
32 | + return _path_for( |
33 | + self.archive, self.rootpath, self.source_name, self.source_version, |
34 | + self.filename) |
35 | |
36 | def makeReleaseID(self, pub_file: IPackageReleaseFile) -> str: |
37 | """ |
38 | @@ -156,8 +173,7 @@ class ArtifactoryPoolEntry: |
39 | else: |
40 | properties["launchpad.channel"] = sorted({ |
41 | "%s:%s" % ( |
42 | - pub.distroseries.getSuite(pub.pocket), |
43 | - pub.channel_string) |
44 | + pub.distroseries.getSuite(pub.pocket), pub.channel) |
45 | for pub in publications}) |
46 | return properties |
47 | |
48 | @@ -285,10 +301,8 @@ class ArtifactoryPool: |
49 | # the pool structure, and doing so would introduce significant |
50 | # complications in terms of having to keep track of components just |
51 | # in order to update an artifact's properties. |
52 | - path = self.rootpath / poolify(source_name) |
53 | - if file: |
54 | - path = path / file |
55 | - return path |
56 | + return _path_for( |
57 | + self.archive, self.rootpath, source_name, source_version, file) |
58 | |
59 | def addFile(self, component: str, source_name: str, source_version: str, |
60 | filename: str, pub_file: IPackageReleaseFile): |
61 | diff --git a/lib/lp/archivepublisher/config.py b/lib/lp/archivepublisher/config.py |
62 | index 55603dc..06ae2a7 100644 |
63 | --- a/lib/lp/archivepublisher/config.py |
64 | +++ b/lib/lp/archivepublisher/config.py |
65 | @@ -20,6 +20,7 @@ from lp.soyuz.enums import ( |
66 | archive_suffixes, |
67 | ArchivePublishingMethod, |
68 | ArchivePurpose, |
69 | + ArchiveRepositoryFormat, |
70 | ) |
71 | |
72 | |
73 | @@ -111,8 +112,12 @@ def getPubConfig(archive): |
74 | pubconf.signingroot = None |
75 | pubconf.signingautokey = False |
76 | |
77 | - pubconf.poolroot = os.path.join(pubconf.archiveroot, 'pool') |
78 | - pubconf.distsroot = os.path.join(pubconf.archiveroot, 'dists') |
79 | + if archive.repository_format == ArchiveRepositoryFormat.DEBIAN: |
80 | + pubconf.poolroot = os.path.join(pubconf.archiveroot, 'pool') |
81 | + pubconf.distsroot = os.path.join(pubconf.archiveroot, 'dists') |
82 | + else: |
83 | + pubconf.poolroot = pubconf.archiveroot |
84 | + pubconf.distsroot = None |
85 | |
86 | # META_DATA custom uploads are stored in a separate directory |
87 | # outside the archive root so Ubuntu Software Center can get some |
88 | diff --git a/lib/lp/archivepublisher/tests/test_artifactory.py b/lib/lp/archivepublisher/tests/test_artifactory.py |
89 | index 241f277..8f3e7b1 100644 |
90 | --- a/lib/lp/archivepublisher/tests/test_artifactory.py |
91 | +++ b/lib/lp/archivepublisher/tests/test_artifactory.py |
92 | @@ -5,6 +5,7 @@ |
93 | |
94 | from pathlib import PurePath |
95 | |
96 | +from artifactory import ArtifactoryPath |
97 | import transaction |
98 | from zope.component import getUtility |
99 | |
100 | @@ -18,12 +19,16 @@ from lp.archivepublisher.tests.test_pool import ( |
101 | PoolTestingFile, |
102 | ) |
103 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
104 | -from lp.registry.interfaces.sourcepackage import SourcePackageFileType |
105 | +from lp.registry.interfaces.sourcepackage import ( |
106 | + SourcePackageFileType, |
107 | + SourcePackageType, |
108 | + ) |
109 | from lp.services.log.logger import BufferLogger |
110 | from lp.soyuz.enums import ( |
111 | ArchivePurpose, |
112 | ArchiveRepositoryFormat, |
113 | BinaryPackageFileType, |
114 | + BinaryPackageFormat, |
115 | ) |
116 | from lp.soyuz.interfaces.publishing import ( |
117 | IPublishingSet, |
118 | @@ -77,17 +82,54 @@ class TestArtifactoryPool(TestCase): |
119 | self.repository_name = "repository" |
120 | self.artifactory = self.useFixture( |
121 | FakeArtifactoryFixture(self.base_url, self.repository_name)) |
122 | - root_url = "%s/%s/pool" % (self.base_url, self.repository_name) |
123 | - self.pool = ArtifactoryPool(FakeArchive(), root_url, BufferLogger()) |
124 | + |
125 | + def makePool(self, repository_format=ArchiveRepositoryFormat.DEBIAN): |
126 | + # Matches behaviour of lp.archivepublisher.config.getPubConfig. |
127 | + root_url = "%s/%s" % (self.base_url, self.repository_name) |
128 | + if repository_format == ArchiveRepositoryFormat.DEBIAN: |
129 | + root_url += "/pool" |
130 | + return ArtifactoryPool( |
131 | + FakeArchive(repository_format), root_url, BufferLogger()) |
132 | + |
133 | + def test_pathFor_debian_without_file(self): |
134 | + pool = self.makePool() |
135 | + self.assertEqual( |
136 | + ArtifactoryPath( |
137 | + "https://foo.example.com/artifactory/repository/pool/f/foo"), |
138 | + pool.pathFor(None, "foo", "1.0")) |
139 | + |
140 | + def test_pathFor_debian_with_file(self): |
141 | + pool = self.makePool() |
142 | + self.assertEqual( |
143 | + ArtifactoryPath( |
144 | + "https://foo.example.com/artifactory/repository/pool/f/foo/" |
145 | + "foo-1.0.deb"), |
146 | + pool.pathFor(None, "foo", "1.0", "foo-1.0.deb")) |
147 | + |
148 | + def test_pathFor_python_without_file(self): |
149 | + pool = self.makePool(ArchiveRepositoryFormat.PYTHON) |
150 | + self.assertEqual( |
151 | + ArtifactoryPath( |
152 | + "https://foo.example.com/artifactory/repository/foo/1.0"), |
153 | + pool.pathFor(None, "foo", "1.0")) |
154 | + |
155 | + def test_pathFor_python_with_file(self): |
156 | + pool = self.makePool(ArchiveRepositoryFormat.PYTHON) |
157 | + self.assertEqual( |
158 | + ArtifactoryPath( |
159 | + "https://foo.example.com/artifactory/repository/foo/1.0/" |
160 | + "foo-1.0.whl"), |
161 | + pool.pathFor(None, "foo", "1.0", "foo-1.0.whl")) |
162 | |
163 | def test_addFile(self): |
164 | + pool = self.makePool() |
165 | foo = ArtifactoryPoolTestingFile( |
166 | - pool=self.pool, source_name="foo", source_version="1.0", |
167 | + pool=pool, source_name="foo", source_version="1.0", |
168 | filename="foo-1.0.deb", release_type=FakeReleaseType.BINARY, |
169 | release_id=1) |
170 | self.assertFalse(foo.checkIsFile()) |
171 | result = foo.addToPool() |
172 | - self.assertEqual(self.pool.results.FILE_ADDED, result) |
173 | + self.assertEqual(pool.results.FILE_ADDED, result) |
174 | self.assertTrue(foo.checkIsFile()) |
175 | self.assertEqual( |
176 | { |
177 | @@ -98,19 +140,21 @@ class TestArtifactoryPool(TestCase): |
178 | foo.getProperties()) |
179 | |
180 | def test_addFile_exists_identical(self): |
181 | + pool = self.makePool() |
182 | foo = ArtifactoryPoolTestingFile( |
183 | - pool=self.pool, source_name="foo", source_version="1.0", |
184 | + pool=pool, source_name="foo", source_version="1.0", |
185 | filename="foo-1.0.deb", release_type=FakeReleaseType.BINARY, |
186 | release_id=1) |
187 | foo.addToPool() |
188 | self.assertTrue(foo.checkIsFile()) |
189 | result = foo.addToPool() |
190 | - self.assertEqual(self.pool.results.NONE, result) |
191 | + self.assertEqual(pool.results.NONE, result) |
192 | self.assertTrue(foo.checkIsFile()) |
193 | |
194 | def test_addFile_exists_overwrite(self): |
195 | + pool = self.makePool() |
196 | foo = ArtifactoryPoolTestingFile( |
197 | - pool=self.pool, source_name="foo", source_version="1.0", |
198 | + pool=pool, source_name="foo", source_version="1.0", |
199 | filename="foo-1.0.deb", release_type=FakeReleaseType.BINARY, |
200 | release_id=1) |
201 | foo.addToPool() |
202 | @@ -119,8 +163,9 @@ class TestArtifactoryPool(TestCase): |
203 | self.assertRaises(PoolFileOverwriteError, foo.addToPool) |
204 | |
205 | def test_removeFile(self): |
206 | + pool = self.makePool() |
207 | foo = ArtifactoryPoolTestingFile( |
208 | - pool=self.pool, source_name="foo", source_version="1.0", |
209 | + pool=pool, source_name="foo", source_version="1.0", |
210 | filename="foo-1.0.deb") |
211 | foo.addToPool() |
212 | self.assertTrue(foo.checkIsFile()) |
213 | @@ -129,6 +174,7 @@ class TestArtifactoryPool(TestCase): |
214 | self.assertEqual(3, size) |
215 | |
216 | def test_getArtifactPatterns_debian(self): |
217 | + pool = self.makePool() |
218 | self.assertEqual( |
219 | [ |
220 | "*.ddeb", |
221 | @@ -138,12 +184,13 @@ class TestArtifactoryPool(TestCase): |
222 | "*.tar.*", |
223 | "*.udeb", |
224 | ], |
225 | - self.pool.getArtifactPatterns(ArchiveRepositoryFormat.DEBIAN)) |
226 | + pool.getArtifactPatterns(ArchiveRepositoryFormat.DEBIAN)) |
227 | |
228 | def test_getArtifactPatterns_python(self): |
229 | + pool = self.makePool() |
230 | self.assertEqual( |
231 | ["*.whl"], |
232 | - self.pool.getArtifactPatterns(ArchiveRepositoryFormat.PYTHON)) |
233 | + pool.getArtifactPatterns(ArchiveRepositoryFormat.PYTHON)) |
234 | |
235 | def test_getAllArtifacts(self): |
236 | # getAllArtifacts mostly relies on constructing a correct AQL query, |
237 | @@ -151,16 +198,17 @@ class TestArtifactoryPool(TestCase): |
238 | # instance, although `FakeArtifactoryFixture` tries to do something |
239 | # with it. This test mainly ensures that we transform the response |
240 | # correctly. |
241 | + pool = self.makePool() |
242 | ArtifactoryPoolTestingFile( |
243 | - pool=self.pool, source_name="foo", source_version="1.0", |
244 | + pool=pool, source_name="foo", source_version="1.0", |
245 | filename="foo-1.0.deb", release_type=FakeReleaseType.BINARY, |
246 | release_id=1).addToPool() |
247 | ArtifactoryPoolTestingFile( |
248 | - pool=self.pool, source_name="foo", source_version="1.1", |
249 | + pool=pool, source_name="foo", source_version="1.1", |
250 | filename="foo-1.1.deb", release_type=FakeReleaseType.BINARY, |
251 | release_id=2).addToPool() |
252 | ArtifactoryPoolTestingFile( |
253 | - pool=self.pool, source_name="bar", source_version="1.0", |
254 | + pool=pool, source_name="bar", source_version="1.0", |
255 | filename="bar-1.0.whl", release_type=FakeReleaseType.BINARY, |
256 | release_id=3).addToPool() |
257 | self.assertEqual( |
258 | @@ -176,7 +224,7 @@ class TestArtifactoryPool(TestCase): |
259 | "launchpad.source-version": ["1.1"], |
260 | }, |
261 | }, |
262 | - self.pool.getAllArtifacts( |
263 | + pool.getAllArtifacts( |
264 | self.repository_name, ArchiveRepositoryFormat.DEBIAN)) |
265 | self.assertEqual( |
266 | { |
267 | @@ -186,7 +234,7 @@ class TestArtifactoryPool(TestCase): |
268 | "launchpad.source-version": ["1.0"], |
269 | }, |
270 | }, |
271 | - self.pool.getAllArtifacts( |
272 | + pool.getAllArtifacts( |
273 | self.repository_name, ArchiveRepositoryFormat.PYTHON)) |
274 | |
275 | |
276 | @@ -200,17 +248,24 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
277 | self.repository_name = "repository" |
278 | self.artifactory = self.useFixture( |
279 | FakeArtifactoryFixture(self.base_url, self.repository_name)) |
280 | - root_url = "%s/%s/pool" % (self.base_url, self.repository_name) |
281 | - self.archive = self.factory.makeArchive(purpose=ArchivePurpose.PPA) |
282 | - self.pool = ArtifactoryPool(self.archive, root_url, BufferLogger()) |
283 | + |
284 | + def makePool(self, repository_format=ArchiveRepositoryFormat.DEBIAN): |
285 | + # Matches behaviour of lp.archivepublisher.config.getPubConfig. |
286 | + root_url = "%s/%s" % (self.base_url, self.repository_name) |
287 | + if repository_format == ArchiveRepositoryFormat.DEBIAN: |
288 | + root_url += "/pool" |
289 | + archive = self.factory.makeArchive( |
290 | + purpose=ArchivePurpose.PPA, repository_format=repository_format) |
291 | + return ArtifactoryPool(archive, root_url, BufferLogger()) |
292 | |
293 | def test_updateProperties_debian_source(self): |
294 | + pool = self.makePool() |
295 | dses = [ |
296 | self.factory.makeDistroSeries( |
297 | - distribution=self.archive.distribution) |
298 | + distribution=pool.archive.distribution) |
299 | for _ in range(2)] |
300 | spph = self.factory.makeSourcePackagePublishingHistory( |
301 | - archive=self.archive, distroseries=dses[0], |
302 | + archive=pool.archive, distroseries=dses[0], |
303 | pocket=PackagePublishingPocket.RELEASE, component="main", |
304 | sourcepackagename="foo", version="1.0") |
305 | spr = spph.sourcepackagerelease |
306 | @@ -221,11 +276,11 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
307 | filetype=SourcePackageFileType.DSC) |
308 | spphs = [spph] |
309 | spphs.append(spph.copyTo( |
310 | - dses[1], PackagePublishingPocket.RELEASE, self.archive)) |
311 | + dses[1], PackagePublishingPocket.RELEASE, pool.archive)) |
312 | transaction.commit() |
313 | - self.pool.addFile( |
314 | + pool.addFile( |
315 | None, spr.name, spr.version, sprf.libraryfile.filename, sprf) |
316 | - path = self.pool.rootpath / "f" / "foo" / "foo_1.0.dsc" |
317 | + path = pool.rootpath / "f" / "foo" / "foo_1.0.dsc" |
318 | self.assertTrue(path.exists()) |
319 | self.assertFalse(path.is_symlink()) |
320 | self.assertEqual( |
321 | @@ -235,7 +290,7 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
322 | "launchpad.source-version": ["1.0"], |
323 | }, |
324 | path.properties) |
325 | - self.pool.updateProperties( |
326 | + pool.updateProperties( |
327 | spr.name, spr.version, sprf.libraryfile.filename, spphs) |
328 | self.assertEqual( |
329 | { |
330 | @@ -248,9 +303,10 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
331 | path.properties) |
332 | |
333 | def test_updateProperties_debian_binary_multiple_series(self): |
334 | + pool = self.makePool() |
335 | dses = [ |
336 | self.factory.makeDistroSeries( |
337 | - distribution=self.archive.distribution) |
338 | + distribution=pool.archive.distribution) |
339 | for _ in range(2)] |
340 | processor = self.factory.makeProcessor() |
341 | dases = [ |
342 | @@ -258,9 +314,9 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
343 | distroseries=ds, architecturetag=processor.name) |
344 | for ds in dses] |
345 | spr = self.factory.makeSourcePackageRelease( |
346 | - archive=self.archive, sourcepackagename="foo", version="1.0") |
347 | + archive=pool.archive, sourcepackagename="foo", version="1.0") |
348 | bpph = self.factory.makeBinaryPackagePublishingHistory( |
349 | - archive=self.archive, distroarchseries=dases[0], |
350 | + archive=pool.archive, distroarchseries=dases[0], |
351 | pocket=PackagePublishingPocket.RELEASE, component="main", |
352 | source_package_release=spr, binarypackagename="foo", |
353 | architecturespecific=True) |
354 | @@ -272,14 +328,13 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
355 | filetype=BinaryPackageFileType.DEB) |
356 | bpphs = [bpph] |
357 | bpphs.append(bpph.copyTo( |
358 | - dses[1], PackagePublishingPocket.RELEASE, self.archive)[0]) |
359 | + dses[1], PackagePublishingPocket.RELEASE, pool.archive)[0]) |
360 | transaction.commit() |
361 | - self.pool.addFile( |
362 | + pool.addFile( |
363 | None, bpr.sourcepackagename, bpr.sourcepackageversion, |
364 | bpf.libraryfile.filename, bpf) |
365 | path = ( |
366 | - self.pool.rootpath / "f" / "foo" / |
367 | - ("foo_1.0_%s.deb" % processor.name)) |
368 | + pool.rootpath / "f" / "foo" / ("foo_1.0_%s.deb" % processor.name)) |
369 | self.assertTrue(path.exists()) |
370 | self.assertFalse(path.is_symlink()) |
371 | self.assertEqual( |
372 | @@ -289,7 +344,7 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
373 | "launchpad.source-version": ["1.0"], |
374 | }, |
375 | path.properties) |
376 | - self.pool.updateProperties( |
377 | + pool.updateProperties( |
378 | bpr.sourcepackagename, bpr.sourcepackageversion, |
379 | bpf.libraryfile.filename, bpphs) |
380 | self.assertEqual( |
381 | @@ -304,15 +359,16 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
382 | path.properties) |
383 | |
384 | def test_updateProperties_debian_binary_multiple_architectures(self): |
385 | + pool = self.makePool() |
386 | ds = self.factory.makeDistroSeries( |
387 | - distribution=self.archive.distribution) |
388 | + distribution=pool.archive.distribution) |
389 | dases = [ |
390 | self.factory.makeDistroArchSeries(distroseries=ds) |
391 | for _ in range(2)] |
392 | spr = self.factory.makeSourcePackageRelease( |
393 | - archive=self.archive, sourcepackagename="foo", version="1.0") |
394 | + archive=pool.archive, sourcepackagename="foo", version="1.0") |
395 | bpb = self.factory.makeBinaryPackageBuild( |
396 | - archive=self.archive, source_package_release=spr, |
397 | + archive=pool.archive, source_package_release=spr, |
398 | distroarchseries=dases[0], pocket=PackagePublishingPocket.RELEASE) |
399 | bpr = self.factory.makeBinaryPackageRelease( |
400 | binarypackagename="foo", build=bpb, component="main", |
401 | @@ -323,13 +379,13 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
402 | filename="foo_1.0_all.deb"), |
403 | filetype=BinaryPackageFileType.DEB) |
404 | bpphs = getUtility(IPublishingSet).publishBinaries( |
405 | - self.archive, ds, PackagePublishingPocket.RELEASE, |
406 | + pool.archive, ds, PackagePublishingPocket.RELEASE, |
407 | {bpr: (bpr.component, bpr.section, bpr.priority, None)}) |
408 | transaction.commit() |
409 | - self.pool.addFile( |
410 | + pool.addFile( |
411 | None, bpr.sourcepackagename, bpr.sourcepackageversion, |
412 | bpf.libraryfile.filename, bpf) |
413 | - path = self.pool.rootpath / "f" / "foo" / "foo_1.0_all.deb" |
414 | + path = pool.rootpath / "f" / "foo" / "foo_1.0_all.deb" |
415 | self.assertTrue(path.exists()) |
416 | self.assertFalse(path.is_symlink()) |
417 | self.assertEqual( |
418 | @@ -339,7 +395,7 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
419 | "launchpad.source-version": ["1.0"], |
420 | }, |
421 | path.properties) |
422 | - self.pool.updateProperties( |
423 | + pool.updateProperties( |
424 | bpr.sourcepackagename, bpr.sourcepackageversion, |
425 | bpf.libraryfile.filename, bpphs) |
426 | self.assertEqual( |
427 | @@ -354,16 +410,120 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
428 | }, |
429 | path.properties) |
430 | |
431 | + def test_updateProperties_python_sdist(self): |
432 | + pool = self.makePool(ArchiveRepositoryFormat.PYTHON) |
433 | + dses = [ |
434 | + self.factory.makeDistroSeries( |
435 | + distribution=pool.archive.distribution) |
436 | + for _ in range(2)] |
437 | + spph = self.factory.makeSourcePackagePublishingHistory( |
438 | + archive=pool.archive, distroseries=dses[0], |
439 | + pocket=PackagePublishingPocket.RELEASE, component="main", |
440 | + sourcepackagename="foo", version="1.0", channel="edge", |
441 | + format=SourcePackageType.SDIST) |
442 | + spr = spph.sourcepackagerelease |
443 | + sprf = self.factory.makeSourcePackageReleaseFile( |
444 | + sourcepackagerelease=spr, |
445 | + library_file=self.factory.makeLibraryFileAlias( |
446 | + filename="foo-1.0.tar.gz"), |
447 | + filetype=SourcePackageFileType.SDIST) |
448 | + spphs = [spph] |
449 | + spphs.append(spph.copyTo( |
450 | + dses[1], PackagePublishingPocket.RELEASE, pool.archive)) |
451 | + transaction.commit() |
452 | + pool.addFile( |
453 | + None, spr.name, spr.version, sprf.libraryfile.filename, sprf) |
454 | + path = pool.rootpath / "foo" / "1.0" / "foo-1.0.tar.gz" |
455 | + self.assertTrue(path.exists()) |
456 | + self.assertFalse(path.is_symlink()) |
457 | + self.assertEqual( |
458 | + { |
459 | + "launchpad.release-id": ["source:%d" % spr.id], |
460 | + "launchpad.source-name": ["foo"], |
461 | + "launchpad.source-version": ["1.0"], |
462 | + }, |
463 | + path.properties) |
464 | + pool.updateProperties( |
465 | + spr.name, spr.version, sprf.libraryfile.filename, spphs) |
466 | + self.assertEqual( |
467 | + { |
468 | + "launchpad.release-id": ["source:%d" % spr.id], |
469 | + "launchpad.source-name": ["foo"], |
470 | + "launchpad.source-version": ["1.0"], |
471 | + "launchpad.channel": list( |
472 | + sorted("%s:edge" % ds.name for ds in dses)), |
473 | + }, |
474 | + path.properties) |
475 | + |
476 | + def test_updateProperties_python_wheel(self): |
477 | + pool = self.makePool(ArchiveRepositoryFormat.PYTHON) |
478 | + dses = [ |
479 | + self.factory.makeDistroSeries( |
480 | + distribution=pool.archive.distribution) |
481 | + for _ in range(2)] |
482 | + processor = self.factory.makeProcessor() |
483 | + dases = [ |
484 | + self.factory.makeDistroArchSeries( |
485 | + distroseries=ds, architecturetag=processor.name) |
486 | + for ds in dses] |
487 | + spr = self.factory.makeSourcePackageRelease( |
488 | + archive=pool.archive, sourcepackagename="foo", version="1.0", |
489 | + format=SourcePackageType.SDIST) |
490 | + bpph = self.factory.makeBinaryPackagePublishingHistory( |
491 | + archive=pool.archive, distroarchseries=dases[0], |
492 | + pocket=PackagePublishingPocket.RELEASE, component="main", |
493 | + source_package_release=spr, binarypackagename="foo", |
494 | + binpackageformat=BinaryPackageFormat.WHL, |
495 | + architecturespecific=False, channel="edge") |
496 | + bpr = bpph.binarypackagerelease |
497 | + bpf = self.factory.makeBinaryPackageFile( |
498 | + binarypackagerelease=bpr, |
499 | + library_file=self.factory.makeLibraryFileAlias( |
500 | + filename="foo-1.0-py3-none-any.whl"), |
501 | + filetype=BinaryPackageFileType.WHL) |
502 | + bpphs = [bpph] |
503 | + bpphs.append( |
504 | + getUtility(IPublishingSet).copyBinaries( |
505 | + pool.archive, dses[1], PackagePublishingPocket.RELEASE, [bpph], |
506 | + channel="edge")[0]) |
507 | + transaction.commit() |
508 | + pool.addFile( |
509 | + None, bpr.sourcepackagename, bpr.sourcepackageversion, |
510 | + bpf.libraryfile.filename, bpf) |
511 | + path = pool.rootpath / "foo" / "1.0" / "foo-1.0-py3-none-any.whl" |
512 | + self.assertTrue(path.exists()) |
513 | + self.assertFalse(path.is_symlink()) |
514 | + self.assertEqual( |
515 | + { |
516 | + "launchpad.release-id": ["binary:%d" % bpr.id], |
517 | + "launchpad.source-name": ["foo"], |
518 | + "launchpad.source-version": ["1.0"], |
519 | + }, |
520 | + path.properties) |
521 | + pool.updateProperties( |
522 | + bpr.sourcepackagename, bpr.sourcepackageversion, |
523 | + bpf.libraryfile.filename, bpphs) |
524 | + self.assertEqual( |
525 | + { |
526 | + "launchpad.release-id": ["binary:%d" % bpr.id], |
527 | + "launchpad.source-name": ["foo"], |
528 | + "launchpad.source-version": ["1.0"], |
529 | + "launchpad.channel": list( |
530 | + sorted("%s:edge" % ds.name for ds in dses)), |
531 | + }, |
532 | + path.properties) |
533 | + |
534 | def test_updateProperties_preserves_externally_set_properties(self): |
535 | # Artifactory sets some properties by itself as part of scanning |
536 | # packages. We leave those untouched. |
537 | + pool = self.makePool() |
538 | ds = self.factory.makeDistroSeries( |
539 | - distribution=self.archive.distribution) |
540 | + distribution=pool.archive.distribution) |
541 | das = self.factory.makeDistroArchSeries(distroseries=ds) |
542 | spr = self.factory.makeSourcePackageRelease( |
543 | - archive=self.archive, sourcepackagename="foo", version="1.0") |
544 | + archive=pool.archive, sourcepackagename="foo", version="1.0") |
545 | bpb = self.factory.makeBinaryPackageBuild( |
546 | - archive=self.archive, source_package_release=spr, |
547 | + archive=pool.archive, source_package_release=spr, |
548 | distroarchseries=das, pocket=PackagePublishingPocket.RELEASE) |
549 | bpr = self.factory.makeBinaryPackageRelease( |
550 | binarypackagename="foo", build=bpb, component="main", |
551 | @@ -374,13 +534,13 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
552 | filename="foo_1.0_all.deb"), |
553 | filetype=BinaryPackageFileType.DEB) |
554 | bpphs = getUtility(IPublishingSet).publishBinaries( |
555 | - self.archive, ds, PackagePublishingPocket.RELEASE, |
556 | + pool.archive, ds, PackagePublishingPocket.RELEASE, |
557 | {bpr: (bpr.component, bpr.section, bpr.priority, None)}) |
558 | transaction.commit() |
559 | - self.pool.addFile( |
560 | + pool.addFile( |
561 | None, bpr.sourcepackagename, bpr.sourcepackageversion, |
562 | bpf.libraryfile.filename, bpf) |
563 | - path = self.pool.rootpath / "f" / "foo" / "foo_1.0_all.deb" |
564 | + path = pool.rootpath / "f" / "foo" / "foo_1.0_all.deb" |
565 | path.set_properties({"deb.version": ["1.0"]}, recursive=False) |
566 | self.assertEqual( |
567 | { |
568 | @@ -390,7 +550,7 @@ class TestArtifactoryPoolFromLibrarian(TestCaseWithFactory): |
569 | "deb.version": ["1.0"], |
570 | }, |
571 | path.properties) |
572 | - self.pool.updateProperties( |
573 | + pool.updateProperties( |
574 | bpr.sourcepackagename, bpr.sourcepackageversion, |
575 | bpf.libraryfile.filename, bpphs) |
576 | self.assertEqual( |
577 | diff --git a/lib/lp/archivepublisher/tests/test_config.py b/lib/lp/archivepublisher/tests/test_config.py |
578 | index 915b4e7..75b1431 100644 |
579 | --- a/lib/lp/archivepublisher/tests/test_config.py |
580 | +++ b/lib/lp/archivepublisher/tests/test_config.py |
581 | @@ -16,7 +16,11 @@ from lp.archivepublisher.config import getPubConfig |
582 | from lp.registry.interfaces.distribution import IDistributionSet |
583 | from lp.services.config import config |
584 | from lp.services.log.logger import BufferLogger |
585 | -from lp.soyuz.enums import ArchivePurpose |
586 | +from lp.soyuz.enums import ( |
587 | + ArchivePublishingMethod, |
588 | + ArchivePurpose, |
589 | + ArchiveRepositoryFormat, |
590 | + ) |
591 | from lp.soyuz.interfaces.archive import IArchiveSet |
592 | from lp.testing import TestCaseWithFactory |
593 | from lp.testing.layers import ZopelessDatabaseLayer |
594 | @@ -235,3 +239,35 @@ class TestGetPubConfigPPACompatUefi(TestCaseWithFactory): |
595 | signingroot = "/var/tmp/ppa-signing-keys.test/uefi/%s/%s" % ( |
596 | self.ppa.owner.name, self.ppa.name) |
597 | self.assertEqual(signingroot, self.ppa_config.signingroot) |
598 | + |
599 | + |
600 | +class TestGetPubConfigPPARepositoryFormatPython(TestCaseWithFactory): |
601 | + |
602 | + layer = ZopelessDatabaseLayer |
603 | + |
604 | + def setUp(self): |
605 | + super().setUp() |
606 | + self.base_url = "https://foo.example.com/artifactory" |
607 | + self.pushConfig("artifactory", base_url=self.base_url) |
608 | + self.ppa = self.factory.makeArchive( |
609 | + purpose=ArchivePurpose.PPA, |
610 | + publishing_method=ArchivePublishingMethod.ARTIFACTORY, |
611 | + repository_format=ArchiveRepositoryFormat.PYTHON) |
612 | + self.ppa_config = getPubConfig(self.ppa) |
613 | + |
614 | + def test_config(self): |
615 | + # Python-format archives published via Artifactory use paths under |
616 | + # the Artifactory base URL, and have various features disabled that |
617 | + # only make sense for locally-published Debian-format archives. |
618 | + self.assertIsNone(self.ppa_config.distroroot) |
619 | + archiveroot = "%s/%s" % (self.base_url, self.ppa.name) |
620 | + self.assertEqual(archiveroot, self.ppa_config.archiveroot) |
621 | + self.assertEqual(archiveroot, self.ppa_config.poolroot) |
622 | + self.assertIsNone(self.ppa_config.distsroot) |
623 | + self.assertIsNone(self.ppa_config.overrideroot) |
624 | + self.assertIsNone(self.ppa_config.cacheroot) |
625 | + self.assertIsNone(self.ppa_config.miscroot) |
626 | + self.assertEqual( |
627 | + "/var/tmp/archive/%s-temp" % self.ppa.distribution.name, |
628 | + self.ppa_config.temproot) |
629 | + self.assertIsNone(self.ppa_config.metaroot) |
630 | diff --git a/lib/lp/registry/interfaces/sourcepackage.py b/lib/lp/registry/interfaces/sourcepackage.py |
631 | index eddd622..21d02ca 100644 |
632 | --- a/lib/lp/registry/interfaces/sourcepackage.py |
633 | +++ b/lib/lp/registry/interfaces/sourcepackage.py |
634 | @@ -418,6 +418,12 @@ class SourcePackageFileType(DBEnumeratedType): |
635 | This file is a detached signature for an Ubuntu component "orig" |
636 | file.""") |
637 | |
638 | + SDIST = DBItem(11, """ |
639 | + Python Source Distribution |
640 | + |
641 | + This file is a Python source distribution ("sdist"). |
642 | + """) |
643 | + |
644 | |
645 | class SourcePackageType(DBEnumeratedType): |
646 | """Source Package Format |
647 | @@ -447,6 +453,12 @@ class SourcePackageType(DBEnumeratedType): |
648 | This is the source package format used by Gentoo. |
649 | """) |
650 | |
651 | + SDIST = DBItem(4, """ |
652 | + The Python Format |
653 | + |
654 | + This is the source package format used by Python packages. |
655 | + """) |
656 | + |
657 | |
658 | class SourcePackageUrgency(DBEnumeratedType): |
659 | """Source Package Urgency |
Merging failed /jenkins. ols.canonical. com/online- services/ job/launchpad/ 2527/
https:/