Configure a Zulip Linkifier to expand GitLab links with regex pattern and URL

GitLab issues and commits are slightly more complex than GitHub because GitLab allows organizations (groups) to have sub-groups.

Thus, here is our capturing regex, allowing a slash in the repo:

(?P<org>[a-zA-Z0-9_-]+)/(?P<repo>[a-zA-Z0-9_/-]+)#(?P<id>[0-9]+)

To test it with standard regex we need to escape the slashes:

(?P<org>[a-zA-Z0-9_-]+)\/(?P<repo>[a-zA-Z0-9_\/-]+)#(?P<id>[0-9]+)

This gets complicated fast, but hey, that’s RegEx

As i wrote on a possibly unrelated Linkifier testing issue:

Would any of this cover how linkifiers are supposed to overlap? Our use case is that most of our work is on GitLab, so we want the short-org/repo#123 form to go to GitLab, but to be able to preface that with gh: to make the GitHub. As it happens, the GitHub linkifier works, but the GitLab linkifier also works, so only the “gh:” gets linked to GitHub and the rest links to a non-existent GitLab. Presumably the solution is regular expressions (excluding strings that start with gh: from the GitLab pattern) but i feel the interaction between linkifiers is worth documenting and testing. (Related, would editing of Linkifiers be a reasonable feature request?)

Sorry for jumping in here, thanks for all the great work!

Testing out how to exclude any string that starts with gh: using “negative lookbehind” on https://regexr.com/ with gh:zulip/zulip#134 in the body of text as the test i’m trying to get my GitLab matching code to not match.

Negative lookbehind “Specifies a group that can not match before the main expression (if it matches, the result is discarded).”

But when i use it, even adding extra parenthesis, it only discards the first letter of the rest of the regex, what i would call the main expression:

(?<!gh:)((?P<org>[a-zA-Z0-9_-]+)\/(?P<repo>[a-zA-Z0-9_-]+)#(?P<id>[0-9]+))

while (?<!gh:*+\b)((?P<org>[a-zA-Z0-9_-]+)\/(?P<repo>[a-zA-Z0-9_-]+)#(?P<id>[0-9]+)) produces an error:

“Compilation failed: lookbehind assertion is not fixed length”

Lookbehind would then seem to be useless to me, as what i’m trying to get it to ignore is necessarily not fixed length.

Reference