Merge lp:~james-w/launchpad/export-code-import into lp:launchpad

Proposed by James Westby
Status: Merged
Approved by: Tim Penhey
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~james-w/launchpad/export-code-import
Merge into: lp:launchpad
Diff against target: 330 lines (+142/-45)
11 files modified
lib/canonical/launchpad/doc/canonical_url_examples.txt (+10/-0)
lib/canonical/launchpad/interfaces/_schema_circular_imports.py (+2/-0)
lib/lp/code/browser/branch.py (+5/-0)
lib/lp/code/browser/codeimport.py (+3/-3)
lib/lp/code/browser/configure.zcml (+5/-0)
lib/lp/code/doc/codeimport.txt (+4/-4)
lib/lp/code/interfaces/branch.py (+4/-2)
lib/lp/code/interfaces/codeimport.py (+48/-36)
lib/lp/code/interfaces/webservice.py (+1/-0)
lib/lp/code/stories/webservice/xx-branch.txt (+1/-0)
lib/lp/code/stories/webservice/xx-code-import.txt (+59/-0)
To merge this branch: bzr merge lp:~james-w/launchpad/export-code-import
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Review via email: mp+21472@code.launchpad.net

Commit message

Expose the main code import attributes read only.

Description of the change

This exports ICodeImport.

It's not intended to be all-singing, all-dancing, just export
the objects, we can do more in future branches.

Thanks,

James

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

I think this is a great start.

review: Approve
Revision history for this message
Francis J. Lacoste (flacoste) wrote :

On March 16, 2010, James Westby wrote:
 + owner = exported(
> + PublicPersonChoice(
> + title=_('Owner'), required=True, readonly=False,
> + vocabulary='ValidPersonOrTeam',
> + description=_("The community contact for this import.")))
>

> + review_status = exported(
> + Choice(
> + title=_("Review Status"), vocabulary=CodeImportReviewStatus,
> + default=CodeImportReviewStatus.NEW,
> + description=_("Before a code import is performed, it is
> reviewed." + " Only reviewed imports are processed.")))
> +

Do we know if the security wrapper were properly defined for the exported field?

> + date_last_successful = exported(
> + Datetime(title=_("Last successful"), required=False))
>

This should probably be a readonly field?

--
Francis J. Lacoste
<email address hidden>

Revision history for this message
James Westby (james-w) wrote :

> On March 16, 2010, James Westby wrote:
> + owner = exported(
> > + PublicPersonChoice(
> > + title=_('Owner'), required=True, readonly=False,
> > + vocabulary='ValidPersonOrTeam',
> > + description=_("The community contact for this import.")))
> >
>
> > + review_status = exported(
> > + Choice(
> > + title=_("Review Status"), vocabulary=CodeImportReviewStatus,
> > + default=CodeImportReviewStatus.NEW,
> > + description=_("Before a code import is performed, it is
> > reviewed." + " Only reviewed imports are processed.")))
> > +
>
> Do we know if the security wrapper were properly defined for the exported
> field?

I don't know what that means, so probably not.

> > + date_last_successful = exported(
> > + Datetime(title=_("Last successful"), required=False))
> >
>
> This should probably be a readonly field?

It is in the latest diff.

Thanks,

James

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/doc/canonical_url_examples.txt'
--- lib/canonical/launchpad/doc/canonical_url_examples.txt 2010-03-12 18:28:28 +0000
+++ lib/canonical/launchpad/doc/canonical_url_examples.txt 2010-03-17 21:52:39 +0000
@@ -356,6 +356,16 @@
356 http://code.launchpad.dev/~name12/gnome-terminal/main/+merge/.../comments/...356 http://code.launchpad.dev/~name12/gnome-terminal/main/+merge/.../comments/...
357357
358358
359== Code Imports ==
360
361Code imports have a canonical URL which is a subordinate of the branch
362that they import to.
363
364 >>> from lp.code.interfaces.codeimport import ICodeImportSet
365 >>> code_import = getUtility(ICodeImportSet).get(1)
366 >>> print canonical_url(code_import)
367 http://code.launchpad.dev/~vcs-imports/gnome-terminal/import/+code-import
368
359== Specifications ==369== Specifications ==
360370
361 >>> from canonical.launchpad.interfaces import ISpecificationSet371 >>> from canonical.launchpad.interfaces import ISpecificationSet
362372
=== modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py'
--- lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-03-16 05:09:55 +0000
+++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-03-17 21:52:39 +0000
@@ -40,6 +40,7 @@
40from lp.code.interfaces.branch import IBranch40from lp.code.interfaces.branch import IBranch
41from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal41from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
42from lp.code.interfaces.branchsubscription import IBranchSubscription42from lp.code.interfaces.branchsubscription import IBranchSubscription
43from lp.code.interfaces.codeimport import ICodeImport
43from lp.code.interfaces.codereviewcomment import ICodeReviewComment44from lp.code.interfaces.codereviewcomment import ICodeReviewComment
44from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference45from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
45from lp.code.interfaces.diff import IPreviewDiff46from lp.code.interfaces.diff import IPreviewDiff
@@ -95,6 +96,7 @@
95patch_plain_parameter_type(96patch_plain_parameter_type(
96 IBranch, 'setTarget', 'source_package', ISourcePackage)97 IBranch, 'setTarget', 'source_package', ISourcePackage)
97patch_reference_property(IBranch, 'sourcepackage', ISourcePackage)98patch_reference_property(IBranch, 'sourcepackage', ISourcePackage)
99patch_reference_property(IBranch, 'code_import', ICodeImport)
98100
99IBranch['spec_links'].value_type.schema = ISpecificationBranch101IBranch['spec_links'].value_type.schema = ISpecificationBranch
100IBranch['subscribe'].queryTaggedValue(102IBranch['subscribe'].queryTaggedValue(
101103
=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py 2010-02-24 13:37:51 +0000
+++ lib/lp/code/browser/branch.py 2010-03-17 21:52:39 +0000
@@ -181,6 +181,11 @@
181 if proposal.id == id:181 if proposal.id == id:
182 return proposal182 return proposal
183183
184 @stepto("+code-import")
185 def traverse_code_import(self):
186 """Traverses to the `ICodeImport` for the branch."""
187 return self.context.code_import
188
184189
185class BranchEditMenu(NavigationMenu):190class BranchEditMenu(NavigationMenu):
186 """Edit menu for IBranch."""191 """Edit menu for IBranch."""
187192
=== modified file 'lib/lp/code/browser/codeimport.py'
--- lib/lp/code/browser/codeimport.py 2010-03-08 19:27:29 +0000
+++ lib/lp/code/browser/codeimport.py 2010-03-17 21:52:39 +0000
@@ -435,9 +435,9 @@
435class EditCodeImportForm(Interface):435class EditCodeImportForm(Interface):
436 """The fields presented on the form for editing a code import."""436 """The fields presented on the form for editing a code import."""
437437
438 use_template(438 url = copy_field(ICodeImport['url'], readonly=False)
439 ICodeImport,439 cvs_root = copy_field(ICodeImport['cvs_root'], readonly=False)
440 ['url', 'cvs_root', 'cvs_module'])440 cvs_module = copy_field(ICodeImport['cvs_module'], readonly=False)
441 whiteboard = copy_field(IBranch['whiteboard'])441 whiteboard = copy_field(IBranch['whiteboard'])
442442
443443
444444
=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml 2010-03-12 18:28:28 +0000
+++ lib/lp/code/browser/configure.zcml 2010-03-17 21:52:39 +0000
@@ -714,6 +714,11 @@
714 template="../templates/codeimport-new.pt"714 template="../templates/codeimport-new.pt"
715 permission="launchpad.AnyPerson"/>715 permission="launchpad.AnyPerson"/>
716 </facet>716 </facet>
717 <browser:url
718 for="lp.code.interfaces.codeimport.ICodeImport"
719 attribute_to_parent="branch"
720 path_expression="string:+code-import"
721 rootsite="code"/>
717 <browser:navigation722 <browser:navigation
718 module="lp.code.browser.codeimport"723 module="lp.code.browser.codeimport"
719 classes="724 classes="
720725
=== modified file 'lib/lp/code/doc/codeimport.txt'
--- lib/lp/code/doc/codeimport.txt 2010-03-09 12:01:49 +0000
+++ lib/lp/code/doc/codeimport.txt 2010-03-17 21:52:39 +0000
@@ -468,14 +468,14 @@
468 >>> print canonical_url(code_import_set)468 >>> print canonical_url(code_import_set)
469 http://code.launchpad.dev/+code-imports469 http://code.launchpad.dev/+code-imports
470470
471The code imports themselves are viewed under the branch's URL,471The code imports themselves have a canonical URL that is subordinate of
472and are not traversable in themselves.472the branches, though they cannot currently be viewed that way in the webapp,
473only over the API.
473474
474 >>> print canonical_url(svn_import.branch)475 >>> print canonical_url(svn_import.branch)
475 http://code.launchpad.dev/~no-priv/firefox/trunk-svn476 http://code.launchpad.dev/~no-priv/firefox/trunk-svn
476 >>> print canonical_url(svn_import)477 >>> print canonical_url(svn_import)
477 Traceback (most recent call last):478 http://code.launchpad.dev/~no-priv/firefox/trunk-svn/+code-import
478 NoCanonicalUrl: ...
479479
480480
481Modifying CodeImports481Modifying CodeImports
482482
=== modified file 'lib/lp/code/interfaces/branch.py'
--- lib/lp/code/interfaces/branch.py 2010-03-10 18:58:02 +0000
+++ lib/lp/code/interfaces/branch.py 2010-03-17 21:52:39 +0000
@@ -855,8 +855,10 @@
855 browse_source_url = Attribute(855 browse_source_url = Attribute(
856 "The URL of the source browser for this branch.")856 "The URL of the source browser for this branch.")
857857
858 # Don't use Object -- that would cause an import loop with ICodeImport.858 # Really ICodeImport, but that would cause a circular import
859 code_import = Attribute("The associated CodeImport, if any.")859 code_import = exported(
860 Reference(
861 title=_("The associated CodeImport, if any."), schema=Interface))
860862
861 bzr_identity = exported(863 bzr_identity = exported(
862 Text(864 Text(
863865
=== modified file 'lib/lp/code/interfaces/codeimport.py'
--- lib/lp/code/interfaces/codeimport.py 2010-03-05 03:51:59 +0000
+++ lib/lp/code/interfaces/codeimport.py 2010-03-17 21:52:39 +0000
@@ -23,6 +23,9 @@
23from canonical.launchpad.validators import LaunchpadValidationError23from canonical.launchpad.validators import LaunchpadValidationError
24from lp.code.enums import CodeImportReviewStatus, RevisionControlSystems24from lp.code.enums import CodeImportReviewStatus, RevisionControlSystems
2525
26from lazr.restful.declarations import (
27 export_as_webservice_entry, exported)
28
2629
27def validate_cvs_root(cvsroot):30def validate_cvs_root(cvsroot):
28 try:31 try:
@@ -60,13 +63,17 @@
60class ICodeImport(Interface):63class ICodeImport(Interface):
61 """A code import to a Bazaar Branch."""64 """A code import to a Bazaar Branch."""
6265
66 export_as_webservice_entry()
67
63 id = Int(readonly=True, required=True)68 id = Int(readonly=True, required=True)
64 date_created = Datetime(69 date_created = Datetime(
65 title=_("Date Created"), required=True, readonly=True)70 title=_("Date Created"), required=True, readonly=True)
6671
67 branch = Choice(72 branch = exported(
68 title=_('Branch'), required=True, readonly=True, vocabulary='Branch',73 Choice(
69 description=_("The Bazaar branch produced by the import system."))74 title=_('Branch'), required=True, readonly=True,
75 vocabulary='Branch',
76 description=_("The Bazaar branch produced by the import system.")))
7077
71 registrant = PublicPersonChoice(78 registrant = PublicPersonChoice(
72 title=_('Registrant'), required=True, readonly=True,79 title=_('Registrant'), required=True, readonly=True,
@@ -94,39 +101,44 @@
94 description=_("The series this import is registered as the "101 description=_("The series this import is registered as the "
95 "code for, or None if there is no such series."))102 "code for, or None if there is no such series."))
96103
97 review_status = Choice(104 review_status = exported(
98 title=_("Review Status"), vocabulary=CodeImportReviewStatus,105 Choice(
99 default=CodeImportReviewStatus.NEW,106 title=_("Review Status"), vocabulary=CodeImportReviewStatus,
100 description=_("Before a code import is performed, it is reviewed."107 default=CodeImportReviewStatus.NEW, readonly=True,
101 " Only reviewed imports are processed."))108 description=_("Before a code import is performed, it is reviewed."
102109 " Only reviewed imports are processed.")))
103 rcs_type = Choice(title=_("Type of RCS"),110
104 required=True, vocabulary=RevisionControlSystems,111 rcs_type = exported(
105 description=_(112 Choice(title=_("Type of RCS"), readonly=True,
106 "The version control system to import from. "113 required=True, vocabulary=RevisionControlSystems,
107 "Can be CVS or Subversion."))114 description=_(
108115 "The version control system to import from. "
109 url = URIField(title=_("URL"), required=False,116 "Can be CVS or Subversion.")))
110 description=_("The URL of the VCS branch."),117
111 allowed_schemes=["http", "https", "svn", "git"],118 url = exported(
112 allow_userinfo=False, # Only anonymous access is supported.119 URIField(title=_("URL"), required=False, readonly=True,
113 allow_port=True,120 description=_("The URL of the VCS branch."),
114 allow_query=False, # Query makes no sense in Subversion.121 allowed_schemes=["http", "https", "svn", "git"],
115 allow_fragment=False, # Fragment makes no sense in Subversion.122 allow_userinfo=False, # Only anonymous access is supported.
116 trailing_slash=False) # See http://launchpad.net/bugs/56357.123 allow_port=True,
117124 allow_query=False, # Query makes no sense in Subversion.
118 cvs_root = TextLine(title=_("Repository"), required=False,125 allow_fragment=False, # Fragment makes no sense in Subversion.
119 constraint=validate_cvs_root,126 trailing_slash=False)) # See http://launchpad.net/bugs/56357.
120 description=_("The CVSROOT. "127
121 "Example: :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome"))128 cvs_root = exported(
122129 TextLine(title=_("Repository"), required=False, readonly=True,
123 cvs_module = TextLine(title=_("Module"), required=False,130 constraint=validate_cvs_root,
124 constraint=validate_cvs_module,131 description=_("The CVSROOT. "
125 description=_("The path to import within the repository."132 "Example: :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome")))
126 " Usually, it is the name of the project."))133
127134 cvs_module = exported(
128 date_last_successful = Datetime(135 TextLine(title=_("Module"), required=False, readonly=True,
129 title=_("Last successful"), required=False)136 constraint=validate_cvs_module,
137 description=_("The path to import within the repository."
138 " Usually, it is the name of the project.")))
139
140 date_last_successful = exported(
141 Datetime(title=_("Last successful"), required=False, readonly=True))
130142
131 update_interval = Timedelta(143 update_interval = Timedelta(
132 title=_("Update interval"), required=False, description=_(144 title=_("Update interval"), required=False, description=_(
133145
=== modified file 'lib/lp/code/interfaces/webservice.py'
--- lib/lp/code/interfaces/webservice.py 2009-07-17 00:26:05 +0000
+++ lib/lp/code/interfaces/webservice.py 2010-03-17 21:52:39 +0000
@@ -6,6 +6,7 @@
6from lp.code.interfaces.branch import IBranch, IBranchSet6from lp.code.interfaces.branch import IBranch, IBranchSet
7from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal7from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
8from lp.code.interfaces.branchsubscription import IBranchSubscription8from lp.code.interfaces.branchsubscription import IBranchSubscription
9from lp.code.interfaces.codeimport import ICodeImport
9from lp.code.interfaces.codereviewcomment import ICodeReviewComment10from lp.code.interfaces.codereviewcomment import ICodeReviewComment
10from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference11from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
11from lp.code.interfaces.diff import IDiff, IPreviewDiff, IStaticDiff12from lp.code.interfaces.diff import IDiff, IPreviewDiff, IStaticDiff
1213
=== modified file 'lib/lp/code/stories/webservice/xx-branch.txt'
--- lib/lp/code/stories/webservice/xx-branch.txt 2010-02-17 22:34:52 +0000
+++ lib/lp/code/stories/webservice/xx-branch.txt 2010-03-17 21:52:39 +0000
@@ -108,6 +108,7 @@
108 branch_format: None108 branch_format: None
109 branch_type: u'Hosted'109 branch_type: u'Hosted'
110 bzr_identity: u'lp://dev/~eric/fooix/trunk'110 bzr_identity: u'lp://dev/~eric/fooix/trunk'
111 code_import_link: None
111 control_format: None112 control_format: None
112 date_created: u'2009-01-01T00:00:00+00:00'113 date_created: u'2009-01-01T00:00:00+00:00'
113 date_last_modified: u'2009-01-01T00:00:00+00:00'114 date_last_modified: u'2009-01-01T00:00:00+00:00'
114115
=== added file 'lib/lp/code/stories/webservice/xx-code-import.txt'
--- lib/lp/code/stories/webservice/xx-code-import.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/code/stories/webservice/xx-code-import.txt 2010-03-17 21:52:39 +0000
@@ -0,0 +1,59 @@
1Introduction
2============
3
4Launchpad can tell you about the code imports that power a branch
5if it is an import branch.
6
7 >>> from zope.security.proxy import removeSecurityProxy
8
9First we create some objects for use in the tests.
10
11 >>> login(ANONYMOUS)
12 >>> person = factory.makePerson(name='import-owner')
13 >>> product = factory.makeProduct(name='scruff')
14 >>> code_import = removeSecurityProxy(factory.makeCodeImport(
15 ... registrant=person, product=product, branch_name='import'))
16 >>> no_import_branch = removeSecurityProxy(factory.makeProductBranch(
17 ... owner=person, product=product, name='no-import'))
18 >>> logout()
19
20If we query a branch with no import then we find that it tells us
21it doesn't have one.
22
23 >>> branch_url = '/' + no_import_branch.unique_name
24 >>> response = webservice.get(branch_url)
25 >>> representation = response.jsonBody()
26 >>> print representation['code_import_link']
27 None
28
29For a branch with an import we get a link to the import entry in its
30representation.
31
32 >>> branch_url = '/' + code_import.branch.unique_name
33 >>> response = webservice.get(branch_url)
34 >>> representation = response.jsonBody()
35 >>> print representation['code_import_link']
36 http://.../~import-owner/scruff/import/+code-import
37
38We can get some information about the import using this URL.
39
40 >>> import_url = representation['code_import_link']
41 >>> response = webservice.get(import_url)
42 >>> representation = response.jsonBody()
43 >>> print representation['self_link'] == import_url
44 True
45 >>> print representation['branch_link']
46 http://.../~import-owner/scruff/import
47 >>> print representation['review_status']
48 Pending Review
49 >>> print representation['rcs_type']
50 Subversion via CSCVS
51 >>> print representation['url']
52 http://domain9.domain.com/path10
53 >>> print representation['cvs_root']
54 None
55 >>> print representation['cvs_module']
56 None
57 >>> print representation['date_last_successful']
58 None
59