← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jelmer/launchpad/bzr-code-imports-ui into lp:launchpad/db-devel

 

Jelmer Vernooij has proposed merging lp:~jelmer/launchpad/bzr-code-imports-ui into lp:launchpad/db-devel with lp:~jelmer/launchpad/bzr-code-imports as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #611837 in Launchpad itself: "Confusions between import and mirror branches"
  https://bugs.launchpad.net/launchpad/+bug/611837

For more details, see:
https://code.launchpad.net/~jelmer/launchpad/bzr-code-imports-ui/+merge/65684

Make it possible to create new Bazaar code imports in the code import UI, disable the ability to create mirror branches.

This removes the user-visible distinction between code imports (syncing from remote non-bzr branches) and mirrors (syncing from remote bzr branches), which should make the UI a bit easier to comprehend.

This doesn't migrate any of the existing mirror branches to be code imports, but that would be the next logical step.
-- 
https://code.launchpad.net/~jelmer/launchpad/bzr-code-imports-ui/+merge/65684
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jelmer/launchpad/bzr-code-imports-ui into lp:launchpad/db-devel.
=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py	2011-06-23 15:16:12 +0000
+++ lib/lp/code/browser/branch.py	2011-06-23 15:16:15 +0000
@@ -1121,15 +1121,12 @@
 
     class schema(Interface):
         use_template(
-            IBranch, include=['owner', 'name', 'url', 'lifecycle_status'])
-        branch_type = copy_field(
-            IBranch['branch_type'], vocabulary=UICreatableBranchType)
+            IBranch, include=['owner', 'name', 'lifecycle_status'])
 
     for_input = True
-    field_names = ['owner', 'name', 'branch_type', 'url', 'lifecycle_status']
+    field_names = ['owner', 'name', 'lifecycle_status']
 
     branch = None
-    custom_widget('branch_type', LaunchpadRadioWidgetWithDescription)
     custom_widget('lifecycle_status', LaunchpadRadioWidgetWithDescription)
 
     initial_focus_widget = 'name'
@@ -1158,27 +1155,17 @@
         """
         return IPerson(self.context, self.user)
 
-    def showOptionalMarker(self, field_name):
-        """Don't show the optional marker for url."""
-        if field_name == 'url':
-            return False
-        else:
-            return LaunchpadFormView.showOptionalMarker(self, field_name)
-
     @action('Register Branch', name='add')
     def add_action(self, action, data):
         """Handle a request to create a new branch for this product."""
         try:
-            ui_branch_type = data['branch_type']
             namespace = self.target.getNamespace(data['owner'])
             self.branch = namespace.createBranch(
-                branch_type=BranchType.items[ui_branch_type.name],
+                branch_type=BranchType.HOSTED,
                 name=data['name'],
                 registrant=self.user,
-                url=data.get('url'),
+                url=None,
                 lifecycle_status=data['lifecycle_status'])
-            if self.branch.branch_type == BranchType.MIRRORED:
-                self.branch.requestMirror()
         except BranchCreationForbidden:
             self.addError(
                 "You are not allowed to create branches in %s." %
@@ -1196,36 +1183,6 @@
                 'owner',
                 'You are not a member of %s' % owner.displayname)
 
-        branch_type = data.get('branch_type')
-        # If branch_type failed to validate, then the rest of the method
-        # doesn't make any sense.
-        if branch_type is None:
-            return
-
-        # If the branch is a MIRRORED branch, then the url
-        # must be supplied, and if HOSTED the url must *not*
-        # be supplied.
-        url = data.get('url')
-        if branch_type == UICreatableBranchType.MIRRORED:
-            if url is None:
-                # If the url is not set due to url validation errors,
-                # there will be an error set for it.
-                error = self.getFieldError('url')
-                if not error:
-                    self.setFieldError(
-                        'url',
-                        'Branch URLs are required for Mirrored branches.')
-        elif branch_type == UICreatableBranchType.HOSTED:
-            if url is not None:
-                self.setFieldError(
-                    'url',
-                    'Branch URLs cannot be set for Hosted branches.')
-        elif branch_type == UICreatableBranchType.REMOTE:
-            # A remote location can, but doesn't have to be set.
-            pass
-        else:
-            raise AssertionError('Unknown branch type')
-
     @property
     def cancel_url(self):
         return canonical_url(self.context)

=== modified file 'lib/lp/code/browser/codeimport.py'
--- lib/lp/code/browser/codeimport.py	2011-05-27 21:12:25 +0000
+++ lib/lp/code/browser/codeimport.py	2011-06-23 15:16:15 +0000
@@ -271,6 +271,16 @@
         allow_fragment=False, # Fragment makes no sense in Mercurial
         trailing_slash=False) # See http://launchpad.net/bugs/56357.
 
+    bzr_branch_url = URIField(
+        title=_("Bazaar branch URL"), required=False,
+        description=_("The URL of the Bazaar branch."),
+        allowed_schemes=["http", "https", "bzr"],
+        allow_userinfo=False, # Only anonymous access is supported.
+        allow_port=True,
+        allow_query=False,    # Query makes no sense in Mercurial
+        allow_fragment=False, # Fragment makes no sense in Mercurial
+        trailing_slash=False)
+
     branch_name = copy_field(
         IBranch['name'],
         __name__='branch_name',
@@ -346,9 +356,9 @@
         # display them separately in the form.
         soup = BeautifulSoup(self.widgets['rcs_type']())
         fields = soup.findAll('input')
-        [cvs_button, svn_button, git_button, hg_button, empty_marker] = [
-            field for field in fields
-            if field.get('value') in ['CVS', 'BZR_SVN', 'GIT', 'HG', '1']]
+        [cvs_button, svn_button, git_button, hg_button, bzr_button,
+            empty_marker] = [field for field in fields
+            if field.get('value') in ['CVS', 'BZR_SVN', 'GIT', 'HG', 'BZR', '1']]
         cvs_button['onclick'] = 'updateWidgets()'
         svn_button['onclick'] = 'updateWidgets()'
         git_button['onclick'] = 'updateWidgets()'
@@ -358,6 +368,7 @@
         self.rcs_type_svn = str(svn_button)
         self.rcs_type_git = str(git_button)
         self.rcs_type_hg = str(hg_button)
+        self.rcs_type_bzr = str(bzr_button)
         self.rcs_type_emptymarker = str(empty_marker)
 
     def _getImportLocation(self, data):
@@ -371,6 +382,8 @@
             return None, None, data.get('git_repo_url')
         elif rcs_type == RevisionControlSystems.HG:
             return None, None, data.get('hg_repo_url')
+        elif rcs_type == RevisionControlSystems.BZR:
+            return None, None, data.get('bzr_branch_url')
         else:
             raise AssertionError(
                 'Unexpected revision control type %r.' % rcs_type)
@@ -485,6 +498,9 @@
         elif rcs_type == RevisionControlSystems.HG:
             self._validateURL(
                 data.get('hg_repo_url'), field_name='hg_repo_url')
+        elif rcs_type == RevisionControlSystems.BZR:
+            self._validateURL(
+                data.get('bzr_branch_url'), field_name='bzr_branch_url')
         else:
             raise AssertionError(
                 'Unexpected revision control type %r.' % rcs_type)
@@ -576,7 +592,8 @@
         elif self.code_import.rcs_type in (RevisionControlSystems.SVN,
                                            RevisionControlSystems.BZR_SVN,
                                            RevisionControlSystems.GIT,
-                                           RevisionControlSystems.HG):
+                                           RevisionControlSystems.HG,
+                                           RevisionControlSystems.BZR):
             self.form_fields = self.form_fields.omit(
                 'cvs_root', 'cvs_module')
         else:
@@ -611,7 +628,8 @@
         elif self.code_import.rcs_type in (RevisionControlSystems.SVN,
                                            RevisionControlSystems.BZR_SVN,
                                            RevisionControlSystems.GIT,
-                                           RevisionControlSystems.HG):
+                                           RevisionControlSystems.HG,
+                                           RevisionControlSystems.BZR):
             self._validateURL(data.get('url'), self.code_import)
         else:
             raise AssertionError('Unknown rcs_type for code import.')

=== modified file 'lib/lp/code/browser/tests/test_branch.py'
--- lib/lp/code/browser/tests/test_branch.py	2011-05-16 03:46:33 +0000
+++ lib/lp/code/browser/tests/test_branch.py	2011-06-23 15:16:15 +0000
@@ -190,8 +190,8 @@
             "This is a short error message.",
             branch_view.mirror_status_message)
 
-    def testBranchAddRequestsMirror(self):
-        """Registering a mirrored branch requests a mirror."""
+    def testBranchAddRequests(self):
+        """Registering a branch that requests a mirror."""
         arbitrary_person = self.factory.makePerson()
         arbitrary_product = self.factory.makeProduct()
         login_person(arbitrary_person)
@@ -199,9 +199,8 @@
             add_view = BranchAddView(arbitrary_person, self.request)
             add_view.initialize()
             data = {
-                'branch_type': BranchType.MIRRORED,
+                'branch_type': BranchType.HOSTED,
                 'name': 'some-branch',
-                'url': 'http://example.com',
                 'title': 'Branch Title',
                 'summary': '',
                 'lifecycle_status': BranchLifecycleStatus.DEVELOPMENT,

=== modified file 'lib/lp/code/doc/codeimport.txt'
--- lib/lp/code/doc/codeimport.txt	2011-05-27 19:53:20 +0000
+++ lib/lp/code/doc/codeimport.txt	2011-06-23 15:16:15 +0000
@@ -62,6 +62,7 @@
     Subversion via bzr-svn
     Git
     Mercurial
+    Bazaar
 
 
 Import from CVS

=== modified file 'lib/lp/code/enums.py'
--- lib/lp/code/enums.py	2011-06-23 15:16:12 +0000
+++ lib/lp/code/enums.py	2011-06-23 15:16:15 +0000
@@ -99,8 +99,8 @@
     IMPORTED = DBItem(3, """
         Imported
 
-        Branches that have been converted from some other revision
-        control system into bzr and are made available through Launchpad.
+        Branches that have been imported from an externally hosted
+        branch in bzr or another VCS and are made available through Launchpad.
         """)
 
     REMOTE = DBItem(4, """

=== modified file 'lib/lp/code/model/codeimport.py'
--- lib/lp/code/model/codeimport.py	2011-06-23 15:16:12 +0000
+++ lib/lp/code/model/codeimport.py	2011-06-23 15:16:15 +0000
@@ -266,7 +266,8 @@
         if review_status is None:
             # Auto approve git and hg imports.
             if rcs_type in (
-                RevisionControlSystems.GIT, RevisionControlSystems.HG):
+                RevisionControlSystems.GIT, RevisionControlSystems.HG,
+                RevisionControlSystems.BZR):
                 review_status = CodeImportReviewStatus.REVIEWED
             else:
                 review_status = CodeImportReviewStatus.NEW

=== modified file 'lib/lp/code/templates/branch-form-macros.pt'
--- lib/lp/code/templates/branch-form-macros.pt	2009-10-02 15:02:23 +0000
+++ lib/lp/code/templates/branch-form-macros.pt	2011-06-23 15:16:15 +0000
@@ -17,20 +17,6 @@
 
 <script type="text/javascript">
 //<![CDATA[
-function update_branch_url()
-{
-  var branch_type_field = document.getElementsByName('field.branch_type')
-  var form = branch_type_field[0].form;
-  var branch_type = 'None';
-  for (var i = 0; i < branch_type_field.length; i++) {
-    if (branch_type_field[i].checked) {
-      branch_type = branch_type_field[i].value;
-      break;
-    }
-  }
-  updateField(form['field.url'], branch_type != 'HOSTED');
-}
-
 function update_branch_unique_name()
 {
   var unique_name = document.getElementById("branch-unique-name")
@@ -43,44 +29,16 @@
   unique_name.innerHTML = branch_name
 }
 
-function populate_branch_name_from_url()
-{
-   url_field = document.getElementById('field.url');
-   var url_text = trim(url_field.value);
-   // strip of any trailing slashes
-   url_text = url_text.replace(/\/+$/, '')
-   if (url_text != url_field.value) {
-      url_field.value = url_text;
-   }
-   var name_field = document.getElementById('field.name');
-   if (name_field.value == '')
-   {
-      // parse the value of the url field
-      url_bits = url_text.split('/');
-      if (url_bits.length > 2) {
-         // attempt at not barfing on something completely invalid
-         last_bit = url_bits[url_bits.length - 1];
-         name_field.value = last_bit;
-      }
-   }
-}
-
 function hookUpBranchFieldFunctions()
 {
   connect('field.owner', 'onkeyup', update_branch_unique_name);
   connect('field.owner', 'onchange', update_branch_unique_name);
   connect('field.name', 'onkeyup', update_branch_unique_name);
-  connect('field.branch_type.0', 'onclick', update_branch_url);
-  connect('field.branch_type.1', 'onclick', update_branch_url);
-  connect('field.branch_type.2', 'onclick', update_branch_url);
   update_branch_unique_name();
-  connect('field.url', 'onchange', populate_branch_name_from_url);
-  connect('field.url', 'onblur', populate_branch_name_from_url);
   document.getElementById("branch-unique-name-div").style.display = "block";
 }
 
 registerLaunchpadFunction(hookUpBranchFieldFunctions);
-registerLaunchpadFunction(update_branch_url);
 
 //]]>
 </script>

=== modified file 'lib/lp/code/templates/branch-import-details.pt'
--- lib/lp/code/templates/branch-import-details.pt	2010-06-10 07:54:59 +0000
+++ lib/lp/code/templates/branch-import-details.pt	2011-06-23 15:16:15 +0000
@@ -51,6 +51,12 @@
           </p>
         </tal:hg-import>
 
+        <tal:bzr-import condition="code_import/rcs_type/enumvalue:BZR">
+          <p>This branch is an import of the Bazaar branch at
+            <span tal:replace="code_import/url" />.
+          </p>
+        </tal:bzr-import>
+
         <tal:svn-import condition="view/is_svn_import">
           <p id="svn-import-details">
             This branch is an import of the

=== modified file 'lib/lp/code/templates/codeimport-new.pt'
--- lib/lp/code/templates/codeimport-new.pt	2010-04-22 23:50:51 +0000
+++ lib/lp/code/templates/codeimport-new.pt	2011-06-23 15:16:15 +0000
@@ -53,6 +53,20 @@
         <tr>
           <td>
             <label>
+              <input tal:replace="structure view/rcs_type_bzr" />
+              Bazaar
+            </label>
+            <table class="importdetails">
+              <tal:widget define="widget nocall:view/widgets/bzr_branch_url">
+                <metal:block use-macro="context/@@launchpad_form/widget_row" />
+              </tal:widget>
+            </table>
+          </td>
+        </tr>
+
+        <tr>
+          <td>
+            <label>
               <input tal:replace="structure view/rcs_type_git" />
               Git
             </label>

=== modified file 'lib/lp/registry/browser/productseries.py'
--- lib/lp/registry/browser/productseries.py	2011-06-23 15:16:12 +0000
+++ lib/lp/registry/browser/productseries.py	2011-06-23 15:16:15 +0000
@@ -1090,8 +1090,7 @@
 
             # Create a new branch.
             if branch_type == CREATE_NEW:
-                branch = self._createBzrBranch(
-                    BranchType.HOSTED, branch_name, branch_owner)
+                branch = self._createBzrBranch(branch_name, branch_owner)
                 if branch is not None:
                     self.context.branch = branch
                     self.request.response.addInfoNotification(
@@ -1102,55 +1101,42 @@
                 # Either create an externally hosted bzr branch
                 # (a.k.a. 'mirrored') or create a new code import.
                 rcs_type = data.get('rcs_type')
-                if rcs_type == RevisionControlSystems.BZR:
-                    branch = self._createBzrBranch(
-                        BranchType.MIRRORED, branch_name, branch_owner,
-                        data['repo_url'])
-                    if branch is None:
-                        return
-
-                    self.context.branch = branch
-                    self.request.response.addInfoNotification(
-                        'Mirrored branch created and linked to '
-                        'the series.')
+                # We need to create an import request.
+                if rcs_type == RevisionControlSystems.CVS:
+                    cvs_root = data.get('repo_url')
+                    cvs_module = data.get('cvs_module')
+                    url = None
                 else:
-                    # We need to create an import request.
-                    if rcs_type == RevisionControlSystems.CVS:
-                        cvs_root = data.get('repo_url')
-                        cvs_module = data.get('cvs_module')
-                        url = None
-                    else:
-                        cvs_root = None
-                        cvs_module = None
-                        url = data.get('repo_url')
-                    rcs_item = RevisionControlSystems.items[rcs_type.name]
-                    try:
-                        code_import = getUtility(ICodeImportSet).new(
-                            registrant=branch_owner,
-                            target=IBranchTarget(self.context.product),
-                            branch_name=branch_name,
-                            rcs_type=rcs_item,
-                            url=url,
-                            cvs_root=cvs_root,
-                            cvs_module=cvs_module)
-                    except BranchExists, e:
-                        self._setBranchExists(e.existing_branch,
-                                              'branch_name')
-                        self.errors_in_action = True
-                        # Abort transaction. This is normally handled
-                        # by LaunchpadFormView, but we are already in
-                        # the success handler.
-                        self._abort()
-                        return
-                    self.context.branch = code_import.branch
-                    self.request.response.addInfoNotification(
-                        'Code import created and branch linked to the '
-                        'series.')
+                    cvs_root = None
+                    cvs_module = None
+                    url = data.get('repo_url')
+                rcs_item = RevisionControlSystems.items[rcs_type.name]
+                try:
+                    code_import = getUtility(ICodeImportSet).new(
+                        registrant=branch_owner,
+                        target=IBranchTarget(self.context.product),
+                        branch_name=branch_name,
+                        rcs_type=rcs_item,
+                        url=url,
+                        cvs_root=cvs_root,
+                        cvs_module=cvs_module)
+                except BranchExists, e:
+                    self._setBranchExists(e.existing_branch,
+                                          'branch_name')
+                    self.errors_in_action = True
+                    # Abort transaction. This is normally handled
+                    # by LaunchpadFormView, but we are already in
+                    # the success handler.
+                    self._abort()
+                    return
+                self.context.branch = code_import.branch
+                self.request.response.addInfoNotification(
+                    'Code import created and branch linked to the '
+                    'series.')
             else:
                 raise UnexpectedFormData(branch_type)
 
-    def _createBzrBranch(self, branch_type, branch_name,
-                         branch_owner, repo_url=None):
+    def _createBzrBranch(self, branch_name, branch_owner, repo_url=None):
         """Create a new Bazaar branch.  It may be hosted or mirrored.
 
         Return the branch on success or None.
@@ -1158,12 +1144,10 @@
         branch = None
         try:
             namespace = self.target.getNamespace(branch_owner)
-            branch = namespace.createBranch(branch_type=branch_type,
+            branch = namespace.createBranch(branch_type=BranchType.HOSTED,
                                             name=branch_name,
                                             registrant=self.user,
                                             url=repo_url)
-            if branch_type == BranchType.MIRRORED:
-                branch.requestMirror()
         except BranchCreationForbidden:
             self.addError(
                 "You are not allowed to create branches in %s." %

=== modified file 'lib/lp/registry/templates/productseries-codesummary.pt'
--- lib/lp/registry/templates/productseries-codesummary.pt	2011-05-16 20:55:08 +0000
+++ lib/lp/registry/templates/productseries-codesummary.pt	2011-06-23 15:16:15 +0000
@@ -54,7 +54,7 @@
         </li>
 
         <li>
-          If the code is in Git, Mercurial, CVS or Subversion you can
+          If the code is in Git, Mercurial, CVS, Subversion or an external Bazaar branch you can
           <a tal:attributes="href view/request_import_link">request that the branch be imported to Bazaar</a>.
         </li>
       </ul>


Follow ups