Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-sphinx-issues for 
openSUSE:Factory checked in at 2022-04-21 15:42:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-sphinx-issues (Old)
 and      /work/SRC/openSUSE:Factory/.python-sphinx-issues.new.1538 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-sphinx-issues"

Thu Apr 21 15:42:42 2022 rev:7 rq:971334 version:3.0.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-sphinx-issues/python-sphinx-issues.changes    
    2020-03-27 00:23:03.488188745 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-sphinx-issues.new.1538/python-sphinx-issues.changes
      2022-04-21 15:49:00.336338472 +0200
@@ -1,0 +2,19 @@
+Wed Apr 20 11:24:07 UTC 2022 - pgaj...@suse.com
+
+- version update to 3.0.1
+  3.0.1 (2022-01-11)
+  * Fix regression from 3.0.0: exception: 'in <string>' requires string as 
left operand, not type.
+  3.0.0 (2022-01-10)
+  * The :commit: role now outputs with an @ prefix.
+  * Add configuration options for changing prefixes.
+  * Allow {group} to be specified within issues_uri, issues_pr_uri, 
issues_commit_uri, and
+  2.0.0 (2022-01-01)
+  * Drop support for Python 2.7 and 3.5.
+  * Test against Python 3.8 to 3.10.
+  * Add :cwe: role for linking to CVEs on https://cwe.mitre.org. Thanks 
@hugovk for the PR.
+  * Add support for custom urls and separators Issue #93
+  * Allow custom titles for all roles Issue #116
+  * Added setting issues_default_group_project as future replacement of 
issues_github_path,
+     to reflect the now to universal nature of the extension
+
+-------------------------------------------------------------------

Old:
----
  1.2.0.tar.gz

New:
----
  3.0.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-sphinx-issues.spec ++++++
--- /var/tmp/diff_new_pack.ly96di/_old  2022-04-21 15:49:00.736338899 +0200
+++ /var/tmp/diff_new_pack.ly96di/_new  2022-04-21 15:49:00.740338904 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-sphinx-issues
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %bcond_without python2
 Name:           python-sphinx-issues
-Version:        1.2.0
+Version:        3.0.1
 Release:        0
 Summary:        A Sphinx extension for linking to a project's issue tracker
 License:        MIT
@@ -53,7 +53,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%pytest test_sphinx_issues.py
+%pytest
 
 %files %{python_files}
 %doc README.rst

++++++ 1.2.0.tar.gz -> 3.0.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/.github/workflows/lint.yml 
new/sphinx-issues-3.0.1/.github/workflows/lint.yml
--- old/sphinx-issues-1.2.0/.github/workflows/lint.yml  1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/.github/workflows/lint.yml  2022-01-11 
17:41:14.000000000 +0100
@@ -0,0 +1,12 @@
+name: Lint
+
+on: [push, pull_request, workflow_dispatch]
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-python@v2
+      - uses: pre-commit/action@v2.0.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/.github/workflows/test.yml 
new/sphinx-issues-3.0.1/.github/workflows/test.yml
--- old/sphinx-issues-1.2.0/.github/workflows/test.yml  1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/.github/workflows/test.yml  2022-01-11 
17:41:14.000000000 +0100
@@ -0,0 +1,34 @@
+name: Test
+
+on: [push, pull_request, workflow_dispatch]
+
+env:
+  FORCE_COLOR: 1
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        python-version: ["3.6", "3.10"]
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Set up Python ${{ matrix.python-version }}
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python-version }}
+          cache: pip
+          cache-dependency-path: "setup.py"
+
+      - name: Install dependencies
+        run: |
+          python -m pip install -U pip
+          python -m pip install -U wheel
+          python -m pip install -U tox
+
+      - name: Tox tests
+        run: |
+          tox -e py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/.pre-commit-config.yaml 
new/sphinx-issues-3.0.1/.pre-commit-config.yaml
--- old/sphinx-issues-1.2.0/.pre-commit-config.yaml     2018-12-26 
17:05:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/.pre-commit-config.yaml     2022-01-11 
17:41:14.000000000 +0100
@@ -1,15 +1,20 @@
 repos:
-- repo: https://github.com/ambv/black
-  rev: 18.9b0
+- repo: https://github.com/asottile/pyupgrade
+  rev: v2.11.0
+  hooks:
+  - id: pyupgrade
+    args: [--py36-plus]
+- repo: https://github.com/python/black
+  rev: 20.8b1
   hooks:
   - id: black
-    language_version: python3.6
-- repo: https://github.com/pre-commit/pre-commit-hooks
-  rev: v2.0.0
+- repo: https://gitlab.com/pycqa/flake8
+  rev: 3.9.0
   hooks:
   - id: flake8
+    additional_dependencies: [flake8-bugbear==21.4.3]
 - repo: https://github.com/asottile/blacken-docs
-  rev: v0.3.0
+  rev: v1.10.0
   hooks:
   - id: blacken-docs
-    additional_dependencies: [black==18.9b0]
+    additional_dependencies: [black==20.8b1]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/.travis.yml 
new/sphinx-issues-3.0.1/.travis.yml
--- old/sphinx-issues-1.2.0/.travis.yml 2018-12-26 17:05:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/.travis.yml 1970-01-01 01:00:00.000000000 +0100
@@ -1,29 +0,0 @@
-language: python
-sudo: false
-cache: pip
-install: travis_retry pip install -U tox
-script: tox
-jobs:
-  fast_finish: true
-
-  include:
-  - { python: '3.6', env: TOXENV=lint }
-  - { python: '2.7', env: TOXENV=py27 }
-  - { python: '3.5', env: TOXENV=py35 }
-  - { python: '3.6', env: TOXENV=py36 }
-  - { python: '3.7', env: TOXENV=py37, dist: xenial, sudo: true }
-
-  - stage: PyPI Release
-    if: tag IS present
-    python: "3.6"
-    env: []
-    install: skip
-    script: skip
-    deploy:
-      provider: pypi
-      user: sloria
-      on:
-        tags: true
-      distributions: sdist bdist_wheel
-      password:
-        secure: 
D0c2PYyI06+N5/inLaPHkEaM/GVgKVPCBDm2asmQvCTs14ory9KK17cnS+tOmrTNyMzw2tYSvD1Ar5a7MQAfcJ+p2bOnr/UCLqzt98H2LlE/2NJdzQtI3FtNCkhRVx20LK85G8ZWaHCecGIkgGmbIDZ56u1Aj+G16z0PqEz5i7s=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/LICENSE 
new/sphinx-issues-3.0.1/LICENSE
--- old/sphinx-issues-1.2.0/LICENSE     2018-12-26 17:05:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/LICENSE     2022-01-11 17:41:14.000000000 +0100
@@ -1,4 +1,4 @@
-Copyright 2018 Steven Loria
+Copyright 2022 Steven Loria
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/README.rst 
new/sphinx-issues-3.0.1/README.rst
--- old/sphinx-issues-1.2.0/README.rst  2018-12-26 17:05:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/README.rst  2022-01-11 17:41:14.000000000 +0100
@@ -2,8 +2,17 @@
 sphinx-issues
 =============
 
-.. image:: https://travis-ci.org/sloria/sphinx-issues.svg?branch=master
-    :target: https://travis-ci.org/sloria/sphinx-issues
+.. image:: https://badgen.net/pypi/v/sphinx-issues
+  :alt: pypi badge
+  :target: https://pypi.org/project/sphinx-issues/
+
+.. image:: 
https://github.com/OpenASL/HowSignBot/workflows/.github/workflows/test.yml/badge.svg
+  :alt: github actions status
+  :target: .github/workflows/test.yml
+
+.. image:: https://badgen.net/badge/code%20style/black/000
+   :target: https://github.com/ambv/black
+   :alt: Code style: Black
 
 A Sphinx extension for linking to your project's issue tracker. Includes roles 
for linking to issues, pull requests, user profiles, with built-in support for 
GitHub (though this works with other services).
 
@@ -20,7 +29,11 @@
     pip install sphinx-issues
 
 
-Add ``sphinx_issues`` to ``extensions`` in your ``conf.py``. If your project 
is on GitHub, add the ``issues_github_path`` config variable. Otherwise, use 
``issues_uri`` and ``issues_pr_uri``.
+Add ``sphinx_issues`` to ``extensions`` in your ``conf.py``.
+
+The extension has default values for GitHub projects.
+Simply set the add the ``issues_default_group_project`` config variable and 
you are good
+to go:
 
 .. code-block:: python
 
@@ -32,16 +45,47 @@
         "sphinx_issues"
     ]
 
-    # Github repo
+    # Path to GitHub repo {group}/{project}  (note that `group` is the GitHub 
user or organization)
     issues_github_path = "sloria/marshmallow"
 
-    # equivalent to
-    issues_uri = "https://github.com/sloria/marshmallow/issues/{issue}";
-    issues_pr_uri = "https://github.com/sloria/marshmallow/pull/{pr}";
-    issues_commit_uri = "https://github.com/sloria/marshmallow/commit/{commit}";
+    # which is the equivalent to:
+    issues_uri = "https://github.com/{group}/{project}/issues/{issue}";
+    issues_prefix = "#"
+    issues_pr_uri = "https://github.com/{group}/{project}/pull/{pr}";
+    issues_pr_prefix = "#"
+    issues_commit_uri = "https://github.com/{group}/{project}/commit/{commit}";
+    issues_commit_prefix = "@"
+    issues_user_uri = "https://github.com/{user}";
+    issues_user_prefix = "@"
+
+The extension is very configurable and can be used with any kind of
+issue tracker. Here is how you could configure it for use
+with a custom hosed GitLab instance:
+
+.. code-block:: python
+
+    # docs/conf.py
+
+    # ...
+    extensions = [
+        # ...
+        "sphinx_issues"
+    ]
+
+    #  Default repo {group}/{project} of gitlab project
+    issues_default_group_project = "myteam/super_great_project"
+    issues_uri = 
"https://gitlab.company.com/{group}/{project}/-/issues/{issue}";
+    issues_prefix = "#"
+    issues_pr_uri = 
"https://gitlab.company.com/{group}/{project}/-/merge_requests/{pr}";
+    issues_pr_prefix = "!"
+    issues_commit_uri = 
"https://gitlab.company.com/{group}/{project}/-/commit/{commit}";
+    issues_commit_prefix = "@"
+    issues_user_uri = "https://gitlab.company.com/{user}";
+    issues_user_prefix = "@"
 
-Usage
-*****
+
+Usage inside the documentation
+******************************
 
 Use the ``:issue:``  and ``:pr:`` roles in your docs like so:
 
@@ -56,7 +100,20 @@
     See PR :pr:`58`
 
 
-Use the ``:user:`` role in your docs to link to user profiles (Github by 
default, but can be configured via the ``issues_user_uri`` config variable).
+Use the ``:user:`` role in your docs to link to user profiles (GitHub by 
default, but can be configured via the ``issues_user_uri`` config variable).
+
+
+Use the ``:commit:`` role to link to commits.
+
+.. code-block:: rst
+
+    Fixed in :commit:`6bb9124d5e9dbb2f7b52864c3d8af7feb1b69403`.
+
+Use the ``:cve:`` role to link to CVEs on https://cve.mitre.org.
+
+.. code-block:: rst
+
+    :cve:`CVE-2018-17175` - Addresses possible vulnerability when...
 
 .. code-block:: rst
 
@@ -68,23 +125,24 @@
 
     This change is due to :user:`Andreas Mueller <amueller>`.
 
+The syntax ``:role:`My custom title <target>``` works for all roles of this 
extension.
 
-Use the ``:commit:`` role to link to commits.
+It can be also used in combination with a list:
 
 .. code-block:: rst
 
-    Fixed in :commit:`6bb9124d5e9dbb2f7b52864c3d8af7feb1b69403`.
+    Fix bad bug :issue:`123, (Duplicate) <199>`
 
-Use the ``:cve:`` role to link to CVEs on https://cve.mitre.org.
+Use the ``:cwe:`` role to link to CWEs on https://cwe.mitre.org.
 
 .. code-block:: rst
 
-    :cve:`CVE-2018-17175` - Addresses possible vulnerability when...
+    :cwe:`CWE-787` - The software writes data past the end, or...
 
 Credits
 *******
 
-Credit goes to Jeff Forcier for his work on the `releases 
<https://github.com/bitprophet/releases>`_ extension, which is a full-featured 
solution for generating changelogs. I just needed a quick way to reference 
Github issues in my docs, so I yoinked the bits that I needed.
+Credit goes to Jeff Forcier for his work on the `releases 
<https://github.com/bitprophet/releases>`_ extension, which is a full-featured 
solution for generating changelogs. I just needed a quick way to reference 
GitHub issues in my docs, so I yoinked the bits that I needed.
 
 License
 *******
@@ -95,6 +153,29 @@
 Changelog
 *********
 
+3.0.1 (2022-01-11)
+------------------
+
+- Fix regression from 3.0.0: `exception: 'in <string>' requires string as left 
operand, not type`.
+
+3.0.0 (2022-01-10)
+------------------
+
+- The `:commit:` role now outputs with an `@` prefix.
+- Add configuration options for changing prefixes.
+- Allow `{group}` to be specified within `issues_uri`, `issues_pr_uri`, 
`issues_commit_uri`, and 
+
+2.0.0 (2022-01-01)
+------------------
+
+- Drop support for Python 2.7 and 3.5.
+- Test against Python 3.8 to 3.10.
+- Add ``:cwe:`` role for linking to CVEs on https://cwe.mitre.org.
+  Thanks @hugovk for the PR.
+- Add support for custom urls and separators `Issue #93 
<https://github.com/sloria/sphinx-issues/issues/93>`_
+- Allow custom titles for all roles `Issue #116 
<https://github.com/sloria/sphinx-issues/issues/116>`_
+- Added setting `issues_default_group_project` as future replacement of 
`issues_github_path`, to reflect the now to universal nature of the extension
+
 1.2.0 (2018-12-26)
 ------------------
 
@@ -132,7 +213,7 @@
 0.2.0 (2014-12-22)
 ------------------
 
-- Add ``:user:`` role for linking to Github user profiles.
+- Add ``:user:`` role for linking to GitHub user profiles.
 
 0.1.0 (2014-12-21)
 ------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/setup.cfg 
new/sphinx-issues-3.0.1/setup.cfg
--- old/sphinx-issues-1.2.0/setup.cfg   2018-12-26 17:05:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/setup.cfg   2022-01-11 17:41:14.000000000 +0100
@@ -1,13 +1,9 @@
 [metadata]
 # This includes the license file in the wheel.
-license_file = LICENSE
-
-[bdist_wheel]
-universal = 1
+license_files = LICENSE
 
 [flake8]
-ignore = E203, E266, E501, W503, E302, W504
-max-line-length = 100
+ignore = E203, E266, E501, W503
+max-line-length = 90
 max-complexity = 18
 select = B,C,E,F,W,T4,B9
-exclude = .git,.ropeproject,.tox,build,env,venv,__pycache__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/setup.py 
new/sphinx-issues-3.0.1/setup.py
--- old/sphinx-issues-1.2.0/setup.py    2018-12-26 17:05:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/setup.py    2022-01-11 17:41:14.000000000 +0100
@@ -1,14 +1,13 @@
-# -*- coding: utf-8 -*-
 import re
 from setuptools import setup
 
 INSTALL_REQUIRES = ["sphinx"]
 EXTRAS_REQUIRE = {
-    "tests": ["pytest", 'mock; python_version < "3.0"'],
+    "tests": ["pytest>=6.2.0"],
     "lint": [
-        "flake8==3.6.0",
-        'flake8-bugbear==18.8.0; python_version >= "3.5"',
-        "pre-commit==1.13.0",
+        "flake8==3.9.2",
+        "flake8-bugbear==20.11.1",
+        "pre-commit~=2.7",
     ],
 }
 EXTRAS_REQUIRE["dev"] = EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["lint"] + 
["tox"]
@@ -19,7 +18,7 @@
     Raises RuntimeError if not found.
     """
     version = ""
-    with open(fname, "r") as fp:
+    with open(fname) as fp:
         reg = re.compile(r'__version__ = [\'"]([^\'"]*)[\'"]')
         for line in fp:
             m = reg.match(line)
@@ -40,7 +39,7 @@
 setup(
     name="sphinx-issues",
     version=find_version("sphinx_issues.py"),
-    description="A Sphinx extension for linking to your project's " "issue 
tracker",
+    description="A Sphinx extension for linking to your project's issue 
tracker",
     long_description=read("README.rst"),
     install_requires=INSTALL_REQUIRES,
     extras_require=EXTRAS_REQUIRE,
@@ -49,15 +48,16 @@
     url="https://github.com/sloria/sphinx-issues";,
     license="MIT",
     keywords="sphinx issues github",
+    python_requires=">=3.6",
     classifiers=[
         "Intended Audience :: Developers",
         "License :: OSI Approved :: MIT License",
-        "Programming Language :: Python :: 2",
-        "Programming Language :: Python :: 2.7",
         "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.5",
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
         "Topic :: Software Development :: Documentation",
     ],
     py_modules=["sphinx_issues"],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/sphinx_issues.py 
new/sphinx-issues-3.0.1/sphinx_issues.py
--- old/sphinx-issues-1.2.0/sphinx_issues.py    2018-12-26 17:05:00.000000000 
+0100
+++ new/sphinx-issues-3.0.1/sphinx_issues.py    2022-01-11 17:41:14.000000000 
+0100
@@ -1,27 +1,23 @@
-# -*- coding: utf-8 -*-
 """A Sphinx extension for linking to your project's issue tracker."""
 import re
+from typing import Callable, Optional, Tuple
 
 from docutils import nodes, utils
+from sphinx.config import Config
 from sphinx.util.nodes import split_explicit_title
 
-__version__ = "1.2.0"
+__version__ = "3.0.1"
 __author__ = "Steven Loria"
 __license__ = "MIT"
 
 
-def user_role(name, rawtext, text, lineno, inliner, options=None, 
content=None):
-    """Sphinx role for linking to a user profile. Defaults to linking to
-    Github profiles, but the profile URIS can be configured via the
-    ``issues_user_uri`` config value.
+def cve_role(name, rawtext, text, lineno, inliner, options=None, content=None):
+    """Sphinx role for linking to a CVE on https://cve.mitre.org.
 
     Examples: ::
 
-        :user:`sloria`
-
-    Anchor text also works: ::
+        :cve:`CVE-2018-17175`
 
-        :user:`Steven Loria <sloria>`
     """
     options = options or {}
     content = content or []
@@ -29,26 +25,154 @@
 
     target = utils.unescape(target).strip()
     title = utils.unescape(title).strip()
-    config = inliner.document.settings.env.app.config
-    if config.issues_user_uri:
-        ref = config.issues_user_uri.format(user=target)
-    else:
-        ref = "https://github.com/{0}".format(target)
-    if has_explicit_title:
-        text = title
-    else:
-        text = "@{0}".format(target)
-
+    ref = f"https://cve.mitre.org/cgi-bin/cvename.cgi?name={target}";
+    text = title if has_explicit_title else target
     link = nodes.reference(text=text, refuri=ref, **options)
     return [link], []
 
 
-def cve_role(name, rawtext, text, lineno, inliner, options=None, content=None):
-    """Sphinx role for linking to a CVE on https://cve.mitre.org.
+GITHUB_USER_RE = re.compile("^https://github.com/([^/]+)/([^/]+)/.*")
+
+
+def _get_default_group_and_project(
+    config: Config, uri_config_option: str
+) -> Optional[Tuple[str, str]]:
+    """
+    Get the default group/project or None if not set
+    """
+    old_config = getattr(config, "issues_github_path", None)
+    new_config = getattr(config, "issues_default_group_project", None)
+
+    if old_config and new_config:
+        raise ValueError(
+            "Both 'issues_github_path' and 'issues_default_group_project' are 
set, even"
+            " though they define the same setting.  "
+            "Please only define one of these."
+        )
+    group_and_project = new_config or old_config
+
+    if group_and_project:
+        assert isinstance(group_and_project, str)
+        try:
+            group, project = group_and_project.split("/", maxsplit=1)
+            return group, project
+        except ValueError as e:
+            raise ValueError(
+                "`issues_github_path` or `issues_default_group_project` needs 
to "
+                "define a value in the form of `<group or user>/<project>` "
+                f"but `{config}` was given."
+            ) from e
+
+    # If group and project was not set, we need to look for it within the 
github url
+    # for backward compatibility
+    if not group_and_project:
+        uri = getattr(config, uri_config_option)
+        if uri:
+            match = GITHUB_USER_RE.match(uri)
+            if match:
+                return match.groups()[0], match.groups()[1]
+
+    return None
+
+
+def _get_placeholder(uri_config_option: str) -> str:
+    """
+    Get the placeholder from the uri_config_option
+    """
+    try:
+        # i.e. issues_pr_uri -> pr
+        return uri_config_option[:-4].split("_", maxsplit=1)[1]
+    except IndexError:
+        # issues_uri -> issue
+        return uri_config_option[:-5]
+
+
+def _get_uri_template(
+    config: Config,
+    uri_config_option: str,
+) -> str:
+    """
+    Get a URL format template that can be filled with user information based
+    on the given configuration
+
+    The result always contains the following placeholder
+      - n (the issue number, user, pull request, etc...)
+
+    The result can contain the following other placeholders
+      - group (same as user in github)
+      - project
+
+    Examples for possible results:
+
+         - "https://github.com/{group}/{project}/issues/{n}";
+
+         - "https://gitlab.company.com/{group}/{project}/{n}";
+
+         - 
"https://fancy.issuetrack.com?group={group}&project={project}&issue={n}";
+
+    Raises:
+         - ValueError if the given uri contains an invalid placeholder
+    """
+    format_string = str(getattr(config, uri_config_option))
+    placeholder = _get_placeholder(uri_config_option)
+
+    result = format_string.replace(f"{{{placeholder}}}", "{n}")
+
+    try:
+        result.format(project="", group="", n="")
+    except (NameError, KeyError) as e:
+        raise ValueError(
+            f"The `{uri_config_option}` option contains invalid placeholders. "
+            f"Only {{group}}, {{projects}} and {{{placeholder}}} are allowed."
+            f'Invalid format string: "{format_string}".'
+        ) from e
+    return result
+
+
+def _get_uri(
+    uri_config_option: str,
+    config: Config,
+    number: str,
+    group_and_project: Optional[Tuple[str, str]] = None,
+) -> str:
+    """
+    Get a URI based on the given configuration and do some sanity checking
+    """
+    format_string = _get_uri_template(config, uri_config_option)
+
+    url_vars = {"n": number}
+
+    config_group_and_project = _get_default_group_and_project(config, 
uri_config_option)
+    if group_and_project:
+        # Group and Project defined by call
+        if config_group_and_project:
+            to_replace = "/".join(config_group_and_project)
+            if to_replace in format_string:
+                # Backward compatibility, replace default group/project
+                # with {group}/{project}
+                format_string = format_string.replace(to_replace, 
"{group}/{project}")
+        (url_vars["group"], url_vars["project"]) = group_and_project
+    elif config_group_and_project:
+        # If not defined by call use the default if given
+        (url_vars["group"], url_vars["project"]) = config_group_and_project
+
+    try:
+        return format_string.format(**url_vars)
+    except (NameError, KeyError) as e:
+        # The format string was checked before, that it contains no additional 
not
+        # supported placeholders. So this occur
+        raise ValueError(
+            f"The `{uri_config_option}` format `{format_string}` requires a "
+            f"group/project to be defined in `issues_default_group_project`."
+        ) from e
+
+
+def cwe_role(name, rawtext, text, lineno, inliner, options=None, content=None):
+    """Sphinx role for linking to a CWE on https://cwe.mitre.org.
 
     Examples: ::
 
-        :cve:`CVE-2018-17175`
+        :cwe:`CWE-787`
 
     """
     options = options or {}
@@ -57,65 +181,80 @@
 
     target = utils.unescape(target).strip()
     title = utils.unescape(title).strip()
-    ref = "https://cve.mitre.org/cgi-bin/cvename.cgi?name={0}".format(target)
+    number = target[4:]
+    ref = f"https://cwe.mitre.org/data/definitions/{number}.html";
     text = title if has_explicit_title else target
     link = nodes.reference(text=text, refuri=ref, **options)
     return [link], []
 
 
-class IssueRole(object):
+class IssueRole:
+    # Symbols used to separate and issue/pull request/merge request etc
+    # i.e
+    #   - group/project#2323 for issues
+    #   - group/project!1234 for merge requests (in gitlab)
+    #   - group/project@adbc1234 for commits
+    ELEMENT_SEPARATORS = "#@!"
 
-    EXTERNAL_REPO_REGEX = re.compile(r"^(\w+)/(.+)([#@])([\w]+)$")
+    EXTERNAL_REPO_REGEX = 
re.compile(rf"^(\w+)/(.+)([{ELEMENT_SEPARATORS}])([\w]+)$")
 
     def __init__(
-        self, uri_config_option, format_kwarg, github_uri_template, 
format_text=None
+        self,
+        config_prefix: str,
+        pre_format_text: Callable[[Config, str], str] = None,
     ):
-        self.uri_config_option = uri_config_option
-        self.format_kwarg = format_kwarg
-        self.github_uri_template = github_uri_template
-        self.format_text = format_text or self.default_format_text
+        self.uri_config = f"{config_prefix}_uri"
+        self.separator_config = f"{config_prefix}_prefix"
+        self.pre_format_text = pre_format_text or self.default_pre_format_text
 
     @staticmethod
-    def default_format_text(issue_no):
-        return "#{0}".format(issue_no)
+    def default_pre_format_text(config: Config, text: str) -> str:
+        return text
+
+    def format_text(self, config: Config, issue_no: str) -> str:
+        """
+        Add supported separator in front of the issue or raise an error if 
invalid
+        separator is given
+        """
+        separator = getattr(config, self.separator_config)
+        if separator not in self.ELEMENT_SEPARATORS:
+            raise ValueError(
+                f"Option {self.separator_config} has to be one of "
+                f"{', '.join(self.ELEMENT_SEPARATORS)}."
+            )
+        text = self.pre_format_text(config, 
issue_no.lstrip(self.ELEMENT_SEPARATORS))
+        return f"{separator}{text}"
+
+    def make_node(self, name: str, issue_no: str, config: Config, 
options=None):
+        if issue_no in ("-", "0"):
+            return None
 
-    def make_node(self, name, issue_no, config, options=None):
-        name_map = {"pr": "pull", "issue": "issues", "commit": "commit"}
         options = options or {}
+
+        has_explicit_title, title, target = split_explicit_title(issue_no)
+
+        if has_explicit_title:
+            issue_no = str(target)
+
         repo_match = self.EXTERNAL_REPO_REGEX.match(issue_no)
-        if repo_match:  # External repo
-            username, repo, symbol, issue = repo_match.groups()
-            if name not in name_map:
-                raise ValueError(
-                    "External repo linking not supported for :{}:".format(name)
-                )
-            path = name_map.get(name)
-            ref = "https://github.com/{issues_github_path}/{path}/{n}".format(
-                issues_github_path="{}/{}".format(username, repo), path=path, 
n=issue
+
+        if repo_match:
+            # External repo
+            group, project, original_separator, issue_no = repo_match.groups()
+            text = f"{group}/{project}{self.format_text(config, issue_no)}"
+            ref = _get_uri(
+                self.uri_config,
+                config,
+                issue_no,
+                (group, project),
             )
-            formatted_issue = self.format_text(issue).lstrip("#")
-            text = 
"{username}/{repo}{symbol}{formatted_issue}".format(**locals())
-            link = nodes.reference(text=text, refuri=ref, **options)
-            return link
-
-        if issue_no not in ("-", "0"):
-            uri_template = getattr(config, self.uri_config_option, None)
-            if uri_template:
-                ref = uri_template.format(**{self.format_kwarg: issue_no})
-            elif config.issues_github_path:
-                ref = self.github_uri_template.format(
-                    issues_github_path=config.issues_github_path, n=issue_no
-                )
-            else:
-                raise ValueError(
-                    "Neither {} nor issues_github_path "
-                    "is set".format(self.uri_config_option)
-                )
-            issue_text = self.format_text(issue_no)
-            link = nodes.reference(text=issue_text, refuri=ref, **options)
         else:
-            link = None
-        return link
+            text = self.format_text(config, issue_no)
+            ref = _get_uri(self.uri_config, config, issue_no)
+        if has_explicit_title:
+            return nodes.reference(text=title, refuri=ref, **options)
+        else:
+            return nodes.reference(text=text, refuri=ref, **options)
 
     def __call__(
         self, name, rawtext, text, lineno, inliner, options=None, content=None
@@ -135,70 +274,115 @@
 
 
 """Sphinx role for linking to an issue. Must have
-`issues_uri` or `issues_github_path` configured in ``conf.py``.
+`issues_uri` or `issues_default_group_project` configured in ``conf.py``.
 Examples: ::
     :issue:`123`
     :issue:`42,45`
     :issue:`sloria/konch#123`
 """
 issue_role = IssueRole(
-    uri_config_option="issues_uri",
-    format_kwarg="issue",
-    github_uri_template="https://github.com/{issues_github_path}/issues/{n}";,
+    config_prefix="issues",
 )
 
 """Sphinx role for linking to a pull request. Must have
-`issues_pr_uri` or `issues_github_path` configured in ``conf.py``.
+`issues_pr_uri` or `issues_default_group_project` configured in ``conf.py``.
 Examples: ::
     :pr:`123`
     :pr:`42,45`
     :pr:`sloria/konch#43`
 """
 pr_role = IssueRole(
-    uri_config_option="issues_pr_uri",
-    format_kwarg="pr",
-    github_uri_template="https://github.com/{issues_github_path}/pull/{n}";,
+    config_prefix="issues_pr",
 )
 
 
-def format_commit_text(sha):
+def format_commit_text(config, sha):
     return sha[:7]
 
 
 """Sphinx role for linking to a commit. Must have
-`issues_pr_uri` or `issues_github_path` configured in ``conf.py``.
+`issues_commit_uri` or `issues_default_group_project` configured in 
``conf.py``.
 Examples: ::
     :commit:`123abc456def`
     :commit:`sloria/konch@123abc456def`
 """
 commit_role = IssueRole(
-    uri_config_option="issues_commit_uri",
-    format_kwarg="commit",
-    github_uri_template="https://github.com/{issues_github_path}/commit/{n}";,
-    format_text=format_commit_text,
+    config_prefix="issues_commit",
+    pre_format_text=format_commit_text,
 )
 
+"""Sphinx role for linking to a user profile. Defaults to linking to
+GitHub profiles, but the profile URIS can be configured via the
+``issues_user_uri`` config value.
+
+Examples: ::
+
+    :user:`sloria`
+
+Anchor text also works: ::
+
+    :user:`Steven Loria <sloria>`
+"""
+user_role = IssueRole(config_prefix="issues_user")
+
 
 def setup(app):
     # Format template for issues URI
     # e.g. 'https://github.com/sloria/marshmallow/issues/{issue}
-    app.add_config_value("issues_uri", default=None, rebuild="html")
+    app.add_config_value(
+        "issues_uri",
+        default="https://github.com/{group}/{project}/issues/{issue}";,
+        rebuild="html",
+        types=[str],
+    )
+    app.add_config_value("issues_prefix", default="#", rebuild="html", 
types=[str])
     # Format template for PR URI
     # e.g. 'https://github.com/sloria/marshmallow/pull/{issue}
-    app.add_config_value("issues_pr_uri", default=None, rebuild="html")
+    app.add_config_value(
+        "issues_pr_uri",
+        default="https://github.com/{group}/{project}/pull/{pr}";,
+        rebuild="html",
+        types=[str],
+    )
+    app.add_config_value("issues_pr_prefix", default="#", rebuild="html", 
types=[str])
     # Format template for commit URI
     # e.g. 'https://github.com/sloria/marshmallow/commits/{commit}
-    app.add_config_value("issues_commit_uri", default=None, rebuild="html")
-    # Shortcut for Github, e.g. 'sloria/marshmallow'
-    app.add_config_value("issues_github_path", default=None, rebuild="html")
+    app.add_config_value(
+        "issues_commit_uri",
+        default="https://github.com/{group}/{project}/commit/{commit}";,
+        rebuild="html",
+        types=[str],
+    )
+    app.add_config_value(
+        "issues_commit_prefix", default="@", rebuild="html", types=[str]
+    )
+    # There is no seperator config as a format_text function is given
+
+    # Default User (Group)/Project eg. 'sloria/marshmallow'
+    # Called github as the package was working with github only before
+    app.add_config_value(
+        "issues_github_path", default=None, rebuild="html", types=[str]
+    )
+    # Same as above but with new naming to reflect the new functionality
+    # Only on of both can be set
+    app.add_config_value(
+        "issues_default_group_project", default=None, rebuild="html", 
types=[str]
+    )
     # Format template for user profile URI
     # e.g. 'https://github.com/{user}'
-    app.add_config_value("issues_user_uri", default=None, rebuild="html")
+    app.add_config_value(
+        "issues_user_uri",
+        default="https://github.com/{user}";,
+        rebuild="html",
+        types=[str],
+    )
+    app.add_config_value("issues_user_prefix", default="@", rebuild="html", 
types=[str])
     app.add_role("issue", issue_role)
     app.add_role("pr", pr_role)
     app.add_role("user", user_role)
     app.add_role("commit", commit_role)
     app.add_role("cve", cve_role)
+    app.add_role("cwe", cwe_role)
     return {
         "version": __version__,
         "parallel_read_safe": True,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/test_sphinx_issues.py 
new/sphinx-issues-3.0.1/test_sphinx_issues.py
--- old/sphinx-issues-1.2.0/test_sphinx_issues.py       2018-12-26 
17:05:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/test_sphinx_issues.py       1970-01-01 
01:00:00.000000000 +0100
@@ -1,142 +0,0 @@
-# -*- coding: utf-8 -*-
-from tempfile import mkdtemp
-from shutil import rmtree
-
-try:
-    from unittest.mock import Mock
-except ImportError:
-    from mock import Mock
-
-from sphinx.application import Sphinx
-from sphinx_issues import (
-    issue_role,
-    user_role,
-    pr_role,
-    cve_role,
-    commit_role,
-    setup as issues_setup,
-)
-
-import pytest
-
-
-@pytest.yield_fixture(
-    params=[
-        # Parametrize config
-        {"issues_github_path": "marshmallow-code/marshmallow"},
-        {
-            "issues_uri": 
"https://github.com/marshmallow-code/marshmallow/issues/{issue}";,
-            "issues_pr_uri": 
"https://github.com/marshmallow-code/marshmallow/pull/{pr}";,
-            "issues_commit_uri": 
"https://github.com/marshmallow-code/marshmallow/commit/{commit}";,
-        },
-    ]
-)
-def app(request):
-    src, doctree, confdir, outdir = [mkdtemp() for _ in range(4)]
-    Sphinx._log = lambda self, message, wfile, nonl=False: None
-    app = Sphinx(
-        srcdir=src, confdir=None, outdir=outdir, doctreedir=doctree, 
buildername="html"
-    )
-    issues_setup(app)
-    # Stitch together as the sphinx app init() usually does w/ real conf files
-    app.config._raw_config = request.param
-    try:
-        app.config.init_values()
-    except TypeError:
-        app.config.init_values(lambda x: x)
-    yield app
-    [rmtree(x) for x in (src, doctree, confdir, outdir)]
-
-
-@pytest.fixture()
-def inliner(app):
-    return Mock(document=Mock(settings=Mock(env=Mock(app=app))))
-
-
-@pytest.mark.parametrize(
-    ("role", "role_name", "text", "expected_text", "expected_url"),
-    [
-        (
-            issue_role,
-            "issue",
-            "42",
-            "#42",
-            "https://github.com/marshmallow-code/marshmallow/issues/42";,
-        ),
-        (
-            pr_role,
-            "pr",
-            "42",
-            "#42",
-            "https://github.com/marshmallow-code/marshmallow/pull/42";,
-        ),
-        (user_role, "user", "sloria", "@sloria", "https://github.com/sloria";),
-        (
-            user_role,
-            "user",
-            "Steven Loria <sloria>",
-            "Steven Loria",
-            "https://github.com/sloria";,
-        ),
-        (
-            cve_role,
-            "cve",
-            "CVE-2018-17175",
-            "CVE-2018-17175",
-            "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-17175";,
-        ),
-        (
-            commit_role,
-            "commit",
-            "123abc456def",
-            "123abc4",
-            
"https://github.com/marshmallow-code/marshmallow/commit/123abc456def";,
-        ),
-        # External issue
-        (
-            issue_role,
-            "issue",
-            "sloria/webargs#42",
-            "sloria/webargs#42",
-            "https://github.com/sloria/webargs/issues/42";,
-        ),
-        # External PR
-        (
-            pr_role,
-            "pr",
-            "sloria/webargs#42",
-            "sloria/webargs#42",
-            "https://github.com/sloria/webargs/pull/42";,
-        ),
-        # External commit
-        (
-            commit_role,
-            "commit",
-            "sloria/webargs@abc123def456",
-            "sloria/webargs@abc123d",
-            "https://github.com/sloria/webargs/commit/abc123def456";,
-        ),
-    ],
-)
-def test_roles(inliner, role, role_name, text, expected_text, expected_url):
-    result = role(role_name, rawtext="", text=text, lineno=None, 
inliner=inliner)
-    link = result[0][0]
-    assert link.astext() == expected_text
-    assert link.attributes["refuri"] == expected_url
-
-
-def test_issue_role_multiple(inliner):
-    result = issue_role(
-        name=None, rawtext="", text="42,43", inliner=inliner, lineno=None
-    )
-    link1 = result[0][0]
-    assert link1.astext() == "#42"
-    issue_url = "https://github.com/marshmallow-code/marshmallow/issues/";
-    assert link1.attributes["refuri"] == issue_url + "42"
-
-    sep = result[0][1]
-    assert sep.astext() == ", "
-
-    link2 = result[0][2]
-    assert link2.astext() == "#43"
-    assert link2.attributes["refuri"] == issue_url + "43"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/tests/source/conf.py 
new/sphinx-issues-3.0.1/tests/source/conf.py
--- old/sphinx-issues-1.2.0/tests/source/conf.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/tests/source/conf.py        2022-01-11 
17:41:14.000000000 +0100
@@ -0,0 +1,64 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = "sphinx-issues"
+copyright = "2022, foobar"
+author = "foobar"
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ["sphinx_issues"]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ["_templates"]
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = "alabaster"
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ["_static"]
+
+#
+suppress_warnings = ["app.add_node"]
+
+issues_uri = "https://gitlab.company.com/{group}/{project}/-/issues/{issue}";
+issues_prefix = "#"
+issues_pr_uri = 
"https://gitlab.company.com/{group}/{project}/-/merge_requests/{pr}";
+issues_pr_prefix = "!"
+issues_commit_uri = 
"https://gitlab.company.com/{group}/{project}/-/commit/{commit}";
+issues_commit_prefix = "@"
+issues_user_uri = "https://gitlab.company.com/{user}";
+issues_user_prefix = "@"
+issues_default_group_project = "myteam/super_great_project"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/tests/source/examples.rst 
new/sphinx-issues-3.0.1/tests/source/examples.rst
--- old/sphinx-issues-1.2.0/tests/source/examples.rst   1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/tests/source/examples.rst   2022-01-11 
17:41:14.000000000 +0100
@@ -0,0 +1,7 @@
+Examples:
+
+    - See issues :issue:`12,13`
+
+    - See other issues :issue:`sloria/konch#45,46`.
+
+    - See PR :pr:`58`, thanks :user:`kound`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/tests/source/index.rst 
new/sphinx-issues-3.0.1/tests/source/index.rst
--- old/sphinx-issues-1.2.0/tests/source/index.rst      1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/tests/source/index.rst      2022-01-11 
17:41:14.000000000 +0100
@@ -0,0 +1,7 @@
+
+Welcome to sphinx-issues's documentation!
+=========================================
+
+
+.. include:: examples.rst
+.. include:: ../README.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/tests/test_sphinx_issues.py 
new/sphinx-issues-3.0.1/tests/test_sphinx_issues.py
--- old/sphinx-issues-1.2.0/tests/test_sphinx_issues.py 1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/tests/test_sphinx_issues.py 2022-01-11 
17:41:14.000000000 +0100
@@ -0,0 +1,358 @@
+import subprocess
+import sys
+from pathlib import Path
+from shutil import rmtree
+from tempfile import mkdtemp
+from unittest.mock import Mock
+
+import pytest
+import sphinx.application
+from sphinx_issues import commit_role, cve_role, cwe_role, issue_role, pr_role
+from sphinx_issues import setup as issues_setup
+from sphinx_issues import user_role
+
+
+BASE_DIR = Path(__file__).parent.absolute()
+
+
+@pytest.fixture(
+    params=[
+        # Parametrize config
+        {"issues_github_path": "marshmallow-code/marshmallow"},
+        {"issues_default_group_project": "marshmallow-code/marshmallow"},
+        {
+            "issues_uri": 
"https://github.com/marshmallow-code/marshmallow/issues/{issue}";,
+            "issues_pr_uri": 
"https://github.com/marshmallow-code/marshmallow/pull/{pr}";,
+            "issues_commit_uri": 
"https://github.com/marshmallow-code/marshmallow/commit/{commit}";,
+        },
+    ]
+)
+def app(request):
+    src, doctree, confdir, outdir = [mkdtemp() for _ in range(4)]
+    sphinx.application.Sphinx._log = lambda self, message, wfile, nonl=False: 
None
+    app = sphinx.application.Sphinx(
+        srcdir=src, confdir=None, outdir=outdir, doctreedir=doctree, 
buildername="html"
+    )
+    issues_setup(app)
+    # Stitch together as the sphinx app init() usually does w/ real conf files
+    app.config._raw_config = request.param
+    try:
+        app.config.init_values()
+    except TypeError:
+        app.config.init_values(lambda x: x)
+    yield app
+    [rmtree(x) for x in (src, doctree, confdir, outdir)]
+
+
+@pytest.fixture()
+def inliner(app):
+    return Mock(document=Mock(settings=Mock(env=Mock(app=app))))
+
+
+@pytest.mark.parametrize(
+    ("role", "role_name", "text", "expected_text", "expected_url"),
+    [
+        (
+            issue_role,
+            "issue",
+            "42",
+            "#42",
+            "https://github.com/marshmallow-code/marshmallow/issues/42";,
+        ),
+        (
+            issue_role,
+            "issue",
+            "Hard Issue <42>",
+            "Hard Issue",
+            "https://github.com/marshmallow-code/marshmallow/issues/42";,
+        ),
+        (
+            issue_role,
+            "issue",
+            "Not my business <foo/bar#42>",
+            "Not my business",
+            "https://github.com/foo/bar/issues/42";,
+        ),
+        (
+            pr_role,
+            "pr",
+            "42",
+            "#42",
+            "https://github.com/marshmallow-code/marshmallow/pull/42";,
+        ),
+        (user_role, "user", "sloria", "@sloria", "https://github.com/sloria";),
+        (
+            user_role,
+            "user",
+            "Steven Loria <sloria>",
+            "Steven Loria",
+            "https://github.com/sloria";,
+        ),
+        (
+            cve_role,
+            "cve",
+            "CVE-2018-17175",
+            "CVE-2018-17175",
+            "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-17175";,
+        ),
+        (
+            cwe_role,
+            "cve",
+            "CWE-787",
+            "CWE-787",
+            "https://cwe.mitre.org/data/definitions/787.html";,
+        ),
+        (
+            commit_role,
+            "commit",
+            "123abc456def",
+            "@123abc4",
+            
"https://github.com/marshmallow-code/marshmallow/commit/123abc456def";,
+        ),
+        # External issue
+        (
+            issue_role,
+            "issue",
+            "sloria/webargs#42",
+            "sloria/webargs#42",
+            "https://github.com/sloria/webargs/issues/42";,
+        ),
+        # External PR
+        (
+            pr_role,
+            "pr",
+            "sloria/webargs#42",
+            "sloria/webargs#42",
+            "https://github.com/sloria/webargs/pull/42";,
+        ),
+        # External commit
+        (
+            commit_role,
+            "commit",
+            "sloria/webargs@abc123def456",
+            "sloria/webargs@abc123d",
+            "https://github.com/sloria/webargs/commit/abc123def456";,
+        ),
+    ],
+)
+def test_roles(inliner, role, role_name, text, expected_text, expected_url):
+    result = role(role_name, rawtext="", text=text, lineno=None, 
inliner=inliner)
+    link = result[0][0]
+    assert link.astext() == expected_text
+    assert link.attributes["refuri"] == expected_url
+
+
+def test_issue_role_multiple(inliner):
+    result = issue_role(
+        name=None, rawtext="", text="a title <42>,43", inliner=inliner, 
lineno=None
+    )
+    link1 = result[0][0]
+    assert link1.astext() == "a title"
+    issue_url = "https://github.com/marshmallow-code/marshmallow/issues/";
+    assert link1.attributes["refuri"] == issue_url + "42"
+
+    sep = result[0][1]
+    assert sep.astext() == ", "
+
+    link2 = result[0][2]
+    assert link2.astext() == "#43"
+    assert link2.attributes["refuri"] == issue_url + "43"
+
+
+def test_issue_role_multiple_with_external(inliner):
+    result = issue_role(
+        "issue", rawtext="", text="42,sloria/konch#43", inliner=inliner, 
lineno=None
+    )
+    link1 = result[0][0]
+    assert link1.astext() == "#42"
+    issue_url = "https://github.com/marshmallow-code/marshmallow/issues/42";
+    assert link1.attributes["refuri"] == issue_url
+
+    sep = result[0][1]
+    assert sep.astext() == ", "
+
+    link2 = result[0][2]
+    assert link2.astext() == "sloria/konch#43"
+    assert link2.attributes["refuri"] == 
"https://github.com/sloria/konch/issues/43";
+
+
+@pytest.fixture
+def app_custom_uri():
+    src, doctree, confdir, outdir = [mkdtemp() for _ in range(4)]
+    sphinx.application.Sphinx._log = lambda self, message, wfile, nonl=False: 
None
+    app = sphinx.application.Sphinx(
+        srcdir=src, confdir=None, outdir=outdir, doctreedir=doctree, 
buildername="html"
+    )
+    issues_setup(app)
+    # Stitch together as the sphinx app init() usually does w/ real conf files
+    app.config._raw_config = {
+        "issues_default_group_project": "myteam/super_great_project",
+        "issues_uri": 
"https://gitlab.company.com/{group}/{project}/-/issues/{issue}";,
+        "issues_prefix": "#",
+        "issues_pr_uri": 
"https://gitlab.company.com/{group}/{project}/-/merge_requests/{pr}";,
+        "issues_pr_prefix": "!",
+        "issues_commit_uri": 
"https://gitlab.company.com/{group}/{project}/-/commit/{commit}";,
+        "issues_commit_prefix": "@",
+        "issues_user_uri": "https://gitlab.company.com/{user}";,
+        "issues_user_prefix": "@",
+    }
+    try:
+        app.config.init_values()
+    except TypeError:
+        app.config.init_values(lambda x: x)
+    yield app
+    [rmtree(x) for x in (src, doctree, confdir, outdir)]
+
+
+@pytest.fixture()
+def inliner_custom_uri(app_custom_uri):
+    return Mock(document=Mock(settings=Mock(env=Mock(app=app_custom_uri))))
+
+
+@pytest.mark.parametrize(
+    ("role", "role_name", "text", "expected_text", "expected_url"),
+    [
+        (
+            issue_role,
+            "issue",
+            "42",
+            "#42",
+            
"https://gitlab.company.com/myteam/super_great_project/-/issues/42";,
+        ),
+        (
+            issue_role,
+            "issue",
+            "Hard Issue <42>",
+            "Hard Issue",
+            
"https://gitlab.company.com/myteam/super_great_project/-/issues/42";,
+        ),
+        (
+            issue_role,
+            "issue",
+            "Not my business <foo/bar#42>",
+            "Not my business",
+            "https://gitlab.company.com/foo/bar/-/issues/42";,
+        ),
+        (
+            pr_role,
+            "pr",
+            "42",
+            "!42",
+            
"https://gitlab.company.com/myteam/super_great_project/-/merge_requests/42";,
+        ),
+        (user_role, "user", "sloria", "@sloria", 
"https://gitlab.company.com/sloria";),
+        (
+            user_role,
+            "user",
+            "Steven Loria <sloria>",
+            "Steven Loria",
+            "https://gitlab.company.com/sloria";,
+        ),
+        (
+            commit_role,
+            "commit",
+            "123abc456def",
+            "@123abc4",
+            
"https://gitlab.company.com/myteam/super_great_project/-/commit/123abc456def";,
+        ),
+        # External issue
+        (
+            issue_role,
+            "issue",
+            "sloria/webargs#42",
+            "sloria/webargs#42",
+            "https://gitlab.company.com/sloria/webargs/-/issues/42";,
+        ),
+        # External PR
+        (
+            pr_role,
+            "pr",
+            "sloria/webargs#42",
+            "sloria/webargs!42",
+            "https://gitlab.company.com/sloria/webargs/-/merge_requests/42";,
+        ),
+        # External commit
+        (
+            commit_role,
+            "commit",
+            "sloria/webargs@abc123def456",
+            "sloria/webargs@abc123d",
+            "https://gitlab.company.com/sloria/webargs/-/commit/abc123def456";,
+        ),
+    ],
+)
+def test_roles_custom_uri(
+    inliner_custom_uri, role, role_name, text, expected_text, expected_url
+):
+    result = role(
+        role_name, rawtext="", text=text, lineno=None, 
inliner=inliner_custom_uri
+    )
+    link = result[0][0]
+    assert link.astext() == expected_text
+    assert link.attributes["refuri"] == expected_url
+
+
+@pytest.fixture
+def tmp_doc_build_folder(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> 
Path:
+    """Generate a temporary source folder and chdir in it. Return the build 
folder"""
+    source = tmp_path / "source"
+    build = tmp_path / "build"
+    static = source / "_static"
+    for folder in (source, build, static):
+        folder.mkdir()
+    conf_py = BASE_DIR / "source" / "conf.py"
+    examples_rst = BASE_DIR / "source" / "examples.rst"
+
+    source.joinpath("conf.py").write_bytes(conf_py.read_bytes())
+    source.joinpath("index.rst").write_bytes(examples_rst.read_bytes())
+
+    monkeypatch.chdir(source)
+    return build
+
+
+def test_sphinx_build_integration(tmp_doc_build_folder: Path):
+    """Ensure that a simulated complete sphinx run works as expected"""
+    subprocess.run(
+        [
+            Path(sys.executable).parent.joinpath("sphinx-build"),
+            "-b",
+            "html",
+            "-W",  # turn warnings into errors
+            "-E",  # force rebuild of environment (even if we work in tmp)
+            ".",
+            str(tmp_doc_build_folder),
+        ],
+        check=True,
+    )
+
+    created = tmp_doc_build_folder / "index.html"
+    assert created.exists() and created.is_file()
+    content = created.read_text()
+    issue_url = 
"https://gitlab.company.com/myteam/super_great_project/-/issues/";
+    other_issue_url = "https://gitlab.company.com/sloria/konch/-/issues/";
+    pr_url = 
"https://gitlab.company.com/myteam/super_great_project/-/merge_requests/";
+    user_url = "https://gitlab.company.com/";
+
+    # We could do something fancy like an HTML parser or regex:
+    # Instead we keep it simple
+    expected_strings = (
+        (
+            f"See issues "
+            f'<a class="reference external" href="{issue_url}12">#12</a>, '
+            f'<a class="reference external" href="{issue_url}13">#13</a>'
+        ),
+        (
+            f"See other issues "
+            f'<a class="reference external" 
href="{other_issue_url}45">sloria/konch#45</a>,'
+            f' <a class="reference external" href="{issue_url}46">#46</a>'
+        ),
+        (
+            f'See PR <a class="reference external" href="{pr_url}58">!58</a>, '
+            f'thanks <a class="reference external" 
href="{user_url}kound">&#64;kound</a>'
+        ),
+    )
+    # Ensure that we do no check character wise but line wise
+    assert len(expected_strings) == 3
+
+    for expected in expected_strings:
+        assert expected in content
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-issues-1.2.0/tox.ini 
new/sphinx-issues-3.0.1/tox.ini
--- old/sphinx-issues-1.2.0/tox.ini     2018-12-26 17:05:00.000000000 +0100
+++ new/sphinx-issues-3.0.1/tox.ini     2022-01-11 17:41:14.000000000 +0100
@@ -1,13 +1,14 @@
 [tox]
-envlist = lint,py27,py35,py36,py37
+envlist = lint,py36,py37,py38,py39,py310
 
 [testenv]
 extras = tests
 commands = pytest {posargs}
 
 [testenv:lint]
-extras = lint
-commands = pre-commit run --all-files --show-diff-on-failure
+deps = pre-commit~=2.7
+skip_install = true
+commands = pre-commit run --all-files
 
 ; Below tasks are for development only (not run in CI)
 [testenv:watch-readme]

Reply via email to