hallmark icon indicating copy to clipboard operation
hallmark copied to clipboard

Custom/Self-Hosted Git Support

Open tricktron opened this issue 5 months ago • 3 comments

Hello @vweevers,

I tried to test hallmark but it immediately fails with: Error: Unable to parse git host URL "ssh://[email protected]/a/b.git". It looks like that custom/self-hosted domains are not supported by one of Hallmark's dependencies:

E.g. Hallmark -> find-githost -> hosted-git-info which looks like to only support a hardcoded list of public git hosts, e.g. github.com, gitlab.com, bitbucket.org, sourcehut.

Is it possible/feasible to add custom git domain support to the find-githost lib as a fallback when hosted-git-info fails? Or even replacing the hosted-git-info with a dependency that has support for every git url irrespective of the provider? Feel free to move this issue to the find-githost repo if it fits better there.

tricktron avatar Nov 11 '25 14:11 tricktron

Sure, we can find a solution for this. With some constraints:

  • We can't support any URL, it has to be a known hoster so that we can e.g. derive the URL of issues (some of hallmark's plugins do still use hardcoded GitHub URLs like here but I've been meaning to fix that using find-githost)
  • This means it requires user configuration e.g. through .hallmarkrc
  • I prefer not to replace or fork hosted-git-info (frankly not worth the effort).

There is an API we can use: hosted-git-info has an addHost method to add custom domains, but it requires passing in a lot of information (example).

I propose reducing that to a set of known types (or maybe "hosters") to function as a template. So you'd put in .hallmarkrc:

{
  "githosts": {
    "my_custom_host": {
      "type": "bitbucket"
      "domain": "bitbucket.custom.domain"
    }
  }
}

And then find-githost and/or hallmark (TBD) would clone the options of the bitbucket host. I.e.

const hosts = require('hosted-git-info/lib/hosts')

GitHost.addHost('my_custom_host', {
  ...hosts.bitbucket,
  domain: 'bitbucket.custom.domain'
}

Downsides (that I'm okay with):

  • It requires reaching into hosted-git-info lib internals
  • It mutates global state
  • It puts a minor burden on the consumer (you) to configure hallmark before it's usable.

WDYT

vweevers avatar Nov 11 '25 15:11 vweevers

@vweevers Thanks for the proposal! I like the template-based approach with configuration. What now follows are just some brainstorming ideas I had to avoid reaching into hosted-git-info lib internals because I don´t like the tight coupling:

Alternative: Define Our Own Templates

Instead of cloning from hosted-git-info internals, we can define our own custom templates.

Both hosted-git-info.fromUrl() and custom providers can return the same object shape (the "nut" interface). The existing GitHost class already wraps both.

function parse(url, options) {
  // Try hosted-git-info first (github.com, gitlab.com, bitbucket.org)
  let provider = hostedGitInfo.fromUrl(url, options)

  if (!provider) {
    // Fallback: use our templates for custom domains
    const template = getTemplateForUrl(url, options.githosts)
    provider = createCustomProvider(url, template)
  }

  return new GitHost(url, provider, options)
}

Then createCustomProvider returns an object with the same shape as hosted-git-info:

  function createCustomProvider(url, template) {
    const { domain, owner, repo } = parseUrl(url)

    return {
      // Properties (same as hosted-git-info)
      type: 'custom',
      domain,
      owner,
      repo,
      default: 'sshurl',

      // Methods (same interface as hosted-git-info)
      ssh: () => `git@${domain}:${owner}/${repo}.git`,
      https: () => `https://${domain}/${owner}/${repo}.git`,
      browse: (path, fragment, opts) => template.browse(domain, owner, repo, path, fragment, opts),
      bugs: () => template.bugs(domain, owner, repo),
      // ... all other methods
    }
  }

And then we use your proposed configuration to create the custom templates:

{
  "githosts": {
    "my_custom_host": {
      "type": "bitbucket"
      "domain": "bitbucket.custom.domain"
    }
  }
}

Benefits:

  • ✅ No tight coupling to hosted-git-info
  • ✅ Easy to replace hosted-git-info entirely later if needed

Tradeoff: We maintain our own URL pattern templates (but they're simple).

tricktron avatar Nov 11 '25 19:11 tricktron

@vweevers What do you think about this? Any plans to implement this?

tricktron avatar Dec 01 '25 16:12 tricktron