Linux maintainer tooling and workflows
 help / color / mirror / Atom feed
* [PATCH v2] review: Generate thanks commit URLs for known repositories automatically
@ 2026-09-12 10:58 Mark Brown
  0 siblings, 0 replies; only message in thread
From: Mark Brown @ 2026-09-12 10:58 UTC (permalink / raw)
  To: Konstantin Ryabitsev; +Cc: tools, Mark Brown

At present generating links to commits in web interfaces for inclusion
in thanks mails requires manual configuration of a global configuration
option b4.thanks-commit-url-mask, or the per remote equivalent
b4-thanks-url-mask.  Given that we also have the b4-check-repo option to
configure where to check to see if thanks are ready to be sent and
practically speaking this is likely to be one of a very small set of
hosting providers this is all a bit redundant.

If one of git.kernel.org, github or gitlab is configured for the check
repo or remote URL for the branch then default to generating a link
based on our knowledge of the remote, a manual configuration will still
override the default.

Signed-off-by: Mark Brown <broonie@kernel.org>
---

Also fall back to the remote URL.

 docs/config.rst                             |  32 ++++-
 docs/maintainer/review.rst                  |  15 +--
 src/b4/command.py                           |   4 +
 src/b4/review_tui/_tracking_app.py          |   4 +-
 src/b4/templates/thanks-am-template.example |   3 +
 src/b4/templates/thanks-pr-template.example |   3 +
 src/b4/ty.py                                | 131 +++++++++++++++-----
 src/tests/test_tui_tracking.py              |  45 +++++++
 src/tests/test_ty.py                        |  88 +++++++++++++
 9 files changed, 281 insertions(+), 44 deletions(-)

diff --git a/docs/config.rst b/docs/config.rst
index 4dce689..91d783e 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -463,6 +463,11 @@ Attestation settings
          [remote "spi"]
              b4-check-repo = https://git.kernel.org/pub/scm/linux/kernel/git/username/spi.git
 
+     For recognized HTTP(S) web hosts (currently git.kernel.org,
+     github.com, and gitlab.com), b4 also uses this URL to link commits in
+     the thank-you message. Other transports and hosting layouts can use
+     the per-remote ``b4-commit-url-mask`` described below.
+
      See :ref:`queuing thanks <thanks_queue>` for details.
 
      Default: ``None``
@@ -471,14 +476,29 @@ Attestation settings
      Used when creating summaries for ``b4 ty`` and the review TUI
      thank-you flow. Can be a value like::
 
-         thanks-commit-url-mask = https://git.kernel.org/username/c/%.12s
+         thanks-commit-url-mask = https://git.kernel.org/username/tree/c/%.12s
+
+     If no explicit mask or recognized check-repository URL is available,
+     b4 falls back to using commit hashes.
 
-     If not set, b4 falls back to using commit hashes.
+     For repositories with multiple remotes, an explicit per-remote mask
+     takes precedence over this setting::
 
-     When this option is set, the review TUI's thank-you preview offers
-     a **Queue** option that stores the message for delayed delivery.
-     Queued messages are held until their commit is verified published,
-     so you can push your commits before the thank-you is sent.
+         [remote "spi"]
+             b4-commit-url-mask = https://git.kernel.org/username/spi/c/%.12s
+
+     When no explicit per-remote mask is set, b4 automatically derives one
+     from that remote's ``b4-check-repo`` for recognized HTTP(S) web hosts.
+     The same derivation is attempted from :term:`b4.thanks-check-repo`, and
+     then from the URL of the remote the target branch tracks, when neither
+     a per-remote nor this global mask is available — the same repository
+     URLs, in the same order, that :term:`b4.thanks-check-repo` resolution
+     uses. A URL that is not a recognized web host is simply skipped.
+
+     When a commit URL can be generated, the review TUI's thank-you preview
+     offers a **Queue** option that stores the message for delayed delivery.
+     Queued messages are held until their commit is verified published, so
+     you can push your commits before the thank-you is sent.
      See :ref:`queuing thanks <thanks_queue>` for details.
 
      .. note::
diff --git a/docs/maintainer/review.rst b/docs/maintainer/review.rst
index 47aa8e7..842120b 100644
--- a/docs/maintainer/review.rst
+++ b/docs/maintainer/review.rst
@@ -1023,13 +1023,14 @@ screen shows the generated message with keybindings to **Send**
 
 **Queuing thanks for delayed delivery**
 
-When :term:`b4.thanks-commit-url-mask` is configured, the thank-you
-preview also offers a **Queue** option (``W``). Queuing writes the
-message as an RFC 2822 file in ``.git/b4-review/queue/`` instead of
-sending it immediately. This is useful when you want to push your
-commits to a public tree before sending thank-you messages — the
-message references commit URLs that may not resolve until the push is
-complete.
+When b4 can generate a web link for the commit — from
+:term:`b4.thanks-commit-url-mask`, a per-remote ``b4-commit-url-mask``, or
+a recognized HTTP(S) check-repository or remote URL — the thank-you preview
+also offers a **Queue** option (``W``). Queuing writes the message as an RFC 2822
+file in ``.git/b4-review/queue/`` instead of sending it immediately. This
+is useful when you want to push your commits to a public tree before
+sending thank-you messages — the message references commit URLs that may
+not resolve until the push is complete.
 
 Files are named ``{change-id}-v{revision}.msg`` and the check target is
 recorded as ``X-Check-URL``, ``X-Check-Commit``, ``X-Check-Repo`` and
diff --git a/src/b4/command.py b/src/b4/command.py
index 00c4c84..41bb9ae 100644
--- a/src/b4/command.py
+++ b/src/b4/command.py
@@ -249,6 +249,10 @@ def cmd_pr(cmdargs: argparse.Namespace) -> None:
 def cmd_ty(cmdargs: argparse.Namespace) -> None:
     import b4.ty
 
+    if cmdargs.gitdir:
+        # The initial setup happens relative to cwd. Reload repository-local
+        # thank-you settings when -g names a different tree.
+        b4.setup_config(cmdargs, topdir=cmdargs.gitdir)
     b4.ty.main(cmdargs)
 
 
diff --git a/src/b4/review_tui/_tracking_app.py b/src/b4/review_tui/_tracking_app.py
index 4c25f8c..0f39b8f 100644
--- a/src/b4/review_tui/_tracking_app.py
+++ b/src/b4/review_tui/_tracking_app.py
@@ -4926,8 +4926,8 @@ class TrackingApp(LoreNodeShutdownMixin, CheckRunnerMixin, App[Optional[str]]):
         # Compute checkurl from last taken commit for queue support
         checkurl: Optional[str] = None
         checkcommit: Optional[str] = None
-        cidmask = config.get('thanks-commit-url-mask')
-        if isinstance(cidmask, str) and cidmask and '%' in cidmask:
+        cidmask = b4.ty.get_commit_url_mask(topdir, target_branch)
+        if cidmask and '%' in cidmask:
             # Find the last commit ID (highest patch index with a commit)
             last_cid: Optional[str] = None
             for _idx, cid in commits:
diff --git a/src/b4/templates/thanks-am-template.example b/src/b4/templates/thanks-am-template.example
index b2c8986..bac889a 100644
--- a/src/b4/templates/thanks-am-template.example
+++ b/src/b4/templates/thanks-am-template.example
@@ -20,6 +20,9 @@ ${quote}
 #   url = https://...
 #   fetch = ...
 #   b4-treename = uname/sound.git
+#   b4-check-repo = https://git.kernel.org/pub/scm/linux/kernel/git/uname/sound.git
+# The check repo is also used to generate commit links for known web hosts.
+# For other hosts, or to choose a different link format, set an explicit mask:
 #   b4-commit-url-mask = https://git.kernel.org/uname/sound/c/%.8s
 Applied to ${branch}, thanks!
 
diff --git a/src/b4/templates/thanks-pr-template.example b/src/b4/templates/thanks-pr-template.example
index 13bd205..afae499 100644
--- a/src/b4/templates/thanks-pr-template.example
+++ b/src/b4/templates/thanks-pr-template.example
@@ -20,6 +20,9 @@ ${quote}
 #   url = https://...
 #   fetch = ...
 #   b4-treename = uname/sound.git
+#   b4-check-repo = https://git.kernel.org/pub/scm/linux/kernel/git/uname/sound.git
+# The check repo is also used to generate commit links for known web hosts.
+# For other hosts, or to choose a different link format, set an explicit mask:
 #   b4-commit-url-mask = https://git.kernel.org/uname/sound/c/%.8s
 Merged into ${branch}, thanks!
 
diff --git a/src/b4/ty.py b/src/b4/ty.py
index bbce149..9aca439 100644
--- a/src/b4/ty.py
+++ b/src/b4/ty.py
@@ -13,6 +13,7 @@ import json
 import os
 import re
 import sys
+import urllib.parse
 from email.message import EmailMessage
 from pathlib import Path
 from string import Template
@@ -61,8 +62,6 @@ ${signature}
 
 # Used to track commits created by current user
 MY_COMMITS: Optional[Dict[str, Tuple[str, str, List[str]]]] = None
-# Used to track additional branch info
-BRANCH_INFO: Optional[Dict[str, str]] = None
 
 
 def git_get_merge_id(
@@ -294,6 +293,87 @@ def auto_locate_series(
     return found
 
 
+def _derive_commit_url_mask(repo: str) -> Optional[str]:
+    """Return a commit URL mask for known web repository layouts."""
+    try:
+        parsed = urllib.parse.urlparse(repo.rstrip('/'))
+        hostname = parsed.hostname
+        has_credentials = parsed.username is not None or parsed.password is not None
+    except ValueError:
+        return None
+    if parsed.scheme not in ('http', 'https') or not hostname:
+        return None
+    if has_credentials or parsed.query or parsed.fragment:
+        return None
+
+    hostname = hostname.lower()
+    path = parsed.path.rstrip('/')
+    if hostname in ('github.com', 'www.github.com', 'gitlab.com', 'www.gitlab.com'):
+        path = re.sub(r'\.git$', '', path)
+    if hostname == 'git.kernel.org':
+        repo_parts = re.sub(r'\.git$', '', path).strip('/').split('/')
+        if len(repo_parts) < 2 or not all(repo_parts):
+            return None
+        short_path = f'/{repo_parts[-2]}/{repo_parts[-1]}'
+        base = urllib.parse.urlunparse(
+            (parsed.scheme, parsed.netloc, short_path, '', '', '')
+        ).replace('%', '%%')
+        return f'{base}/c/%.12s'
+    base = urllib.parse.urlunparse(
+        (parsed.scheme, parsed.netloc, path, '', '', '')
+    ).replace('%', '%%')
+    if hostname in ('github.com', 'www.github.com'):
+        return f'{base}/commit/%s'
+    if hostname in ('gitlab.com', 'www.gitlab.com'):
+        return f'{base}/-/commit/%s'
+    return None
+
+
+def _get_commit_url_mask(config: ConfigDictT, binfo: Dict[str, str]) -> Optional[str]:
+    """Resolve the commit URL mask for one branch's remote.
+
+    An explicit mask always wins, per-remote before global. Failing that
+    we derive one from the same repository URLs check-repo resolution
+    uses, in the same order: the per-remote b4-check-repo, the
+    b4.thanks-check-repo config option, then the branch's remote URL. A
+    URL we cannot derive a mask from does not end the search, so an
+    unrecognized check repo still gets a link if the remote URL is a host
+    we know. See get_check_repo_for_branch().
+    """
+    if 'b4-commit-url-mask' in binfo:
+        return binfo['b4-commit-url-mask'] or None
+
+    checkrepo = binfo.get('b4-check-repo')
+    if checkrepo:
+        cidmask = _derive_commit_url_mask(checkrepo)
+        if cidmask:
+            return cidmask
+
+    global_cidmask = config.get('thanks-commit-url-mask')
+    if global_cidmask:
+        assert isinstance(global_cidmask, str), (
+            'thanks-commit-url-mask must be a string'
+        )
+        return global_cidmask
+
+    global_checkrepo = config.get('thanks-check-repo')
+    if global_checkrepo:
+        assert isinstance(global_checkrepo, str), 'thanks-check-repo must be a string'
+        cidmask = _derive_commit_url_mask(global_checkrepo)
+        if cidmask:
+            return cidmask
+
+    remoteurl = binfo.get('url')
+    if remoteurl:
+        return _derive_commit_url_mask(remoteurl)
+    return None
+
+
+def get_commit_url_mask(gitdir: Optional[str], branch: str) -> Optional[str]:
+    """Return the effective commit URL mask for a branch."""
+    return _get_commit_url_mask(b4.get_main_config(), get_branch_info(gitdir, branch))
+
+
 def set_branch_details(
     gitdir: Optional[str], branch: str, jsondata: JsonDictT, config: ConfigDictT
 ) -> Tuple[JsonDictT, ConfigDictT]:
@@ -302,8 +382,6 @@ def set_branch_details(
     for key, val in binfo.items():
         if key == 'b4-treename':
             config['thanks-treename'] = val
-        elif key == 'b4-commit-url-mask':
-            config['thanks-commit-url-mask'] = val
         elif key == 'b4-pr-template':
             config['thanks-pr-template'] = val
         elif key == 'b4-am-template':
@@ -311,6 +389,8 @@ def set_branch_details(
         elif key == 'branch':
             jsondata['branch'] = val
 
+    config['thanks-commit-url-mask'] = _get_commit_url_mask(config, binfo)
+
     if 'thanks-treename' in config and isinstance(config['thanks-treename'], str):
         jsondata['treename'] = config['thanks-treename']
     elif 'url' in binfo:
@@ -330,7 +410,7 @@ def set_branch_details(
 def generate_pr_thanks(
     gitdir: Optional[str], jsondata: JsonDictT, branch: str, cmdargs: argparse.Namespace
 ) -> EmailMessage:
-    config = b4.get_main_config()
+    config = b4.get_main_config().copy()
     jsondata, config = set_branch_details(gitdir, branch, jsondata, config)
     thanks_template = DEFAULT_PR_TEMPLATE
     _ctpr = config.get('thanks-pr-template')
@@ -369,9 +449,7 @@ def generate_pr_thanks(
 def generate_am_thanks(
     gitdir: Optional[str], jsondata: JsonDictT, branch: str, cmdargs: argparse.Namespace
 ) -> EmailMessage:
-    global BRANCH_INFO
-    BRANCH_INFO = None
-    config = b4.get_main_config()
+    config = b4.get_main_config().copy()
     jsondata, config = set_branch_details(gitdir, branch, jsondata, config)
     thanks_template = DEFAULT_AM_TEMPLATE
     _ctat = config.get('thanks-am-template')
@@ -900,7 +978,6 @@ def check_stale_thanks(outdir: str) -> None:
 
 
 def get_wanted_branch(cmdargs: argparse.Namespace) -> str:
-    global BRANCH_INFO
     gitdir = cmdargs.gitdir
     if not cmdargs.branch:
         # Find out our current branch
@@ -995,7 +1072,7 @@ def _parse_checkurl(checkurl: str) -> Tuple[Optional[str], Optional[str]]:
     """Extract (repo_url, commit_id) from a thanks-commit-url-mask URL.
 
     The repo URL is only derivable from cgit/github/gitlab-style commit
-    URLs; for anything else (e.g. git.kernel.org /username/c/ shortlinks)
+    URLs; for anything else (e.g. git.kernel.org /username/tree/c/ shortlinks)
     we can usually still recover the commit id from a trailing hex run.
     Either element may be None.
     """
@@ -1037,10 +1114,6 @@ def get_check_repo_for_branch(
     3. the branch's remote URL
     4. a repo URL derived from the commit check URL
     """
-    # Long-lived callers (the TUI) thank series on different branches;
-    # never serve another branch's cached remote info
-    global BRANCH_INFO
-    BRANCH_INFO = None
     binfo = get_branch_info(gitdir, branch)
     crepo = binfo.get('b4-check-repo')
     if crepo:
@@ -1568,20 +1641,18 @@ def _process_queue_locked(
 
 
 def get_branch_info(gitdir: Optional[str], branch: str) -> Dict[str, str]:
-    global BRANCH_INFO
-    if BRANCH_INFO is not None:
-        return BRANCH_INFO
+    branch_info: Dict[str, str] = dict()
 
-    BRANCH_INFO = dict()
-
-    remotecfg = b4.get_config_from_git('branch\\.%s\\..*' % branch)
+    remotecfg = b4.get_config_from_git(
+        r'^branch\.%s\.' % re.escape(branch), gitdir=gitdir
+    )
     if 'remote' not in remotecfg:
         # Did not find a matching branch entry, so look at remotes
         gitargs = ['remote', 'show']
         lines = b4.git_get_command_lines(gitdir, gitargs)
         if not len(lines):
             # No remotes? Hmm...
-            return BRANCH_INFO
+            return branch_info
 
         remote = None
         for entry in lines:
@@ -1591,21 +1662,23 @@ def get_branch_info(gitdir: Optional[str], branch: str) -> Dict[str, str]:
 
         if remote is None:
             # Not found any matching remotes
-            return BRANCH_INFO
+            return branch_info
 
-        BRANCH_INFO['remote'] = remote
-        BRANCH_INFO['branch'] = branch.replace(f'{remote}/', '')
+        branch_info['remote'] = remote
+        branch_info['branch'] = branch.replace(f'{remote}/', '')
 
     else:
-        BRANCH_INFO['remote'] = remotecfg['remote']
+        branch_info['remote'] = remotecfg['remote']
         if 'merge' in remotecfg:
-            BRANCH_INFO['branch'] = re.sub(r'^refs/heads/', '', remotecfg['merge'])
+            branch_info['branch'] = re.sub(r'^refs/heads/', '', remotecfg['merge'])
 
     # Grab template overrides
-    remotecfg = b4.get_config_from_git('remote\\.%s\\..*' % BRANCH_INFO['remote'])
-    BRANCH_INFO.update(remotecfg)
+    remotecfg = b4.get_config_from_git(
+        r'^remote\.%s\.' % re.escape(branch_info['remote']), gitdir=gitdir
+    )
+    branch_info.update(remotecfg)
 
-    return BRANCH_INFO
+    return branch_info
 
 
 def main(cmdargs: argparse.Namespace) -> None:
diff --git a/src/tests/test_tui_tracking.py b/src/tests/test_tui_tracking.py
index e3d79ef..1e064cf 100644
--- a/src/tests/test_tui_tracking.py
+++ b/src/tests/test_tui_tracking.py
@@ -2931,6 +2931,51 @@ class TestSeriesLifecycle:
         # Only the two taken patches contribute commits (by 1-based index).
         assert jsondata['commits'] == [(1, 'aaa111'), (2, 'bbb222')]
 
+    def test_thank_preview_uses_branch_check_repo_url(self, gitdir: str) -> None:
+        """The queue target uses the same per-remote URL as the message."""
+        from unittest import mock
+
+        checkrepo = 'https://git.kernel.org/pub/scm/linux/kernel/git/example/spi.git'
+        b4.git_set_config(gitdir, 'branch.for-next.remote', 'spi')
+        b4.git_set_config(gitdir, 'branch.for-next.merge', 'refs/heads/for-next')
+        b4.git_set_config(gitdir, 'remote.spi.b4-check-repo', checkrepo)
+        commit = '0123456789abcdef0123456789abcdef01234567'
+        tracking_data: Dict[str, Any] = {
+            'series': {
+                'header-info': {},
+                'taken': {'branch': 'for-next'},
+                'expected': 1,
+            },
+            'patches': [
+                {
+                    'title': '[PATCH] test patch',
+                    'header-info': {'msgid': 'patch@example.com'},
+                    'taken': {'commit-id': commit},
+                }
+            ],
+        }
+        series = {'change_id': 'test-change-id'}
+        app = mock.Mock()
+        generated = email.message.EmailMessage()
+
+        with (
+            patch('b4.git_get_toplevel', return_value=gitdir),
+            patch('b4.review.load_tracking', return_value=('cover', tracking_data)),
+            patch('b4.ty.generate_am_thanks', return_value=generated),
+            patch('b4.get_email_signature', return_value='Test'),
+        ):
+            TrackingApp._start_thank(app, series)
+
+        app._show_thank_preview.assert_called_once_with(
+            generated,
+            series,
+            checkurl=f'https://git.kernel.org/example/spi/c/{commit[:12]}',
+            checkcommit=commit,
+            archive_after=False,
+            checkrepo=checkrepo,
+            checkbranch='for-next',
+        )
+
     def test_partial_series_ingests_new_revision(self, gitdir: str) -> None:
         """A 'partial' series must ingest an incoming v2 and record it.
 
diff --git a/src/tests/test_ty.py b/src/tests/test_ty.py
index be132ff..50ec18b 100644
--- a/src/tests/test_ty.py
+++ b/src/tests/test_ty.py
@@ -7,6 +7,7 @@ from unittest import mock
 import pytest
 
 import b4
+import b4.command
 import b4.ty
 
 
@@ -62,6 +63,20 @@ def test_render_ty_review_layout() -> None:
     assert b4.ty.parse_ty_review(buf, sections) == set()
 
 
+def test_cmd_ty_reloads_config_for_gitdir(monkeypatch: pytest.MonkeyPatch) -> None:
+    """-g makes repository-local thank-you settings come from that tree."""
+    cmdargs = mock.Mock(gitdir='/other/repo')
+    setup_config = mock.Mock()
+    ty_main = mock.Mock()
+    monkeypatch.setattr(b4, 'setup_config', setup_config)
+    monkeypatch.setattr(b4.ty, 'main', ty_main)
+
+    b4.command.cmd_ty(cmdargs)
+
+    setup_config.assert_called_once_with(cmdargs, topdir='/other/repo')
+    ty_main.assert_called_once_with(cmdargs)
+
+
 def test_parse_ty_review_marks_skips() -> None:
     """Flipping '+' to 'x' on an item marks it (by position) skipped."""
     sections = _review_sections()
@@ -436,6 +451,79 @@ def test_commit_reachable_uses_the_gitdir_it_is_given(
     )
 
 
+@pytest.mark.parametrize(
+    'repo,mask',
+    [
+        (
+            'https://git.kernel.org/pub/scm/linux/kernel/git/example/spi.git',
+            'https://git.kernel.org/example/spi/c/%.12s',
+        ),
+        ('https://github.com/user/repo.git', 'https://github.com/user/repo/commit/%s'),
+        (
+            'https://gitlab.com/group/repo.git',
+            'https://gitlab.com/group/repo/-/commit/%s',
+        ),
+        # Unrecognized host, and transports we cannot map to a web view
+        ('https://example.com/spi.git', None),
+        ('git://git.kernel.org/pub/scm/linux/kernel/git/example/spi.git', None),
+        ('git@github.com:user/repo.git', None),
+    ],
+)
+def test_derive_commit_url_mask(repo: str, mask: Optional[str]) -> None:
+    assert b4.ty._derive_commit_url_mask(repo) == mask
+
+
+def test_get_commit_url_mask_priority(monkeypatch: pytest.MonkeyPatch) -> None:
+    """Mask resolution: explicit per-remote mask, then derivation from the
+    per-remote b4-check-repo, then the global mask, then derivation from
+    b4.thanks-check-repo and finally from the branch's remote URL."""
+    binfo = {'url': 'https://github.com/user/repo.git'}
+
+    # Nothing configured: the branch's remote URL is the last resort
+    assert (
+        b4.ty._get_commit_url_mask(b4.MAIN_CONFIG, binfo)
+        == 'https://github.com/user/repo/commit/%s'
+    )
+    # A check repo we cannot derive from does not stop the search
+    monkeypatch.setitem(
+        b4.MAIN_CONFIG, 'thanks-check-repo', 'https://example.com/r.git'
+    )
+    assert (
+        b4.ty._get_commit_url_mask(b4.MAIN_CONFIG, binfo)
+        == 'https://github.com/user/repo/commit/%s'
+    )
+    # b4.thanks-check-repo beats the remote URL
+    monkeypatch.setitem(
+        b4.MAIN_CONFIG, 'thanks-check-repo', 'https://gitlab.com/group/repo.git'
+    )
+    assert (
+        b4.ty._get_commit_url_mask(b4.MAIN_CONFIG, binfo)
+        == 'https://gitlab.com/group/repo/-/commit/%s'
+    )
+    # The global mask beats anything derived from a check repo
+    monkeypatch.setitem(
+        b4.MAIN_CONFIG, 'thanks-commit-url-mask', 'https://example.com/c/%.8s'
+    )
+    assert (
+        b4.ty._get_commit_url_mask(b4.MAIN_CONFIG, binfo)
+        == 'https://example.com/c/%.8s'
+    )
+    # remote.<name>.b4-check-repo beats the global mask
+    binfo['b4-check-repo'] = (
+        'https://git.kernel.org/pub/scm/linux/kernel/git/example/spi.git'
+    )
+    assert (
+        b4.ty._get_commit_url_mask(b4.MAIN_CONFIG, binfo)
+        == 'https://git.kernel.org/example/spi/c/%.12s'
+    )
+    # ... and an explicit per-remote mask beats everything
+    binfo['b4-commit-url-mask'] = 'https://example.com/spi/c/%.10s'
+    assert (
+        b4.ty._get_commit_url_mask(b4.MAIN_CONFIG, binfo)
+        == 'https://example.com/spi/c/%.10s'
+    )
+
+
 def test_get_check_repo_for_branch_priority(
     monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
 ) -> None:
-- 
2.47.3


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-12 10:58 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-12 10:58 [PATCH v2] review: Generate thanks commit URLs for known repositories automatically Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox