f03e774da875 — Steve Fink 3 years ago
Move some things from using configuration dump to using REST API natively
2 files changed, 45 insertions(+), 54 deletions(-)

M __init__.py
M bz.py
M __init__.py +26 -54
@@ 252,17 252,10 @@ def revset_bzbasechange(repo, subset, x)
     s = revset.baseset(_basechange(repo, s))
     return subset & s
 
-def get_default_version(ui, api_server, product):
-    c = bzauth.load_configuration(ui, api_server, BINARY_CACHE_FILENAME)
-    versions = c['product'].get(product, {}).get('version')
-    if not versions:
-        raise Abort("Product %s has no versions" % product)
-    # Ugh! /configuration returns the versions in sorted order, which makes it
-    # impossible to determine the default. If there's something like
-    # "unspecified" in the list, prefer that for now, until bzapi gets fixed.
-    # https://bugzilla.mozilla.org/show_bug.cgi?id=723170
-    uns = [v for v in versions if v.startswith("un")]
-    return uns[-1] if uns else versions[-1]
+
+def get_default_version(ui, auth, product):
+    p = bz.get_product(auth, product, include_fields=('versions',))
+    return p['versions'][-1]['name']
 
 
 # ui.promptchoice only allows single-character responses and was changed in

          
@@ 811,7 804,7 @@ def guess_prodcomponent(ui, repo, patchd
         # loaded version of mqext does not have guess_components
         return None, None
 
-def choose_prodcomponent(ui, repo, cache, orig_product, orig_component, finalize=False,
+def choose_prodcomponent(ui, repo, auth, orig_product, orig_component, finalize=False,
                          patchdata=None):
     def canon(v):
         if not v or v == '<choose-from-menu>':

          
@@ 821,13 814,17 @@ def choose_prodcomponent(ui, repo, cache
     product = canon(orig_product)
     component = canon(orig_component)
 
-    products_info = cache.get('product', {})
+    raw_products = bz.get_products(auth)
+    products_info = {
+        p['name']: set(c['name'] for c in p['components'])
+        for p in raw_products
+    }
     all_products = products_info.keys()
 
     def products_with_component_match(component):
         return [p
-                for p, v in products_info.items()
-                if len(filter_strings(v['component'].keys(), component)) > 0]
+                for p, all_components in products_info.items()
+                if len(filter_strings(all_components, component)) > 0]
 
     # The product and component may be given as part of component alone, in the
     # format 'product :: component'.

          
@@ 859,12 856,12 @@ def choose_prodcomponent(ui, repo, cache
         products = filter_strings(all_products, product)
 
     for p in products:
-        components.update(products_info[p]['component'].keys())
+        components.update(products_info[p])
     if component is not None:
         components = filter_strings(components, component, drop_lesser=True)
         products = [p
                     for p in products
-                    if len(set(products_info[p]['component'].keys()) & set(components)) > 0]
+                    if len(products_info[p] & set(components)) > 0]
 
     # Now choose a final product::component (unless finalize is false, in which
     # case if there are multiple possibilities, the passed-in value will be

          
@@ 879,7 876,7 @@ def choose_prodcomponent(ui, repo, cache
                                message="Select from these products:",
                                usemenu=finalize)
         if product is not None:
-            prodcomponents = products_info[product]['component'].keys()
+            prodcomponents = products_info[product]
             components = set(components).intersection(prodcomponents)
         else:
             product = orig_product

          
@@ 898,39 895,14 @@ def choose_prodcomponent(ui, repo, cache
     return (product, component)
 
 
-class LazyDict(collections.abc.Mapping):
-    '''Dictionary that calls the given loader function when its contents are accessed.'''
-    def __init__(self, loader):
-        collections.abc.Mapping.__init__(self)
-        self._loader = loader
-        self._data = None
-
-    def data(self):
-        if self._data is None:
-            self._data = self._loader()
-        return self._data
-
-    def __getitem__(self, key):
-        return self.data().__getitem__(key)
-
-    def __iter__(self):
-        return self.data().__iter__()
-
-    def __len__(self):
-        return len(self.data())
-
-
-def fill_values(values, ui, repo, api_server, finalize=False, patchdata=None):
-    # If things are fully specified, the bugzilla configuration info may be unneeded.
-    cache = LazyDict(lambda: bzauth.load_configuration(ui, api_server, BINARY_CACHE_FILENAME))
-
+def fill_values(values, ui, repo, auth, api_server, finalize=False, patchdata=None):
     if 'PRODUCT' in values:
-        values['PRODUCT'], values['COMPONENT'] = choose_prodcomponent(ui, repo, cache, values['PRODUCT'],
+        values['PRODUCT'], values['COMPONENT'] = choose_prodcomponent(ui, repo, auth, values['PRODUCT'],
                                                                       values['COMPONENT'], finalize=finalize, patchdata=patchdata)
 
     if 'PRODVERSION' in values:
         if values['PRODVERSION'] == '<default>' and values['PRODUCT'] not in [None, '<choose-from-menu>']:
-            values['PRODVERSION'] = get_default_version(ui, api_server, values['PRODUCT'])
+            values['PRODVERSION'] = get_default_version(ui, auth, values['PRODUCT'])
             ui.write(("Using default version '{}' of product {}\n".format(
                 values['PRODVERSION'], values['PRODUCT']
             ).encode()))

          
@@ 1490,7 1462,7 @@ def _bzexport_bugzilla(ui, repo, opts, r
                                    fallback_title=info['description'],
                                    fallback_bug_description=info['comment'])
 
-    values = fill_values(values, ui, repo, api_server, finalize=False, patchdata=contents)
+    values = fill_values(values, ui, repo, auth, api_server, finalize=False, patchdata=contents)
 
     if opts['edit']:
         if opts['new']:

          
@@ 1516,7 1488,7 @@ def _bzexport_bugzilla(ui, repo, opts, r
         if 'ATTACHMENT_FILENAME' in values:
             filename = values['ATTACHMENT_FILENAME']
 
-    values = fill_values(values, ui, repo, api_server, finalize=True, patchdata=contents)
+    values = fill_values(values, ui, repo, auth, api_server, finalize=True, patchdata=contents)
 
     if opts["new"]:
         if bug is not None:

          
@@ 1707,7 1679,7 @@ def _bzexport_moz_phab(ui, repo, opts, r
     )
     values['ATTACHCOMMENT'] = opts.get('comment', '') or '<none>'
 
-    values = fill_values(values, ui, repo, api_server,
+    values = fill_values(values, ui, repo, auth, api_server,
                          finalize=False, patchdata=contents)
 
     if opts['edit']:

          
@@ 1716,7 1688,7 @@ def _bzexport_moz_phab(ui, repo, opts, r
         else:
             values = edit_form(ui, repo, values, 'phab_update_template', b"phab_update.txt")
 
-    values = fill_values(values, ui, repo, api_server,
+    values = fill_values(values, ui, repo, auth, api_server,
                          finalize=True, patchdata=contents)
 
     # If the user gave a revset containing multiple revisions, respect it. In

          
@@ 1822,7 1794,7 @@ def _bzexport_phabsend(ui, repo, opts, r
 
     if opts['new']:
         values = edit_form(ui, repo, values, 'new_bug_template')
-        fill_values(values, ui, repo, api_server, finalize=True,
+        fill_values(values, ui, repo, auth, api_server, finalize=True,
                     patchdata=contents)
         bug = create_bug(ui, values, bzinfo, opts)
         values['BUGNUM'] = str(bug)

          
@@ 1864,7 1836,7 @@ def _bzexport_phabsend(ui, repo, opts, r
             value_sets[idx].update(values)
 
     value_sets = [
-        fill_values(values, ui, repo, api_server, finalize=True, patchdata=contents)
+        fill_values(values, ui, repo, auth, api_server, finalize=True, patchdata=contents)
         for values in value_sets
     ]
 

          
@@ 2001,12 1973,12 @@ def newbug(ui, repo, *args, **opts):
     values = fill_values_from_opts(ui, bzinfo, {}, opts,
                                    fallback_title="<required>",
                                    fallback_bug_description=opts['comment'] or '<required>')
-    fill_values(values, ui, repo, api_server, finalize=False)
+    fill_values(values, ui, repo, auth, api_server, finalize=False)
 
     if opts['edit']:
         values = edit_form(ui, repo, values, 'new_bug_template')
 
-    fill_values(values, ui, repo, api_server, finalize=True)
+    fill_values(values, ui, repo, auth, api_server, finalize=True)
 
     cc = validate_users(ui, api_server, auth, values['CC'], multi_user_prompt, 'reviewer')
     if cc is None:

          
M bz.py +19 -0
@@ 135,6 135,25 @@ def get_configuration(api_server):
     return request.Request(url, None, JSON_HEADERS)
 
 
+def get_product(auth, product, **opts):
+    url = f"product/{product}"
+    if 'include_fields' in opts:
+        fields = ",".join(opts['include_fields'])
+        url += f"?include_fields={fields}"
+    resp = auth.rest_request('GET', url)
+    return resp['products'][0]
+
+
+def get_products(auth, **opts):
+    args = {}
+    if 'include_fields' in opts:
+        args['include_fields'] = ",".join(opts['include_fields'])
+    else:
+        args['include_fields'] = "id,name,components.name"
+    resp = auth.rest_request('GET', f"product?type=enterable&include_fields={args['include_fields']}")
+    return resp['products']
+
+
 def get_bug(auth, bug, **opts):
     """
     Retrieve an existing bug