~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
= Fake Packager Utility =

FakePackager allows us to easily create minimal debian packages to be
used in tests.

    >>> import os
    >>> from lp.soyuz.tests.fakepackager import FakePackager


== Setup and reset ==

When FakePackager is initialized it automatically creates a temporary
directory we call 'sandbox'. It's where the packages will get created.

    >>> packager = FakePackager('biscuit', '1.0')

    >>> print packager.sandbox_path
    /tmp/fakepackager-...

    >>> os.path.exists(packager.sandbox_path)
    True

Source 'name' and 'version' and 'gpg_key_id' are set according the
give arguments passed in the initialization.

    >>> print packager.name
    biscuit

    >>> print packager.version
    1.0

    >>> print packager.gpg_key_id
    None

The upstream directory is known but not yet created.

    >>> print packager.upstream_directory
    /tmp/fakepackager-.../biscuit-1.0

    >>> os.path.exists(packager.upstream_directory)
    False


== Creating Packages ==

Then we create it on disk based on the FakePackager templates.

    >>> packager.buildUpstream(build_orig=False)

It results in a buildable source package with the suffix '-1' appended
to the upstream version in the upstream_directory path.

    >>> os.path.exists(packager.upstream_directory)
    True

    >>> print sorted(os.listdir(packager.sandbox_path))
    ['biscuit-1.0']

    >>> print sorted(os.listdir(packager.debian_path))
    ['changelog', 'control', 'copyright', 'rules']

We will instantiate a new packager so we can generate a new upstream
directory with a corresponding original tarball.

    >>> packager = FakePackager('biscuit', '1.0')
    >>> packager.buildUpstream()

    >>> print sorted(os.listdir(packager.sandbox_path))
    ['biscuit-1.0', 'biscuit_1.0.orig.tar.gz']

    >>> print sorted(os.listdir(packager.debian_path))
    ['changelog', 'control', 'copyright', 'rules']

Now we can build the source package using the generated tarball.

    >>> packager.buildSource(signed=False)

    >>> for changesfile in packager.listAvailableUploads():
    ...     print changesfile
    /tmp/fakepackager-.../biscuit_1.0-1_source.changes

    >>> changesfile_path = packager.listAvailableUploads()[0]
    >>> changesfile = open(changesfile_path)
    >>> print changesfile.read()
    Format: ...
    Date: ...
    Source: biscuit
    Binary: biscuit
    Architecture: source
    Version: 1.0-1
    Distribution: hoary
    Urgency: low
    Maintainer: Launchpad team <launchpad@lists.canonical.com>
    Changed-By: Foo Bar <foo.bar@canonical.com>
    Description:
     biscuit    - Stuff for testing
    Changes:
     biscuit (1.0-1) hoary; urgency=low
     .
       * Initial Upstream package
    ...
     ... devel optional biscuit_1.0-1.dsc
     ... devel optional biscuit_1.0.orig.tar.gz
     ... devel optional biscuit_1.0-1.diff.gz
    <BLANKLINE>

When we try to build an incompatible package version an error will be
raised indicating it could not created.

    >>> packager.buildVersion('2.0-2', changelog_text="version on crack.")
    Traceback (most recent call last):
    ...
    AssertionError: New versions should start with the upstream version: 1.0

Using a proper version, let's build a new source package version, but
now signing the DSC and the changesfile.

    >>> packager.buildVersion(
    ...    '1.0-2', changelog_text="Waar ligt de sleutel ?")
    >>> packager.buildSource(include_orig=True)
    Traceback (most recent call last):
    ...
    AssertionError: Cannot build signed packages because the key is not set.

The error was raised because no signing key was set.

    >>> print packager.gpg_key_id
    None

A GPG key can only be set on initialization so we will have to create a
new packager passing a filename available in our test_keys directory
(see launchpad/ftests/keys_for_tests.py)

    >>> packager = FakePackager(
    ...     'biscuit', '1.0', 'foo.bar@canonical.com-passwordless.sec')
    >>> packager.buildUpstream()
    >>> packager.buildSource()

GPG key set, now we are able to build a signed version.

    >>> print packager.gpg_key_id
    0x5D147547

FakePackager also allows us to include as many versions it needs
before building the package. It helps when the content of the
changelog matters in the test context.

    >>> packager.buildVersion('1.0-2', changelog_text="cookies")
    >>> packager.buildVersion('1.0-3', changelog_text="butter cookies")
    >>> packager.buildSource(include_orig=False)

The generated changesfile contains a valid signature done by the
preset GPG key. All the job is done by `debuild` here, we are
basically checking we pass the right arguments to it.

    >>> changesfile_path = packager.listAvailableUploads()[1]
    >>> print os.path.basename(changesfile_path)
    biscuit_1.0-3_source.changes

    >>> content = open(changesfile_path).read()

    >>> from zope.component import getUtility
    >>> from lp.services.gpg.interfaces import IGPGHandler
    >>> gpghandler = getUtility(IGPGHandler)
    >>> sig = gpghandler.verifySignature(content)

    >>> sig.fingerprint[-8:] == packager.gpg_key_id[2:]
    True

Continuing in the same 'sandbox', we can generate subsequent packages
for the same upstream source.

    >>> packager.buildVersion('1.0-4', changelog_text="uhmmm, leker")
    >>> packager.buildSource(include_orig=False)

Or, at any time, we can create another packager.

    >>> zeca_packager = FakePackager(
    ...     'zeca', '1.0', 'foo.bar@canonical.com-passwordless.sec')
    >>> zeca_packager.buildUpstream()
    >>> zeca_packager.buildSource()

    >>> zeca_packager.buildVersion('1.0-2', changelog_text="cookies")
    >>> zeca_packager.buildSource(include_orig=False)

And get back to the previous source.

    >>> packager.buildVersion('1.0-5', changelog_text="we, together, again.")
    >>> packager.buildSource(include_orig=False)

All generated changesfiles and related files are available in their
corresponding sandbox directory.

    >>> for changesfile in packager.listAvailableUploads():
    ...     print changesfile
    /tmp/fakepackager-.../biscuit_1.0-1_source.changes
    /tmp/fakepackager-.../biscuit_1.0-3_source.changes
    /tmp/fakepackager-.../biscuit_1.0-4_source.changes
    /tmp/fakepackager-.../biscuit_1.0-5_source.changes

    >>> for changesfile in zeca_packager.listAvailableUploads():
    ...     print changesfile
    /tmp/fakepackager-.../zeca_1.0-1_source.changes
    /tmp/fakepackager-.../zeca_1.0-2_source.changes

Finally, an error is raised if we try to build a source package before
creating the upstream directory.

    >>> canjica_packager = FakePackager('canjica', '1.0')
    >>> canjica_packager.buildSource()
    Traceback (most recent call last):
    ...
    AssertionError: Selected upstream directory does not exist: canjica-1.0


== Uploading generated packages ==

FakePackage also allow the user to upload available packages using a
simplified upload-processor.

In order to upload packages we have to be logged in as an administrator.

    >>> login('foo.bar@canonical.com')

It also requires the public test gpg keys to be imported in the
database.

    >>> from lp.testing.gpgkeys import import_public_test_keys
    >>> import_public_test_keys()

The default upload target is ubuntu/hoary and since we will deal with
NEW packages, which defaults to 'universe' component, we have to
enable uploads for it.

    >>> from lp.soyuz.model.component import (
    ...     ComponentSelection)
    >>> from lp.services.librarian.interfaces import ILibraryFileAliasSet
    >>> from lp.registry.interfaces.distribution import IDistributionSet
    >>> from lp.soyuz.interfaces.component import IComponentSet

    >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
    >>> hoary = ubuntu.getSeries('hoary')
    >>> universe = getUtility(IComponentSet)['universe']
    >>> selection = ComponentSelection(
    ...     distroseries=hoary, component=universe)
    >>> fake_chroot = getUtility(ILibraryFileAliasSet)[1]
    >>> unused = hoary['i386'].addOrUpdateChroot(fake_chroot)
    >>> unused = hoary['hppa'].addOrUpdateChroot(fake_chroot)

Uploading a generated package is deadly simple: just call
`FakePackager.uploadSourceVersion()` passing the desired upload
version.

It raises an error if the version has not been generated.

    >>> upload = zeca_packager.uploadSourceVersion('6.6.6')
    Traceback (most recent call last):
    ...
    AssertionError: Could not find a source upload for version 6.6.6.

If the version is available, the package is uploaded, NEW packages are
automatically accepted, builds are created, the upload is published and
the source publishing record created are returned.

    >>> print ubuntu.getSourcePackage('zeca')
    None

    >>> zeca_pub = zeca_packager.uploadSourceVersion('1.0-1')

    >>> print zeca_pub.displayname, zeca_pub.status.name
    zeca 1.0-1 in hoary PENDING

    >>> len(zeca_pub.getBuilds())
    2

    >>> print ubuntu.getSourcePackage('zeca').currentrelease.version
    1.0-1

New uploaded versions will immediately show up as the current
version in ubuntu.

    >>> zeca_pub = zeca_packager.uploadSourceVersion('1.0-2')

    >>> len(zeca_pub.getBuilds())
    2

    >>> print ubuntu.getSourcePackage('zeca').currentrelease.version
    1.0-2

We can change the upload policy for a specific upload, for instance to
allow unsigned uploads.

    >>> biscuit_pub = packager.uploadSourceVersion('1.0-1', policy="sync")

    >>> len(biscuit_pub.getBuilds())
    2

    >>> print ubuntu.getSourcePackage('biscuit').currentrelease.version
    1.0-1

Since we are using Foo Bar's GPG key to sign packages, in order to test
PPA uploads we will create a PPA for it.

    >>> from lp.registry.interfaces.person import IPersonSet
    >>> foobar = getUtility(IPersonSet).getByName('name16')
    >>> print foobar.archive
    None

    >>> from lp.soyuz.enums import ArchivePurpose
    >>> from lp.soyuz.interfaces.archive import IArchiveSet
    >>> ppa = getUtility(IArchiveSet).new(
    ...     owner=foobar, distribution=ubuntu, purpose=ArchivePurpose.PPA)

So, uploading to a PPA only requires us to specify the target archive.

    >>> ppa_pub = packager.uploadSourceVersion(
    ...     '1.0-5', archive=foobar.archive)

    >>> print ppa_pub.archive.displayname
    PPA for Foo Bar

    >>> print ppa_pub.displayname, ppa_pub.status.name
    biscuit 1.0-5 in hoary PENDING

    >>> len(ppa_pub.getBuilds())
    1

Upload errors are raised when they happen. In this case, packages
signed by Foo Bar can't be uploaded to Celso's PPA.

    >>> cprov = getUtility(IPersonSet).getByName('cprov')

    >>> cprov_pub = packager.uploadSourceVersion(
    ...     '1.0-5', archive=cprov.archive)
    Traceback (most recent call last):
    ...
    AssertionError: Upload was rejected: Signer has no upload rights
    to this PPA.