Merge lp:~cjwatson/launchpad/snap-auto-build-ui into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18129
Proposed branch: lp:~cjwatson/launchpad/snap-auto-build-ui
Merge into: lp:launchpad
Prerequisite: lp:~cjwatson/launchpad/snap-auto-build-archive-widget
Diff against target: 797 lines (+426/-43)
10 files modified
lib/lp/snappy/browser/snap.py (+58/-5)
lib/lp/snappy/browser/tests/test_snap.py (+77/-1)
lib/lp/snappy/configure.zcml (+2/-0)
lib/lp/snappy/help/snap-build-frequency.html (+42/-0)
lib/lp/snappy/javascript/snap.edit.js (+25/-6)
lib/lp/snappy/javascript/tests/test_snap.edit.html (+90/-1)
lib/lp/snappy/javascript/tests/test_snap.edit.js (+35/-2)
lib/lp/snappy/templates/snap-edit.pt (+36/-18)
lib/lp/snappy/templates/snap-index.pt (+25/-0)
lib/lp/snappy/templates/snap-new.pt (+36/-10)
To merge this branch: bzr merge lp:~cjwatson/launchpad/snap-auto-build-ui
Reviewer Review Type Date Requested Status
Thomi Richards (community) Approve
Launchpad code reviewers Pending
Review via email: mp+297962@code.launchpad.net

Commit message

Add UI for auto-building snap packages.

Description of the change

Add UI for auto-building snap packages. It's a little basic and could probably use more JS niceties in a few places, but it's functional.

To post a comment you must log in.
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

LGTM, but it might be worth asking someone with more LP UI experience to take a look.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/snappy/browser/snap.py'
--- lib/lp/snappy/browser/snap.py 2016-07-05 10:20:51 +0000
+++ lib/lp/snappy/browser/snap.py 2016-07-12 13:40:07 +0000
@@ -179,6 +179,13 @@
179 self.context, field, format_link(self.context.owner),179 self.context, field, format_link(self.context.owner),
180 header='Change owner', step_title='Select a new owner')180 header='Change owner', step_title='Select a new owner')
181181
182 @property
183 def build_frequency(self):
184 if self.context.auto_build:
185 return 'Built automatically'
186 else:
187 return 'Built on request'
188
182189
183def builds_for_snap(snap):190def builds_for_snap(snap):
184 """A list of interesting builds.191 """A list of interesting builds.
@@ -303,6 +310,7 @@
303 'name',310 'name',
304 'private',311 'private',
305 'require_virtualized',312 'require_virtualized',
313 'auto_build',
306 'store_upload',314 'store_upload',
307 ])315 ])
308 store_distro_series = Choice(316 store_distro_series = Choice(
@@ -315,8 +323,13 @@
315 branch = copy_field(ISnap['branch'], required=True)323 branch = copy_field(ISnap['branch'], required=True)
316 git_ref = copy_field(ISnap['git_ref'], required=True)324 git_ref = copy_field(ISnap['git_ref'], required=True)
317325
318 # These are only required if store_upload is True. Later validation326 # These are only required if auto_build is True. Later validation takes
319 # takes care of adjusting the required attribute.327 # care of adjusting the required attribute.
328 auto_build_archive = copy_field(ISnap['auto_build_archive'], required=True)
329 auto_build_pocket = copy_field(ISnap['auto_build_pocket'], required=True)
330
331 # This is only required if store_upload is True. Later validation takes
332 # care of adjusting the required attribute.
320 store_name = copy_field(ISnap['store_name'], required=True)333 store_name = copy_field(ISnap['store_name'], required=True)
321334
322335
@@ -350,10 +363,14 @@
350 'owner',363 'owner',
351 'name',364 'name',
352 'store_distro_series',365 'store_distro_series',
366 'auto_build',
367 'auto_build_archive',
368 'auto_build_pocket',
353 'store_upload',369 'store_upload',
354 'store_name',370 'store_name',
355 ]371 ]
356 custom_widget('store_distro_series', LaunchpadRadioWidget)372 custom_widget('store_distro_series', LaunchpadRadioWidget)
373 custom_widget('auto_build_archive', SnapArchiveWidget)
357374
358 def initialize(self):375 def initialize(self):
359 """See `LaunchpadView`."""376 """See `LaunchpadView`."""
@@ -417,6 +434,8 @@
417 'processors': [434 'processors': [
418 p for p in getUtility(IProcessorSet).getAll()435 p for p in getUtility(IProcessorSet).getAll()
419 if p.build_by_default],436 if p.build_by_default],
437 'auto_build_archive': series.main_archive,
438 'auto_build_pocket': PackagePublishingPocket.UPDATES,
420 }439 }
421440
422 @property441 @property
@@ -425,6 +444,13 @@
425444
426 def validate_widgets(self, data, names=None):445 def validate_widgets(self, data, names=None):
427 """See `LaunchpadFormView`."""446 """See `LaunchpadFormView`."""
447 if self.widgets.get('auto_build') is not None:
448 # Set widgets as required or optional depending on the
449 # auto_build field.
450 super(SnapAddView, self).validate_widgets(data, ['auto_build'])
451 auto_build = data.get('auto_build', False)
452 self.widgets['auto_build_archive'].context.required = auto_build
453 self.widgets['auto_build_pocket'].context.required = auto_build
428 if self.widgets.get('store_upload') is not None:454 if self.widgets.get('store_upload') is not None:
429 # Set widgets as required or optional depending on the455 # Set widgets as required or optional depending on the
430 # store_upload field.456 # store_upload field.
@@ -441,9 +467,15 @@
441 kwargs = {'branch': self.context}467 kwargs = {'branch': self.context}
442 private = not getUtility(468 private = not getUtility(
443 ISnapSet).isValidPrivacy(False, data['owner'], **kwargs)469 ISnapSet).isValidPrivacy(False, data['owner'], **kwargs)
470 if not data.get('auto_build', False):
471 data['auto_build_archive'] = None
472 data['auto_build_pocket'] = None
444 snap = getUtility(ISnapSet).new(473 snap = getUtility(ISnapSet).new(
445 self.user, data['owner'],474 self.user, data['owner'],
446 data['store_distro_series'].distro_series, data['name'],475 data['store_distro_series'].distro_series, data['name'],
476 auto_build=data['auto_build'],
477 auto_build_archive=data['auto_build_archive'],
478 auto_build_pocket=data['auto_build_pocket'],
447 private=private, store_upload=data['store_upload'],479 private=private, store_upload=data['store_upload'],
448 store_series=data['store_distro_series'].snappy_series,480 store_series=data['store_distro_series'].snappy_series,
449 store_name=data['store_name'], processors=data['processors'],481 store_name=data['store_name'], processors=data['processors'],
@@ -502,6 +534,14 @@
502 self.widgets['git_ref'].context.required = True534 self.widgets['git_ref'].context.required = True
503 else:535 else:
504 raise AssertionError("Unknown branch type %s" % vcs)536 raise AssertionError("Unknown branch type %s" % vcs)
537 if self.widgets.get('auto_build') is not None:
538 # Set widgets as required or optional depending on the
539 # auto_build field.
540 super(BaseSnapEditView, self).validate_widgets(
541 data, ['auto_build'])
542 auto_build = data.get('auto_build', False)
543 self.widgets['auto_build_archive'].context.required = auto_build
544 self.widgets['auto_build_pocket'].context.required = auto_build
505 if self.widgets.get('store_upload') is not None:545 if self.widgets.get('store_upload') is not None:
506 # Set widgets as required or optional depending on the546 # Set widgets as required or optional depending on the
507 # store_upload field.547 # store_upload field.
@@ -538,9 +578,15 @@
538 self.context.setProcessors(578 self.context.setProcessors(
539 new_processors, check_permissions=True, user=self.user)579 new_processors, check_permissions=True, user=self.user)
540 del data['processors']580 del data['processors']
581 if not data.get('auto_build', False):
582 if 'auto_build_archive' in data:
583 del data['auto_build_archive']
584 if 'auto_build_pocket' in data:
585 del data['auto_build_pocket']
541 store_upload = data.get('store_upload', False)586 store_upload = data.get('store_upload', False)
542 if not store_upload:587 if not store_upload:
543 data['store_name'] = None588 if 'store_name' in data:
589 del data['store_name']
544 need_store_reauth = self._needStoreReauth(data)590 need_store_reauth = self._needStoreReauth(data)
545 self.updateContextFromData(data)591 self.updateContextFromData(data)
546 if need_store_reauth:592 if need_store_reauth:
@@ -592,15 +638,19 @@
592 'owner',638 'owner',
593 'name',639 'name',
594 'store_distro_series',640 'store_distro_series',
595 'store_upload',
596 'store_name',
597 'vcs',641 'vcs',
598 'branch',642 'branch',
599 'git_ref',643 'git_ref',
644 'auto_build',
645 'auto_build_archive',
646 'auto_build_pocket',
647 'store_upload',
648 'store_name',
600 ]649 ]
601 custom_widget('store_distro_series', LaunchpadRadioWidget)650 custom_widget('store_distro_series', LaunchpadRadioWidget)
602 custom_widget('vcs', LaunchpadRadioWidget)651 custom_widget('vcs', LaunchpadRadioWidget)
603 custom_widget('git_ref', GitRefWidget)652 custom_widget('git_ref', GitRefWidget)
653 custom_widget('auto_build_archive', SnapArchiveWidget)
604654
605 def setUpFields(self):655 def setUpFields(self):
606 """See `LaunchpadFormView`."""656 """See `LaunchpadFormView`."""
@@ -624,6 +674,9 @@
624 initial_values['vcs'] = VCSType.GIT674 initial_values['vcs'] = VCSType.GIT
625 else:675 else:
626 initial_values['vcs'] = VCSType.BZR676 initial_values['vcs'] = VCSType.BZR
677 if self.context.auto_build_pocket is None:
678 initial_values['auto_build_pocket'] = (
679 PackagePublishingPocket.UPDATES)
627 return initial_values680 return initial_values
628681
629 def validate(self, data):682 def validate(self, data):
630683
=== modified file 'lib/lp/snappy/browser/tests/test_snap.py'
--- lib/lp/snappy/browser/tests/test_snap.py 2016-07-05 10:20:51 +0000
+++ lib/lp/snappy/browser/tests/test_snap.py 2016-07-12 13:40:07 +0000
@@ -42,6 +42,7 @@
42from lp.buildmaster.enums import BuildStatus42from lp.buildmaster.enums import BuildStatus
43from lp.buildmaster.interfaces.processor import IProcessorSet43from lp.buildmaster.interfaces.processor import IProcessorSet
44from lp.code.errors import GitRepositoryScanFault44from lp.code.errors import GitRepositoryScanFault
45from lp.code.interfaces.githosting import IGitHostingClient
45from lp.registry.enums import PersonVisibility46from lp.registry.enums import PersonVisibility
46from lp.registry.interfaces.pocket import PackagePublishingPocket47from lp.registry.interfaces.pocket import PackagePublishingPocket
47from lp.registry.interfaces.series import SeriesStatus48from lp.registry.interfaces.series import SeriesStatus
@@ -72,6 +73,7 @@
72 time_counter,73 time_counter,
73 )74 )
74from lp.testing.fakemethod import FakeMethod75from lp.testing.fakemethod import FakeMethod
76from lp.testing.fixture import ZopeUtilityFixture
75from lp.testing.layers import (77from lp.testing.layers import (
76 DatabaseFunctionalLayer,78 DatabaseFunctionalLayer,
77 LaunchpadFunctionalLayer,79 LaunchpadFunctionalLayer,
@@ -220,11 +222,23 @@
220 "Source:\n%s\nEdit snap package" % source_display,222 "Source:\n%s\nEdit snap package" % source_display,
221 MatchesTagText(content, "source"))223 MatchesTagText(content, "source"))
222 self.assertThat(224 self.assertThat(
225 "Build schedule:\n(?)\nBuilt on request\nEdit snap package\n",
226 MatchesTagText(content, "auto_build"))
227 self.assertThat(
228 "Source archive for automatic builds:\n\nEdit snap package\n",
229 MatchesTagText(content, "auto_build_archive"))
230 self.assertThat(
231 "Pocket for automatic builds:\n\nEdit snap package",
232 MatchesTagText(content, "auto_build_pocket"))
233 self.assertThat(
223 "Builds of this snap package are not automatically uploaded to "234 "Builds of this snap package are not automatically uploaded to "
224 "the store.\nEdit snap package",235 "the store.\nEdit snap package",
225 MatchesTagText(content, "store_upload"))236 MatchesTagText(content, "store_upload"))
226237
227 def test_create_new_snap_git(self):238 def test_create_new_snap_git(self):
239 hosting_client = FakeMethod()
240 hosting_client.getBlob = FakeMethod(result="")
241 self.useFixture(ZopeUtilityFixture(hosting_client, IGitHostingClient))
228 [git_ref] = self.factory.makeGitRefs()242 [git_ref] = self.factory.makeGitRefs()
229 source_display = git_ref.display_name243 source_display = git_ref.display_name
230 browser = self.getViewBrowser(244 browser = self.getViewBrowser(
@@ -244,6 +258,15 @@
244 "Source:\n%s\nEdit snap package" % source_display,258 "Source:\n%s\nEdit snap package" % source_display,
245 MatchesTagText(content, "source"))259 MatchesTagText(content, "source"))
246 self.assertThat(260 self.assertThat(
261 "Build schedule:\n(?)\nBuilt on request\nEdit snap package\n",
262 MatchesTagText(content, "auto_build"))
263 self.assertThat(
264 "Source archive for automatic builds:\n\nEdit snap package\n",
265 MatchesTagText(content, "auto_build_archive"))
266 self.assertThat(
267 "Pocket for automatic builds:\n\nEdit snap package",
268 MatchesTagText(content, "auto_build_pocket"))
269 self.assertThat(
247 "Builds of this snap package are not automatically uploaded to "270 "Builds of this snap package are not automatically uploaded to "
248 "the store.\nEdit snap package",271 "the store.\nEdit snap package",
249 MatchesTagText(content, "store_upload"))272 MatchesTagText(content, "store_upload"))
@@ -309,6 +332,34 @@
309 extract_text(find_tag_by_id(browser.contents, "privacy"))332 extract_text(find_tag_by_id(browser.contents, "privacy"))
310 )333 )
311334
335 def test_create_new_snap_auto_build(self):
336 # Creating a new snap and asking for it to be automatically built
337 # sets all the appropriate fields.
338 branch = self.factory.makeAnyBranch()
339 archive = self.factory.makeArchive()
340 browser = self.getViewBrowser(
341 branch, view_name="+new-snap", user=self.person)
342 browser.getControl(name="field.name").value = "snap-name"
343 browser.getControl(
344 "Automatically build when branch changes").selected = True
345 browser.getControl("PPA").click()
346 browser.getControl(name="field.auto_build_archive.ppa").value = (
347 archive.reference)
348 browser.getControl("Pocket for automatic builds").value = ["SECURITY"]
349 browser.getControl("Create snap package").click()
350
351 content = find_main_content(browser.contents)
352 self.assertThat(
353 "Build schedule:\n(?)\nBuilt automatically\nEdit snap package\n",
354 MatchesTagText(content, "auto_build"))
355 self.assertThat(
356 "Source archive for automatic builds:\n%s\nEdit snap package\n" %
357 archive.displayname,
358 MatchesTagText(content, "auto_build_archive"))
359 self.assertThat(
360 "Pocket for automatic builds:\nSecurity\nEdit snap package",
361 MatchesTagText(content, "auto_build_pocket"))
362
312 def test_create_new_snap_store_upload(self):363 def test_create_new_snap_store_upload(self):
313 # Creating a new snap and asking for it to be automatically uploaded364 # Creating a new snap and asking for it to be automatically uploaded
314 # to the store sets all the appropriate fields and redirects to SSO365 # to the store sets all the appropriate fields and redirects to SSO
@@ -441,7 +492,7 @@
441 view = create_initialized_view(git_ref, "+new-snap")492 view = create_initialized_view(git_ref, "+new-snap")
442 with mock.patch('yaml.load') as unsafe_load:493 with mock.patch('yaml.load') as unsafe_load:
443 with mock.patch('yaml.safe_load') as safe_load:494 with mock.patch('yaml.safe_load') as safe_load:
444 initial_values = view.initial_values495 view.initial_values
445 self.assertEqual(0, unsafe_load.call_count)496 self.assertEqual(0, unsafe_load.call_count)
446 self.assertEqual(1, safe_load.call_count)497 self.assertEqual(1, safe_load.call_count)
447498
@@ -574,6 +625,7 @@
574 new_snappy_series = self.factory.makeSnappySeries(625 new_snappy_series = self.factory.makeSnappySeries(
575 usable_distro_series=[new_series])626 usable_distro_series=[new_series])
576 [new_git_ref] = self.factory.makeGitRefs()627 [new_git_ref] = self.factory.makeGitRefs()
628 archive = self.factory.makeArchive()
577629
578 browser = self.getViewBrowser(snap, user=self.person)630 browser = self.getViewBrowser(snap, user=self.person)
579 browser.getLink("Edit snap package").click()631 browser.getLink("Edit snap package").click()
@@ -585,6 +637,12 @@
585 browser.getControl("Git repository").value = (637 browser.getControl("Git repository").value = (
586 new_git_ref.repository.identity)638 new_git_ref.repository.identity)
587 browser.getControl("Git branch").value = new_git_ref.path639 browser.getControl("Git branch").value = new_git_ref.path
640 browser.getControl(
641 "Automatically build when branch changes").selected = True
642 browser.getControl("PPA").click()
643 browser.getControl(name="field.auto_build_archive.ppa").value = (
644 archive.reference)
645 browser.getControl("Pocket for automatic builds").value = ["SECURITY"]
588 browser.getControl("Update snap package").click()646 browser.getControl("Update snap package").click()
589647
590 content = find_main_content(browser.contents)648 content = find_main_content(browser.contents)
@@ -598,6 +656,16 @@
598 "Source:\n%s\nEdit snap package" % new_git_ref.display_name,656 "Source:\n%s\nEdit snap package" % new_git_ref.display_name,
599 MatchesTagText(content, "source"))657 MatchesTagText(content, "source"))
600 self.assertThat(658 self.assertThat(
659 "Build schedule:\n(?)\nBuilt automatically\nEdit snap package\n",
660 MatchesTagText(content, "auto_build"))
661 self.assertThat(
662 "Source archive for automatic builds:\n%s\nEdit snap package\n" %
663 archive.displayname,
664 MatchesTagText(content, "auto_build_archive"))
665 self.assertThat(
666 "Pocket for automatic builds:\nSecurity\nEdit snap package",
667 MatchesTagText(content, "auto_build_pocket"))
668 self.assertThat(
601 "Builds of this snap package are not automatically uploaded to "669 "Builds of this snap package are not automatically uploaded to "
602 "the store.\nEdit snap package",670 "the store.\nEdit snap package",
603 MatchesTagText(content, "store_upload"))671 MatchesTagText(content, "store_upload"))
@@ -1083,6 +1151,10 @@
1083 Owner: Test Person1151 Owner: Test Person
1084 Distribution series: Ubuntu Shiny1152 Distribution series: Ubuntu Shiny
1085 Source: lp://dev/~test-person/\\+junk/snap-branch1153 Source: lp://dev/~test-person/\\+junk/snap-branch
1154 Build schedule: \(\?\)
1155 Built on request
1156 Source archive for automatic builds:
1157 Pocket for automatic builds:
1086 Builds of this snap package are not automatically uploaded to1158 Builds of this snap package are not automatically uploaded to
1087 the store.1159 the store.
1088 Latest builds1160 Latest builds
@@ -1106,6 +1178,10 @@
1106 Owner: Test Person1178 Owner: Test Person
1107 Distribution series: Ubuntu Shiny1179 Distribution series: Ubuntu Shiny
1108 Source: ~test-person/\\+git/snap-repository:master1180 Source: ~test-person/\\+git/snap-repository:master
1181 Build schedule: \(\?\)
1182 Built on request
1183 Source archive for automatic builds:
1184 Pocket for automatic builds:
1109 Builds of this snap package are not automatically uploaded to1185 Builds of this snap package are not automatically uploaded to
1110 the store.1186 the store.
1111 Latest builds1187 Latest builds
11121188
=== modified file 'lib/lp/snappy/configure.zcml'
--- lib/lp/snappy/configure.zcml 2016-05-06 16:34:21 +0000
+++ lib/lp/snappy/configure.zcml 2016-07-12 13:40:07 +0000
@@ -14,6 +14,8 @@
14 <include package=".browser" />14 <include package=".browser" />
15 <include file="vocabularies.zcml" />15 <include file="vocabularies.zcml" />
1616
17 <lp:help-folder folder="help" name="+help-snappy" />
18
17 <!-- Snap -->19 <!-- Snap -->
18 <class class="lp.snappy.model.snap.Snap">20 <class class="lp.snappy.model.snap.Snap">
19 <require21 <require
2022
=== added directory 'lib/lp/snappy/help'
=== added file 'lib/lp/snappy/help/snap-build-frequency.html'
--- lib/lp/snappy/help/snap-build-frequency.html 1970-01-01 00:00:00 +0000
+++ lib/lp/snappy/help/snap-build-frequency.html 2016-07-12 13:40:07 +0000
@@ -0,0 +1,42 @@
1<html>
2 <head>
3 <title>Snap package build schedule</title>
4 <link rel="stylesheet" type="text/css"
5 href="/+icing/yui/cssreset/reset.css" />
6 <link rel="stylesheet" type="text/css"
7 href="/+icing/yui/cssfonts/fonts.css" />
8 <link rel="stylesheet" type="text/css"
9 href="/+icing/yui/cssbase/base.css" />
10 <style type="text/css">
11 dt { font-weight: bold }
12 dd p { margin-bottom: 0.5em }
13 </style>
14 </head>
15 <body>
16 <h1>Snap package build schedule</h1>
17
18 <p>There are two options for when snap packages get built:</p>
19 <dl>
20 <dt>Built automatically</dt>
21 <dd>
22 <p>A build will be scheduled automatically once a change to the
23 top-level source branch for the snap package is detected.</p>
24 <p>If there has been a build of the snap package within the previous
25 hour from the source archive, the build will not be scheduled
26 until an hour since the last build from the source archive.</p>
27 <p>If the snap package has been built within the last hour from a
28 different archive using the "Request builds" action, this will not
29 delay the automatic build.</p>
30 <p>If you really want the build to happen before the one-hour period
31 is up, you can use the "Request builds" action.</p>
32 </dd>
33 <dt>Built on request</dt>
34 <dd>
35 <p>Builds of the snap package have to be manually requested using
36 the "Request builds" action.</p>
37 </dd>
38 </dl>
39
40 </body>
41</html>
42
043
=== modified file 'lib/lp/snappy/javascript/snap.edit.js'
--- lib/lp/snappy/javascript/snap.edit.js 2015-09-09 14:17:46 +0000
+++ lib/lp/snappy/javascript/snap.edit.js 2016-07-12 13:40:07 +0000
@@ -1,7 +1,8 @@
1/* Copyright 2015 Canonical Ltd. This software is licensed under the1/* Copyright 2015-2016 Canonical Ltd. This software is licensed under the
2 * GNU Affero General Public License version 3 (see the file LICENSE).2 * GNU Affero General Public License version 3 (see the file LICENSE).
3 *3 *
4 * Control enabling/disabling form elements on the Snap:+edit page.4 * Control enabling/disabling form elements on the {Branch,GitRef}:+new-snap
5 * and Snap:+edit pages.
5 *6 *
6 * @module Y.lp.snappy.snap.edit7 * @module Y.lp.snappy.snap.edit
7 * @requires node, DOM8 * @requires node, DOM
@@ -12,7 +13,9 @@
1213
13 module.set_enabled = function(field_id, is_enabled) {14 module.set_enabled = function(field_id, is_enabled) {
14 var field = Y.DOM.byId(field_id);15 var field = Y.DOM.byId(field_id);
15 field.disabled = !is_enabled;16 if (field !== null) {
17 field.disabled = !is_enabled;
18 }
16 };19 };
1720
18 module.onclick_vcs = function(e) {21 module.onclick_vcs = function(e) {
@@ -22,15 +25,31 @@
22 selected_vcs = node.get('value');25 selected_vcs = node.get('value');
23 }26 }
24 });27 });
25 module.set_enabled('field.branch', selected_vcs === 'BZR');28 if (selected_vcs !== null) {
26 module.set_enabled('field.git_ref.repository', selected_vcs === 'GIT');29 module.set_enabled('field.branch', selected_vcs === 'BZR');
27 module.set_enabled('field.git_ref.path', selected_vcs === 'GIT');30 module.set_enabled(
31 'field.git_ref.repository', selected_vcs === 'GIT');
32 module.set_enabled('field.git_ref.path', selected_vcs === 'GIT');
33 }
34 };
35
36 module.onclick_auto_build = function(e) {
37 var auto_build = Y.one(
38 'input[name="field.auto_build"]').get('checked');
39 module.set_enabled(
40 'field.auto_build_archive.option.primary', auto_build);
41 module.set_enabled('field.auto_build_archive.option.ppa', auto_build);
42 module.set_enabled('field.auto_build_archive.ppa', auto_build);
43 module.set_enabled('field.auto_build_pocket', auto_build);
28 };44 };
2945
30 module.setup = function() {46 module.setup = function() {
31 Y.all('input[name="field.vcs"]').on('click', module.onclick_vcs);47 Y.all('input[name="field.vcs"]').on('click', module.onclick_vcs);
48 Y.all('input[name="field.auto_build"]').on(
49 'click', module.onclick_auto_build);
3250
33 // Set the initial state.51 // Set the initial state.
34 module.onclick_vcs();52 module.onclick_vcs();
53 module.onclick_auto_build();
35 };54 };
36}, '0.1', {'requires': ['node', 'DOM']});55}, '0.1', {'requires': ['node', 'DOM']});
3756
=== modified file 'lib/lp/snappy/javascript/tests/test_snap.edit.html'
--- lib/lp/snappy/javascript/tests/test_snap.edit.html 2015-09-09 14:17:46 +0000
+++ lib/lp/snappy/javascript/tests/test_snap.edit.html 2016-07-12 13:40:07 +0000
@@ -1,6 +1,6 @@
1<!DOCTYPE html>1<!DOCTYPE html>
2<!--2<!--
3Copyright 2015 Canonical Ltd. This software is licensed under the3Copyright 2015-2016 Canonical Ltd. This software is licensed under the
4GNU Affero General Public License version 3 (see the file LICENSE).4GNU Affero General Public License version 3 (see the file LICENSE).
5-->5-->
66
@@ -133,6 +133,95 @@
133 </div>133 </div>
134 </td>134 </td>
135 </tr>135 </tr>
136 <tr>
137 <td colspan="2">
138 <div>
139 <label for="field.auto_build">Automatically build when branch changes</label>
140 <input class="checkboxType"
141 id="field.auto_build"
142 name="field.auto_build"
143 type="checkbox"
144 value="" />
145 </div>
146 </td>
147 </tr>
148 <tr>
149 <td>
150 <table class="subordinate">
151 <tr>
152 <td colspan="2">
153 <div>
154 <label for="field.auto_build_archive">Source archive for automatic builds:</label>
155 <div>
156 <table>
157 <tr>
158 <td colspan="2">
159 <label>
160 <input class="radioType"
161 id="field.auto_build_archive.option.primary"
162 name="field.auto_build_archive"
163 type="radio"
164 value="primary" />
165 Primary Archive for Ubuntu
166 </label>
167 </td>
168 </tr>
169 <tr>
170 <td>
171 <label>
172 <input class="radioType"
173 id="field.auto_build_archive.option.ppa"
174 name="field.auto_build_archive"
175 type="radio"
176 value="ppa" />
177 PPA
178 </label>
179 </td>
180 <td>
181 <input type="text"
182 value=""
183 id="field.auto_build_archive.ppa"
184 name="field.auto_build_archive.ppa"
185 size="20"
186 maxlength=""
187 onKeyPress=""
188 style=""
189 class="" />
190 </td>
191 </tr>
192 </table>
193 </div>
194 </div>
195 </td>
196 </tr>
197 <tr>
198 <td colspan="2">
199 <div>
200 <label for="field.auto_build_pocket">Pocket for automatic builds:</label>
201 <div>
202 <div>
203 <div class="value">
204 <select id="field.auto_build_pocket"
205 name="field.auto_build_pocket"
206 size="1">
207 <option value="RELEASE">Release</option>
208 <option value="SECURITY">Security</option>
209 <option selected="selected" value="UPDATES">Updates</option>
210 <option value="PROPOSED">Proposed</option>
211 <option value="BACKPORTS">Backports</option>
212 </select>
213 </div>
214 <input name="field.auto_build_pocket-empty-marker"
215 type="hidden"
216 value="1" />
217 </div>
218 </div>
219 </div>
220 </td>
221 </tr>
222 </table>
223 </td>
224 </tr>
136 </table>225 </table>
137226
138 <input type="submit" id="field.actions.update"227 <input type="submit" id="field.actions.update"
139228
=== modified file 'lib/lp/snappy/javascript/tests/test_snap.edit.js'
--- lib/lp/snappy/javascript/tests/test_snap.edit.js 2015-09-09 14:17:46 +0000
+++ lib/lp/snappy/javascript/tests/test_snap.edit.js 2016-07-12 13:40:07 +0000
@@ -1,4 +1,4 @@
1/* Copyright 2015 Canonical Ltd. This software is licensed under the1/* Copyright 2015-2016 Canonical Ltd. This software is licensed under the
2 * GNU Affero General Public License version 3 (see the file LICENSE).2 * GNU Affero General Public License version 3 (see the file LICENSE).
3 *3 *
4 * Test driver for snap.edit.js.4 * Test driver for snap.edit.js.
@@ -14,9 +14,10 @@
14 setUp: function() {14 setUp: function() {
15 this.tbody = Y.one('#snap.edit');15 this.tbody = Y.one('#snap.edit');
1616
17 // Get the individual VCS type radio buttons.17 // Get the widgets with event handlers attached.
18 this.vcs_bzr = Y.DOM.byId('field.vcs.Bazaar');18 this.vcs_bzr = Y.DOM.byId('field.vcs.Bazaar');
19 this.vcs_git = Y.DOM.byId('field.vcs.Git');19 this.vcs_git = Y.DOM.byId('field.vcs.Git');
20 this.auto_build = Y.DOM.byId('field.auto_build');
2021
21 // Get the input widgets.22 // Get the input widgets.
22 this.input_branch = Y.DOM.byId('field.branch');23 this.input_branch = Y.DOM.byId('field.branch');
@@ -45,6 +46,7 @@
4546
46 check_handler(this.vcs_bzr, module.onclick_vcs);47 check_handler(this.vcs_bzr, module.onclick_vcs);
47 check_handler(this.vcs_git, module.onclick_vcs);48 check_handler(this.vcs_git, module.onclick_vcs);
49 check_handler(this.auto_build, module.onclick_auto_build);
48 },50 },
4951
50 test_select_vcs_bzr: function() {52 test_select_vcs_bzr: function() {
@@ -73,7 +75,38 @@
73 'git_ref.repository field disabled');75 'git_ref.repository field disabled');
74 Y.Assert.isFalse(this.input_git_path.disabled,76 Y.Assert.isFalse(this.input_git_path.disabled,
75 'git_ref.path field disabled');77 'git_ref.path field disabled');
78 },
79
80 test_check_auto_build: function() {
81 var fields = [
82 'auto_build_archive.option.primary',
83 'auto_build_archive.option.ppa',
84 'auto_build_archive.ppa',
85 'auto_build_pocket'
86 ];
87 var field;
88 module.setup();
89 for (i = 0; i < fields.length; i++) {
90 field = Y.DOM.byId('field.' + fields[i]);
91 Y.Assert.isTrue(
92 field.disabled, fields[i] + ' field not disabled');
93 }
94 this.auto_build.checked = true;
95 module.onclick_auto_build();
96 for (i = 0; i < fields.length; i++) {
97 field = Y.DOM.byId('field.' + fields[i]);
98 Y.Assert.isFalse(
99 field.disabled, fields[i] + ' field disabled');
100 }
101 this.auto_build.checked = false;
102 module.onclick_auto_build();
103 for (i = 0; i < fields.length; i++) {
104 field = Y.DOM.byId('field.' + fields[i]);
105 Y.Assert.isTrue(
106 field.disabled, fields[i] + ' field not disabled');
107 }
76 }108 }
109
77 }));110 }));
78}, '0.1', {111}, '0.1', {
79 requires: ['lp.testing.runner', 'test', 'test-console',112 requires: ['lp.testing.runner', 'test', 'test-console',
80113
=== modified file 'lib/lp/snappy/templates/snap-edit.pt'
--- lib/lp/snappy/templates/snap-edit.pt 2016-05-24 05:15:50 +0000
+++ lib/lp/snappy/templates/snap-edit.pt 2016-07-12 13:40:07 +0000
@@ -29,24 +29,6 @@
29 <metal:block use-macro="context/@@launchpad_form/widget_row" />29 <metal:block use-macro="context/@@launchpad_form/widget_row" />
30 </tal:widget>30 </tal:widget>
3131
32 <tr tal:condition="view/has_snappy_distro_series">
33 <td>
34 <tal:widget define="widget nocall:view/widgets/store_upload">
35 <metal:block use-macro="context/@@launchpad_form/widget_row" />
36 </tal:widget>
37 <table class="subordinate">
38 <tal:widget define="widget nocall:view/widgets/store_name">
39 <metal:block use-macro="context/@@launchpad_form/widget_row" />
40 </tal:widget>
41 </table>
42 <p class="formHelp">
43 If you change any settings related to automatically uploading
44 builds of this snap to the store, then the login service will
45 prompt you to authorize this request.
46 </p>
47 </td>
48 </tr>
49
50 <tr>32 <tr>
51 <td>33 <td>
52 <div>34 <div>
@@ -78,6 +60,42 @@
78 </td>60 </td>
79 </tr>61 </tr>
8062
63 <tal:widget define="widget nocall:view/widgets/auto_build">
64 <metal:block use-macro="context/@@launchpad_form/widget_row" />
65 </tal:widget>
66 <tr>
67 <td>
68 <table class="subordinate">
69 <tal:widget define="widget nocall:view/widgets/auto_build_archive">
70 <metal:block use-macro="context/@@launchpad_form/widget_row" />
71 </tal:widget>
72 <tal:widget define="widget nocall:view/widgets/auto_build_pocket">
73 <metal:block use-macro="context/@@launchpad_form/widget_row" />
74 </tal:widget>
75 </table>
76 </td>
77 </tr>
78
79 <tal:has-sds tal:condition="view/has_snappy_distro_series">
80 <tal:widget define="widget nocall:view/widgets/store_upload">
81 <metal:block use-macro="context/@@launchpad_form/widget_row" />
82 </tal:widget>
83 <tr>
84 <td>
85 <table class="subordinate">
86 <tal:widget define="widget nocall:view/widgets/store_name">
87 <metal:block use-macro="context/@@launchpad_form/widget_row" />
88 </tal:widget>
89 </table>
90 <p class="formHelp">
91 If you change any settings related to automatically uploading
92 builds of this snap to the store, then the login service will
93 prompt you to authorize this request.
94 </p>
95 </td>
96 </tr>
97 </tal:has-sds>
98
81 <tal:widget define="widget nocall:view/widgets/processors">99 <tal:widget define="widget nocall:view/widgets/processors">
82 <metal:block use-macro="context/@@launchpad_form/widget_row" />100 <metal:block use-macro="context/@@launchpad_form/widget_row" />
83 </tal:widget>101 </tal:widget>
84102
=== modified file 'lib/lp/snappy/templates/snap-index.pt'
--- lib/lp/snappy/templates/snap-index.pt 2016-05-28 00:21:40 +0000
+++ lib/lp/snappy/templates/snap-index.pt 2016-07-12 13:40:07 +0000
@@ -61,6 +61,31 @@
61 <a tal:replace="structure view/menu:overview/edit/fmt:icon"/>61 <a tal:replace="structure view/menu:overview/edit/fmt:icon"/>
62 </dd>62 </dd>
63 </dl>63 </dl>
64
65 <dl id="auto_build">
66 <dt>Build schedule:
67 <a href="/+help-snappy/snap-build-frequency.html" target="help"
68 class="sprite maybe action-icon">(?)</a>
69 </dt>
70 <dd>
71 <span tal:replace="view/build_frequency"/>
72 <a tal:replace="structure view/menu:overview/edit/fmt:icon"/>
73 </dd>
74 </dl>
75 <dl id="auto_build_archive">
76 <dt>Source archive for automatic builds:</dt>
77 <dd>
78 <a tal:replace="structure context/auto_build_archive/fmt:link"/>
79 <a tal:replace="structure view/menu:overview/edit/fmt:icon"/>
80 </dd>
81 </dl>
82 <dl id="auto_build_pocket">
83 <dt>Pocket for automatic builds:</dt>
84 <dd>
85 <span tal:replace="context/auto_build_pocket/title|nothing"/>
86 <a tal:replace="structure view/menu:overview/edit/fmt:icon"/>
87 </dd>
88 </dl>
64 </div>89 </div>
6590
66 <div id="store_upload" class="two-column-list"91 <div id="store_upload" class="two-column-list"
6792
=== modified file 'lib/lp/snappy/templates/snap-new.pt'
--- lib/lp/snappy/templates/snap-new.pt 2016-06-30 19:19:20 +0000
+++ lib/lp/snappy/templates/snap-new.pt 2016-07-12 13:40:07 +0000
@@ -35,26 +35,52 @@
35 <metal:block use-macro="context/@@launchpad_form/widget_row" />35 <metal:block use-macro="context/@@launchpad_form/widget_row" />
36 </tal:widget>36 </tal:widget>
3737
38 <tr tal:condition="view/has_snappy_distro_series">38 <tal:widget define="widget nocall:view/widgets/auto_build">
39 <metal:block use-macro="context/@@launchpad_form/widget_row" />
40 </tal:widget>
41 <tr>
39 <td>42 <td>
40 <tal:widget define="widget nocall:view/widgets/store_upload">
41 <metal:block use-macro="context/@@launchpad_form/widget_row" />
42 </tal:widget>
43 <table class="subordinate">43 <table class="subordinate">
44 <tal:widget define="widget nocall:view/widgets/store_name">44 <tal:widget define="widget nocall:view/widgets/auto_build_archive">
45 <metal:block use-macro="context/@@launchpad_form/widget_row" />
46 </tal:widget>
47 <tal:widget define="widget nocall:view/widgets/auto_build_pocket">
45 <metal:block use-macro="context/@@launchpad_form/widget_row" />48 <metal:block use-macro="context/@@launchpad_form/widget_row" />
46 </tal:widget>49 </tal:widget>
47 </table>50 </table>
48 <p class="formHelp">
49 If you ask Launchpad to automatically upload builds of this
50 snap to the store on your behalf, then the login service
51 will prompt you to authorize this request.
52 </p>
53 </td>51 </td>
54 </tr>52 </tr>
53
54 <tal:has-sds condition="view/has_snappy_distro_series">
55 <tal:widget define="widget nocall:view/widgets/store_upload">
56 <metal:block use-macro="context/@@launchpad_form/widget_row" />
57 </tal:widget>
58 <tr>
59 <td>
60 <table class="subordinate">
61 <tal:widget define="widget nocall:view/widgets/store_name">
62 <metal:block use-macro="context/@@launchpad_form/widget_row" />
63 </tal:widget>
64 </table>
65 <p class="formHelp">
66 If you ask Launchpad to automatically upload builds of this
67 snap to the store on your behalf, then the login service
68 will prompt you to authorize this request.
69 </p>
70 </td>
71 </tr>
72 </tal:has-sds>
55 </table>73 </table>
56 </metal:formbody>74 </metal:formbody>
57 </div>75 </div>
76
77 <script type="text/javascript">
78 LPJS.use('lp.snappy.snap.edit', function(Y) {
79 Y.on('domready', function(e) {
80 Y.lp.snappy.snap.edit.setup();
81 }, window);
82 });
83 </script>
58</div>84</div>
5985
60</body>86</body>