docs: def issues_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
      """
      Use: :issue|bug|feature|support:`ticket_number`
  
      When invoked as :issue:, turns into just a "#NN" hyperlink to
      `releases_issue_uri`.
  
      When invoked otherwise, turns into "[Type] <#NN hyperlink>: ".
  
      Spaces present in the "ticket number" are used as fields for keywords
      (major, backported) and/or specs (e.g. '>=1.0'). This data is removed &
      used when constructing the object.
  
      May give a 'ticket number' of ``-`` or ``0`` to generate no hyperlink.
      """
      parts = utils.unescape(text).split()
      issue_no = parts.pop(0)
      # Lol @ access back to Sphinx
      config = inliner.document.settings.env.app.config
      if issue_no not in ('-', '0'):
          ref = None
          if config.releases_issue_uri:
              # TODO: deal with % vs .format()
              ref = config.releases_issue_uri % issue_no
          elif config.releases_github_path:
              ref = "https://github.com/{}/issues/{}".format(
                  config.releases_github_path, issue_no)
          # Only generate a reference/link if we were able to make a URI
          if ref:
              identifier = nodes.reference(
                  rawtext, '#' + issue_no, refuri=ref, **options
              )
          # Otherwise, just make it regular text
          else:
              identifier = nodes.raw(
                  rawtext=rawtext, text='#' + issue_no, format='html',
                  **options
              )
      else:
          identifier = None
          issue_no = None # So it doesn't gum up dupe detection later
      # Additional 'new-style changelog' stuff
      if name in ISSUE_TYPES:
          nodelist = issue_nodelist(name, identifier)
          spec = None
          keyword = None
          # TODO: sanity checks re: e.g. >2 parts, >1 instance of keywords, >1
          # instance of specs, etc.
          for part in parts:
              maybe_spec = scan_for_spec(part)
              if maybe_spec:
                  spec = maybe_spec
              else:
                  if part in ('backported', 'major'):
                      keyword = part
                  else:
                      err = "Gave unknown keyword {!r} for issue no. {}"
                      raise ValueError(err.format(keyword, issue_no))
          # Create temporary node w/ data & final nodes to publish
          node = Issue(
              number=issue_no,
              type_=name,
              nodelist=nodelist,
              backported=(keyword == 'backported'),
              major=(keyword == 'major'),
              spec=spec,
          )
          return [node], []
      # Return old style info for 'issue' for older changelog entries
      else:
          return [identifier], []