ref(installerconf): rename config keys and add full URL support

Renames:
- github_repo → github_releases (back-compat kept)
- github_source → github_sources (back-compat kept)
- gitea_repo → gitea_releases (back-compat kept)

New keys:
- gitea_sources, gitlab_releases, gitlab_sources

All keys now accept either owner/repo shorthand or full URLs:
- github_releases = sharkdp/bat
- github_releases = https://github.com/sharkdp/bat
- gitea_releases = https://git.rootprojects.org/root/pathman

Defaults: github → github.com, gitlab → gitlab.com.
Gitea has no default (self-hosted only).

Updated all 73 releases.conf files from github_repo to github_releases.
This commit is contained in:
AJ ONeal
2026-03-11 11:51:43 -06:00
parent bd3bd85e43
commit 23100394ac
79 changed files with 268 additions and 113 deletions

View File

@@ -1,3 +1,3 @@
# Example releases.conf — uses ripgrep as a sample project.
# Copy this file into your package directory and adjust.
github_repo = BurntSushi/ripgrep
github_releases = BurntSushi/ripgrep

View File

@@ -1,2 +1,2 @@
github_source = BeyondCodeBootcamp/aliasman
github_sources = BeyondCodeBootcamp/aliasman
git_url = https://github.com/BeyondCodeBootcamp/aliasman.git

View File

@@ -1 +1 @@
github_repo = mholt/archiver
github_releases = mholt/archiver

View File

@@ -1 +1 @@
github_repo = wez/atomicparsley
github_releases = wez/atomicparsley

View File

@@ -1 +1 @@
github_repo = wallix/awless
github_releases = wallix/awless

View File

@@ -1 +1 @@
github_repo = sharkdp/bat
github_releases = sharkdp/bat

View File

@@ -1,4 +1,4 @@
github_repo = oven-sh/bun
github_releases = oven-sh/bun
tag_prefix = bun-
default_x86_64 = x86_64_v3
x86_64_v2 = baseline

View File

@@ -1 +1 @@
github_repo = caddyserver/caddy
github_releases = caddyserver/caddy

View File

@@ -1 +1 @@
github_repo = cilium/cilium-cli
github_releases = cilium/cilium-cli

View File

@@ -1 +1 @@
github_repo = Kitware/CMake
github_releases = Kitware/CMake

View File

@@ -1 +1 @@
github_repo = kivikakk/comrak
github_releases = kivikakk/comrak

View File

@@ -1 +1 @@
github_repo = sstadick/crabz
github_releases = sstadick/crabz

View File

@@ -1 +1 @@
github_repo = rs/curlie
github_releases = rs/curlie

View File

@@ -1 +1 @@
github_repo = dashpay/dash
github_releases = dashpay/dash

View File

@@ -1 +1 @@
github_repo = dashhive/dashmsg
github_releases = dashhive/dashmsg

View File

@@ -1 +1 @@
github_repo = dandavison/delta
github_releases = dandavison/delta

View File

@@ -1 +1 @@
github_repo = denoland/deno
github_releases = denoland/deno

View File

@@ -1 +1 @@
github_repo = dotenv-linter/dotenv-linter
github_releases = dotenv-linter/dotenv-linter

View File

@@ -1 +1 @@
github_repo = therootcompany/dotenv
github_releases = therootcompany/dotenv

View File

@@ -1,2 +1,2 @@
github_source = BeyondCodeBootcamp/DuckDNS.sh
github_sources = BeyondCodeBootcamp/DuckDNS.sh
git_url = https://github.com/BeyondCodeBootcamp/DuckDNS.sh.git

View File

@@ -1 +1 @@
github_repo = sharkdp/fd
github_releases = sharkdp/fd

View File

@@ -1,3 +1,3 @@
github_repo = eugeneware/ffmpeg-static
github_releases = eugeneware/ffmpeg-static
asset_filter = ffmpeg
version_prefix = b

View File

@@ -1 +1 @@
github_repo = ffuf/ffuf
github_releases = ffuf/ffuf

View File

@@ -1,2 +1,2 @@
github_repo = fish-shell/fish-shell
github_releases = fish-shell/fish-shell
exclude = bundledpcre fish-static OpenBeta

View File

@@ -1 +1 @@
github_repo = junegunn/fzf
github_releases = junegunn/fzf

View File

@@ -1 +1 @@
github_repo = cli/cli
github_releases = cli/cli

View File

@@ -1,4 +1,4 @@
github_repo = git-for-windows/git
github_releases = git-for-windows/git
asset_filter = MinGit
exclude = busybox
variants = installer

View File

@@ -1 +1 @@
github_repo = therootcompany/gitdeploy
github_releases = therootcompany/gitdeploy

View File

@@ -1,2 +1,2 @@
github_repo = go-gitea/gitea
github_releases = go-gitea/gitea
exclude = -src- -docs-

View File

@@ -1 +1 @@
github_repo = goreleaser/goreleaser
github_releases = goreleaser/goreleaser

View File

@@ -1 +1 @@
github_repo = creedasaurus/gprox
github_releases = creedasaurus/gprox

View File

@@ -1 +1 @@
github_repo = anchore/grype
github_releases = anchore/grype

View File

@@ -1 +1 @@
github_repo = sharkdp/hexyl
github_releases = sharkdp/hexyl

View File

@@ -1,3 +1,3 @@
github_repo = gohugoio/hugo
github_releases = gohugoio/hugo
asset_filter = extended
exclude = Linux-64bit

View File

@@ -1,2 +1,2 @@
github_repo = gohugoio/hugo
github_releases = gohugoio/hugo
exclude = extended Linux-64bit

View File

@@ -6,24 +6,30 @@
//
// The source type is inferred from the primary key:
//
// GitHub releases (covers ~70% of packages):
// GitHub releases (binary assets):
//
// github_repo = sharkdp/bat
// github_releases = sharkdp/bat
// github_releases = https://github.com/sharkdp/bat
//
// GitHub sources (tarball/zipball/git for source-installable packages):
//
// github_sources = BeyondCodeBootcamp/aliasman
// git_url = https://github.com/BeyondCodeBootcamp/aliasman.git
//
// With version prefix stripping (jq tags are "jq-1.7.1"):
//
// github_repo = jqlang/jq
// github_releases = jqlang/jq
// version_prefixes = jq-
//
// With filename exclusions and variant documentation:
//
// github_repo = gohugoio/hugo
// github_releases = gohugoio/hugo
// exclude = _extended_ Linux-64bit
// variants = extended extended_withdeploy
//
// Monorepo with tag prefix:
//
// github_repo = therootcompany/golib
// github_releases = therootcompany/golib
// tag_prefix = tools/monorel/
//
// Git tag sources (vim plugins, etc.):
@@ -32,9 +38,14 @@
//
// Gitea releases:
//
// gitea_repo = root/pathman
// gitea_releases = root/pathman
// base_url = https://git.rootprojects.org
//
// GitLab releases:
//
// gitlab_releases = owner/repo
// base_url = https://gitlab.com
//
// HashiCorp releases:
//
// hashicorp_product = terraform
@@ -54,13 +65,15 @@ package installerconf
import (
"bufio"
"fmt"
"net/url"
"os"
"strings"
)
// Conf holds the parsed per-package release configuration.
type Conf struct {
// Source is the fetch source type: "github", "gitea", "gitlab",
// Source is the fetch source type: "github", "githubsource",
// "gitea", "giteasource", "gitlab", "gitlabsource",
// "gittag", "nodedist", etc.
Source string
@@ -75,7 +88,7 @@ type Conf struct {
BaseURL string
// GitURL is the git clone URL for source-installable packages.
// Present alongside github_source/gitea_source to provide a
// Present alongside github_sources/gitea_sources to provide a
// git clone fallback in addition to release tarballs.
GitURL string
@@ -114,6 +127,25 @@ type Conf struct {
Extra map[string]string
}
// parseRepoRef parses a value that is either "owner/repo" or a full URL
// like "https://github.com/owner/repo". Returns baseURL, owner, repo.
// For short form, baseURL is empty (caller uses the default for the forge).
// For full URL form, baseURL is the scheme+host (e.g. "https://github.com").
func parseRepoRef(val, defaultBase string) (baseURL, owner, repo string) {
if strings.Contains(val, "://") {
u, err := url.Parse(val)
if err == nil {
baseURL = u.Scheme + "://" + u.Host
path := strings.Trim(u.Path, "/")
owner, repo, _ = strings.Cut(path, "/")
return baseURL, owner, repo
}
}
// Short form: "owner/repo"
owner, repo, _ = strings.Cut(val, "/")
return defaultBase, owner, repo
}
// Read parses a releases.conf file.
func Read(path string) (*Conf, error) {
f, err := os.Open(path)
@@ -143,29 +175,65 @@ func Read(path string) (*Conf, error) {
// Infer source from primary key, falling back to explicit "source".
switch {
case raw["github_repo"] != "":
// GitHub binary releases.
case raw["github_releases"] != "":
c.Source = "github"
c.Owner, c.Repo, _ = strings.Cut(raw["github_repo"], "/")
case raw["github_source"] != "":
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["github_releases"], "https://github.com")
case raw["github_repo"] != "":
// Back-compat alias.
c.Source = "github"
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["github_repo"], "https://github.com")
// GitHub source tarballs.
case raw["github_sources"] != "":
c.Source = "githubsource"
c.Owner, c.Repo, _ = strings.Cut(raw["github_source"], "/")
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["github_sources"], "https://github.com")
case raw["github_source"] != "":
// Back-compat alias.
c.Source = "githubsource"
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["github_source"], "https://github.com")
// Gitea binary releases (self-hosted only — requires full URL or base_url).
case raw["gitea_releases"] != "":
c.Source = "gitea"
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["gitea_releases"], raw["base_url"])
case raw["gitea_repo"] != "":
// Back-compat alias.
c.Source = "gitea"
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["gitea_repo"], raw["base_url"])
// Gitea source tarballs (self-hosted only).
case raw["gitea_sources"] != "":
c.Source = "giteasource"
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["gitea_sources"], raw["base_url"])
// GitLab binary releases (defaults to gitlab.com).
case raw["gitlab_releases"] != "":
c.Source = "gitlab"
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["gitlab_releases"], "https://gitlab.com")
// GitLab source tarballs (defaults to gitlab.com).
case raw["gitlab_sources"] != "":
c.Source = "gitlabsource"
c.BaseURL, c.Owner, c.Repo = parseRepoRef(raw["gitlab_sources"], "https://gitlab.com")
// Git tag enumeration.
case raw["git_url"] != "":
c.Source = "gittag"
c.BaseURL = raw["git_url"]
case raw["gitea_repo"] != "":
c.Source = "gitea"
c.Owner, c.Repo, _ = strings.Cut(raw["gitea_repo"], "/")
c.BaseURL = raw["base_url"]
// HashiCorp.
case raw["hashicorp_product"] != "":
c.Source = "hashicorp"
c.Repo = raw["hashicorp_product"]
default:
// One-off dist sources (nodedist, zigdist, etc.).
c.Source = raw["source"]
c.BaseURL = raw["url"]
}
// git_url can appear alongside any source type (e.g. github_source)
// git_url can appear alongside any source type (e.g. github_sources)
// to provide a git clone fallback. When it's the only key, it's the
// primary source (gittag).
c.GitURL = raw["git_url"]
@@ -195,10 +263,16 @@ func Read(path string) (*Conf, error) {
// Collect unrecognized keys.
known := map[string]bool{
"source": true,
"github_releases": true,
"github_repo": true,
"github_sources": true,
"github_source": true,
"git_url": true,
"gitea_releases": true,
"gitea_repo": true,
"gitea_sources": true,
"gitlab_releases": true,
"gitlab_sources": true,
"git_url": true,
"hashicorp_product": true,
"base_url": true,
"url": true,

View File

@@ -8,26 +8,67 @@ import (
"github.com/webinstall/webi-installers/internal/installerconf"
)
func TestSimpleGitHub(t *testing.T) {
func TestGitHubReleases(t *testing.T) {
c := confFromString(t, `
github_releases = sharkdp/bat
`)
assertEqual(t, "Source", c.Source, "github")
assertEqual(t, "Owner", c.Owner, "sharkdp")
assertEqual(t, "Repo", c.Repo, "bat")
assertEqual(t, "BaseURL", c.BaseURL, "https://github.com")
assertEqual(t, "TagPrefix", c.TagPrefix, "")
if len(c.VersionPrefixes) != 0 {
t.Errorf("VersionPrefixes = %v, want empty", c.VersionPrefixes)
}
if len(c.Exclude) != 0 {
t.Errorf("Exclude = %v, want empty", c.Exclude)
}
}
func TestGitHubReleasesFullURL(t *testing.T) {
c := confFromString(t, `
github_releases = https://github.com/sharkdp/bat
`)
assertEqual(t, "Source", c.Source, "github")
assertEqual(t, "BaseURL", c.BaseURL, "https://github.com")
assertEqual(t, "Owner", c.Owner, "sharkdp")
assertEqual(t, "Repo", c.Repo, "bat")
}
func TestGitHubRepoBackCompat(t *testing.T) {
c := confFromString(t, `
github_repo = sharkdp/bat
`)
assertEqual(t, "Source", c.Source, "github")
assertEqual(t, "Owner", c.Owner, "sharkdp")
assertEqual(t, "Repo", c.Repo, "bat")
assertEqual(t, "TagPrefix", c.TagPrefix, "")
if len(c.VersionPrefixes) != 0 {
t.Errorf("VersionPrefixes = %v, want empty", c.VersionPrefixes)
}
}
if len(c.Exclude) != 0 {
t.Errorf("Exclude = %v, want empty", c.Exclude)
}
func TestGitHubSources(t *testing.T) {
c := confFromString(t, `
github_sources = BeyondCodeBootcamp/aliasman
git_url = https://github.com/BeyondCodeBootcamp/aliasman.git
`)
assertEqual(t, "Source", c.Source, "githubsource")
assertEqual(t, "Owner", c.Owner, "BeyondCodeBootcamp")
assertEqual(t, "Repo", c.Repo, "aliasman")
assertEqual(t, "GitURL", c.GitURL, "https://github.com/BeyondCodeBootcamp/aliasman.git")
}
func TestGitHubSourcesFullURL(t *testing.T) {
c := confFromString(t, `
github_sources = https://github.com/BeyondCodeBootcamp/aliasman
git_url = https://github.com/BeyondCodeBootcamp/aliasman.git
`)
assertEqual(t, "Source", c.Source, "githubsource")
assertEqual(t, "BaseURL", c.BaseURL, "https://github.com")
assertEqual(t, "Owner", c.Owner, "BeyondCodeBootcamp")
assertEqual(t, "Repo", c.Repo, "aliasman")
}
func TestVersionPrefixes(t *testing.T) {
c := confFromString(t, `
github_repo = jqlang/jq
github_releases = jqlang/jq
version_prefixes = jq- cli-
`)
if len(c.VersionPrefixes) != 2 {
@@ -39,7 +80,7 @@ version_prefixes = jq- cli-
func TestExclude(t *testing.T) {
c := confFromString(t, `
github_repo = gohugoio/hugo
github_releases = gohugoio/hugo
exclude = _extended_ Linux-64bit
`)
if len(c.Exclude) != 2 {
@@ -51,7 +92,7 @@ exclude = _extended_ Linux-64bit
func TestMonorepoTagPrefix(t *testing.T) {
c := confFromString(t, `
github_repo = therootcompany/golib
github_releases = therootcompany/golib
tag_prefix = tools/monorel/
`)
assertEqual(t, "TagPrefix", c.TagPrefix, "tools/monorel/")
@@ -66,7 +107,28 @@ url = https://nodejs.org/download/release
assertEqual(t, "BaseURL", c.BaseURL, "https://nodejs.org/download/release")
}
func TestGiteaBaseURL(t *testing.T) {
func TestGiteaReleases(t *testing.T) {
c := confFromString(t, `
gitea_releases = https://git.rootprojects.org/root/pathman
`)
assertEqual(t, "Source", c.Source, "gitea")
assertEqual(t, "BaseURL", c.BaseURL, "https://git.rootprojects.org")
assertEqual(t, "Owner", c.Owner, "root")
assertEqual(t, "Repo", c.Repo, "pathman")
}
func TestGiteaReleasesWithBaseURL(t *testing.T) {
c := confFromString(t, `
gitea_releases = root/pathman
base_url = https://git.rootprojects.org
`)
assertEqual(t, "Source", c.Source, "gitea")
assertEqual(t, "BaseURL", c.BaseURL, "https://git.rootprojects.org")
assertEqual(t, "Owner", c.Owner, "root")
assertEqual(t, "Repo", c.Repo, "pathman")
}
func TestGiteaRepoBackCompat(t *testing.T) {
c := confFromString(t, `
gitea_repo = xorm/xorm
base_url = https://gitea.com
@@ -76,10 +138,30 @@ base_url = https://gitea.com
assertEqual(t, "Owner", c.Owner, "xorm")
}
func TestGitLabReleases(t *testing.T) {
c := confFromString(t, `
gitlab_releases = owner/repo
`)
assertEqual(t, "Source", c.Source, "gitlab")
assertEqual(t, "BaseURL", c.BaseURL, "https://gitlab.com")
assertEqual(t, "Owner", c.Owner, "owner")
assertEqual(t, "Repo", c.Repo, "repo")
}
func TestGitLabReleasesFullURL(t *testing.T) {
c := confFromString(t, `
gitlab_releases = https://gitlab.example.com/myorg/myrepo
`)
assertEqual(t, "Source", c.Source, "gitlab")
assertEqual(t, "BaseURL", c.BaseURL, "https://gitlab.example.com")
assertEqual(t, "Owner", c.Owner, "myorg")
assertEqual(t, "Repo", c.Repo, "myrepo")
}
func TestBlanksAndComments(t *testing.T) {
c := confFromString(t, `
# Hugo config
github_repo = foo/bar
github_releases = foo/bar
# exclude line
exclude = extended
@@ -91,7 +173,7 @@ exclude = extended
func TestExtraKeys(t *testing.T) {
c := confFromString(t, `
github_repo = foo/bar
github_releases = foo/bar
custom_thing = hello
`)
if c.Extra == nil || c.Extra["custom_thing"] != "hello" {
@@ -101,7 +183,7 @@ custom_thing = hello
func TestAssetExcludeAlias(t *testing.T) {
c := confFromString(t, `
github_repo = gohugoio/hugo
github_releases = gohugoio/hugo
asset_exclude = extended
`)
if len(c.Exclude) != 1 {
@@ -112,7 +194,7 @@ asset_exclude = extended
func TestVariants(t *testing.T) {
c := confFromString(t, `
github_repo = jmorganca/ollama
github_releases = jmorganca/ollama
variants = rocm jetpack5 jetpack6
`)
if len(c.Variants) != 3 {
@@ -124,7 +206,7 @@ variants = rocm jetpack5 jetpack6
}
func TestEmptyExclude(t *testing.T) {
c := confFromString(t, "github_repo = foo/bar\n")
c := confFromString(t, "github_releases = foo/bar\n")
if c.Exclude != nil {
t.Errorf("Exclude = %v, want nil", c.Exclude)
}

View File

@@ -1,2 +1,2 @@
github_repo = stedolan/jq
github_releases = stedolan/jq
version_prefixes = jq-

View File

@@ -1 +1 @@
github_repo = derailed/k9s
github_releases = derailed/k9s

View File

@@ -1 +1 @@
github_repo = therootcompany/keypairs
github_releases = therootcompany/keypairs

View File

@@ -1 +1 @@
github_repo = kubernetes-sigs/kind
github_releases = kubernetes-sigs/kind

View File

@@ -1 +1 @@
github_repo = cococonscious/koji
github_releases = cococonscious/koji

View File

@@ -1,2 +1,2 @@
github_repo = ahmetb/kubectx
github_releases = ahmetb/kubectx
asset_filter = kubectx

View File

@@ -1,2 +1,2 @@
github_repo = ahmetb/kubectx
github_releases = ahmetb/kubectx
asset_filter = kubens

View File

@@ -1 +1 @@
github_repo = gokcehan/lf
github_releases = gokcehan/lf

View File

@@ -1 +1 @@
github_repo = lsd-rs/lsd
github_releases = lsd-rs/lsd

View File

@@ -1,2 +1,2 @@
github_repo = therootcompany/golib
github_releases = therootcompany/golib
tag_prefix = tools/monorel/

View File

@@ -1 +1 @@
github_repo = mutagen-io/mutagen
github_releases = mutagen-io/mutagen

View File

@@ -1,2 +1,2 @@
github_repo = jmorganca/ollama
github_releases = jmorganca/ollama
variants = rocm jetpack5 jetpack6

View File

@@ -1 +1 @@
github_repo = emdneto/otsgo
github_releases = emdneto/otsgo

View File

@@ -1 +1 @@
github_repo = jgm/pandoc
github_releases = jgm/pandoc

View File

@@ -1,3 +1,2 @@
gitea_repo = root/pathman
base_url = https://git.rootprojects.org
gitea_releases = https://git.rootprojects.org/root/pathman
exclude = armv8

View File

@@ -1 +1 @@
github_repo = bnnanet/postgresql-releases
github_releases = bnnanet/postgresql-releases

View File

@@ -1,2 +1,2 @@
github_repo = bnnanet/postgresql-releases
github_releases = bnnanet/postgresql-releases
asset_filter = postgres

View File

@@ -1,2 +1,2 @@
github_repo = bnnanet/postgresql-releases
github_releases = bnnanet/postgresql-releases
asset_filter = psql

View File

@@ -1,2 +1,2 @@
github_repo = powershell/powershell
github_releases = powershell/powershell
variants = fxdependent fxdependentWinDesktop

View File

@@ -1 +1 @@
github_repo = rclone/rclone
github_releases = rclone/rclone

View File

@@ -1 +1 @@
github_repo = BurntSushi/ripgrep
github_releases = BurntSushi/ripgrep

View File

@@ -1 +1 @@
github_repo = therootcompany/runzip
github_releases = therootcompany/runzip

View File

@@ -1 +1 @@
github_repo = sass/dart-sass
github_releases = sass/dart-sass

View File

@@ -1 +1 @@
github_repo = therootcompany/sclient
github_releases = therootcompany/sclient

View File

@@ -1 +1 @@
github_repo = chmln/sd
github_releases = chmln/sd

View File

@@ -1,2 +1,2 @@
github_source = bnnanet/serviceman
github_sources = bnnanet/serviceman
git_url = https://github.com/bnnanet/serviceman.git

View File

@@ -1 +1 @@
github_repo = koalaman/shellcheck
github_releases = koalaman/shellcheck

View File

@@ -1 +1 @@
github_repo = mvdan/sh
github_releases = mvdan/sh

View File

@@ -1 +1 @@
github_repo = sqlc-dev/sqlc
github_releases = sqlc-dev/sqlc

View File

@@ -1 +1 @@
github_repo = nalgeon/sqlpkg-cli
github_releases = nalgeon/sqlpkg-cli

View File

@@ -1 +1 @@
github_repo = abhimanyu003/sttr
github_releases = abhimanyu003/sttr

View File

@@ -1 +1 @@
github_repo = syncthing/syncthing
github_releases = syncthing/syncthing

View File

@@ -1 +1 @@
github_repo = terramate-io/terramate
github_releases = terramate-io/terramate

View File

@@ -1 +1 @@
github_repo = tinygo-org/tinygo
github_releases = tinygo-org/tinygo

View File

@@ -1 +1 @@
github_repo = fujiapple852/trippy
github_releases = fujiapple852/trippy

View File

@@ -1,2 +1,2 @@
github_repo = coolaj86/uuidv7
github_releases = coolaj86/uuidv7
exclude = -thumb -armeb -loong -gnux32 -risc

View File

@@ -1 +1 @@
github_repo = watchexec/watchexec
github_releases = watchexec/watchexec

View File

@@ -1 +1 @@
github_repo = caddyserver/xcaddy
github_releases = caddyserver/xcaddy

View File

@@ -1 +1 @@
github_repo = BurntSushi/xsv
github_releases = BurntSushi/xsv

View File

@@ -1 +1 @@
github_repo = therootcompany/xz-static
github_releases = therootcompany/xz-static

View File

@@ -1,2 +1,2 @@
github_repo = mikefarah/yq
github_releases = mikefarah/yq
exclude = man_page_only

View File

@@ -1 +1 @@
github_repo = ajeetdsouza/zoxide
github_releases = ajeetdsouza/zoxide