feat(git): add --server/--check-existing to mkrep for gitea/gitlab/github

mkrep can now pick a git host from --server, $GIT_SERVER, and
$GITEA_URL/$GITEA_HOST/$GITLAB_URL/$GITLAB_HOST (base URL only -- type
must come from --server/$GIT_SERVER, so setting those URL vars for an
unrelated tool can't silently turn a plain mkrep call into a
remote-creating one). Before creating anything it checks via
gh/glab/tea whether the repo already exists and links instead of
recreating it; --check-existing runs just that check and reports
without touching remotes.
This commit is contained in:
2026-09-14 21:06:28 -04:00
parent 9821e64ae4
commit 1a07e94002
5 changed files with 430 additions and 19 deletions
+32
View File
@@ -0,0 +1,32 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# _mkrep_default_remote_cmd <type>
#
# DESCRIPTION
# Prints the default remote-create command template for <type>, used by
# mkrep's --server flow when $MKREP_REMOTE_CMD is unset. Same {name},
# {user}, {server} placeholders as --new-remote.
#
# ARGUMENTS
# type gitea, gitlab, or github
#
# RETURNS
# The template string, on stdout
#
# EXIT STATUS
# 0 known type
# 1 unrecognized type
function _mkrep_default_remote_cmd --argument-names type
switch $type
case github
echo 'gh repo create {name} --private --source=. --remote=origin --push'
case gitlab
echo 'glab repo create {name} --private --skipGitInit && git remote add origin {server}/{user}/{name}.git && git push -u origin HEAD'
case gitea
echo 'tea repos create --name {name} --private && git remote add origin {server}/{user}/{name}.git && git push -u origin HEAD'
case '*'
return 1
end
end
+36
View File
@@ -0,0 +1,36 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# _mkrep_remote_url <type> <user> <name> <url>
#
# DESCRIPTION
# Builds the clone URL for a repo on <type>, for mkrep's --server flow:
# linking to a repo that already exists, and reporting the URL of one it
# just created. <url> is the resolved server base (from --server/$GIT_SERVER
# plus $GITEA_URL/$GITEA_HOST/$GITLAB_URL/$GITLAB_HOST) and is unused for
# github, which always resolves to github.com.
#
# ARGUMENTS
# type gitea, gitlab, or github
# user Account/namespace the repo lives under
# name Repo name
# url Server base URL (required for gitea/gitlab)
#
# RETURNS
# The clone URL, on stdout
#
# EXIT STATUS
# 0 URL built
# 1 unrecognized type, or gitea/gitlab given with no url
function _mkrep_remote_url --argument-names type user name url
switch $type
case github
echo "https://github.com/$user/$name.git"
case gitlab gitea
test -n "$url"; or return 1
echo "$url/$user/$name.git"
case '*'
return 1
end
end
+39
View File
@@ -0,0 +1,39 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# DEPENDENCIES
# gh, glab, tea
#
# SYNOPSIS
# _mkrep_repo_exists <type> <user> <name>
#
# DESCRIPTION
# Checks whether <user>/<name> already exists on the given server, for
# mkrep's --server and --check-existing flows. Each host CLI is already
# authenticated (gh/glab/tea login), so this shells out to its own
# repo-lookup command rather than querying an API directly.
#
# ARGUMENTS
# type gitea, gitlab, or github
# user Account/namespace to check under
# name Repo name
#
# EXIT STATUS
# 0 repository exists
# 1 repository does not exist, the check tool is missing, or type is
# invalid
function _mkrep_repo_exists --argument-names type user name
switch $type
case github
type -q gh; or return 1
gh repo view "$user/$name" >/dev/null 2>&1
case gitlab
type -q glab; or return 1
glab repo view "$user/$name" >/dev/null 2>&1
case gitea
type -q tea; or return 1
tea repos "$user/$name" >/dev/null 2>&1
case '*'
return 1
end
end
+156 -19
View File
@@ -5,14 +5,15 @@
# 04-git-and-version-control
#
# DEPENDENCIES
# _fish_mkdir_p, __fish_palette, _mkrep_say, _mkrep_verbose, git
# _fish_mkdir_p, __fish_palette, _mkrep_say, _mkrep_verbose,
# _mkrep_default_remote_cmd, _mkrep_remote_url, _mkrep_repo_exists, git
#
# SYNOPSIS
# mkrep [--cd | --no-cd] [--mkdir | --no-mkdir] [--git | --no-git]
# [-c | --clean | --no-clean] [--strict] [-v | --verbose]
# [-s | --silent] [--template <path>] [--branch <name>]
# [--remote <url>] [--new-remote [<cmd>]] [--name <name>]
# [-h | --help] <dir>
# [--remote <url>] [--new-remote [<cmd>]] [--server <type>]
# [--check-existing] [--name <name>] [-h | --help] <dir>
#
# DESCRIPTION
# Creates a directory, cds into it, and git-inits it -- mkcd plus a git
@@ -31,11 +32,33 @@
# by running a shell command template in the new repo directory, then
# nothing further is needed since the template itself does the linking
# (e.g. gh repo create {name} --source=. --remote=origin --push).
# Two placeholders are substituted in the template: {name} (--name, or
# the target directory's basename) and {user} ($USER). Pass a command
# after --new-remote to use it for this call only; with no value it
# falls back to $MKREP_REMOTE_CMD. --remote and --new-remote are
# mutually exclusive, and either requires --git.
# Three placeholders are substituted in a template: {name} (--name, or
# the target directory's basename), {user} ($USER), and {server} (the
# resolved server base URL, gitea/gitlab only). Pass a command after
# --new-remote to use it for this call only; with no value it falls
# back to $MKREP_REMOTE_CMD. --remote and --new-remote are mutually
# exclusive, and either requires --git.
#
# --server <type> (gitea, gitlab, or github) picks a host without an
# explicit --remote/--new-remote: resolve its base URL from
# $GITEA_URL/$GITEA_HOST (gitea) or $GITLAB_URL/$GITLAB_HOST (gitlab),
# preferring the _URL form when both are set, then run
# $MKREP_REMOTE_CMD or that type's built-in default template. With no
# --server, --remote, or --new-remote, $GIT_SERVER picks the type the
# same way (invalid values are rejected the same as an invalid
# --server) -- $GITEA_URL/$GITEA_HOST/$GITLAB_URL/$GITLAB_HOST only ever
# supply the base URL, never the type on their own, so setting one for
# an unrelated tool (an API token helper, say) can't turn a plain mkrep
# call into a remote-creating one. This auto-detect path is silent (no
# error) under --no-git; --server itself still requires --git, and
# --server together with --remote or --new-remote is an error. Either
# way, before creating anything mkrep checks whether
# <user>/<name> already exists on that host: if so, it links to the
# existing repo instead of creating one; if not, it creates the repo
# and reports the new remote's URL. --check-existing runs just that
# check and reports the result without creating or linking anything; it
# requires a resolved server and is mutually exclusive with --remote
# and --new-remote.
#
# ARGUMENTS
# <dir> Directory to create and enter
@@ -55,8 +78,11 @@
# --new-remote [<cmd>]
# Create + link a remote by running <cmd> (or
# $MKREP_REMOTE_CMD) in the new repo directory
# --name <name> {name} substitution when --new-remote (default: <dir>'s
# basename)
# --server <type> Auto-create/link a remote on gitea, gitlab, or github
# --check-existing Report whether the repo exists on the resolved
# server; creates or links nothing
# --name <name> {name} substitution for --new-remote/--server
# (default: <dir>'s basename)
# -h, --help Show this help message
#
# EXIT STATUS
@@ -69,21 +95,27 @@
# mkrep --remote git@git.example.com:me/foo.git ~/projects/foo
# set -Ux MKREP_REMOTE_CMD 'gh repo create {name} --private --source=. --remote=origin --push'
# mkrep --new-remote ~/projects/foo
# set -gx GITEA_URL https://git.example.com
# set -gx GIT_SERVER gitea
# mkrep ~/projects/foo
# mkrep --server gitlab --check-existing ~/projects/foo
#
# Starting points for $MKREP_REMOTE_CMD, one per host CLI -- each assumes
# that tool is already installed and authenticated, creates a private
# repo under the caller's own account, and pushes the initial commit.
# gh and glab support a one-shot --source/--remote/--push; tea's create
# does not, so it is chained with the git commands that do the linking
# (adjust the host in the URL to your Gitea instance):
# These are also mkrep's built-in defaults for --server/$GIT_SERVER when
# $MKREP_REMOTE_CMD is unset. gh supports a one-shot
# --source/--remote/--push; glab and tea's create commands do not, so
# they are chained with the git commands that do the linking:
# GitHub (gh): gh repo create {name} --private --source=. --remote=origin --push
# GitLab (glab): glab repo create {name} --private --source=. --remote=origin --push
# Gitea (tea): tea repo create --name {name} --private && git remote add origin https://YOUR-GITEA-HOST/{user}/{name}.git && git push -u origin HEAD
# GitLab (glab): glab repo create {name} --private --skipGitInit && git remote add origin {server}/{user}/{name}.git && git push -u origin HEAD
# Gitea (tea): tea repos create --name {name} --private && git remote add origin {server}/{user}/{name}.git && git push -u origin HEAD
function mkrep --description 'Create a directory, cd into it, and git init it'
__fish_palette
argparse h/help cd no-cd mkdir no-mkdir git no-git c/clean no-clean strict \
v/verbose s/silent template= branch= remote= new-remote=? name= \
v/verbose s/silent template= branch= remote= new-remote=? server= \
check-existing name= \
-- $argv
or return 1
@@ -105,7 +137,9 @@ function mkrep --description 'Create a directory, cd into it, and git init it'
echo " $c_flag--branch$c_reset $c_arg<name>$c_reset git init -b <name>"
echo " $c_flag--remote$c_reset $c_arg<url>$c_reset Link an existing remote"
echo " $c_flag--new-remote$c_reset $c_arg<cmd>$c_reset (optional) Create + link a remote"
echo " $c_flag--name$c_reset $c_arg<name>$c_reset {name} substitution for --new-remote"
echo " $c_flag--server$c_reset $c_arg<type>$c_reset Auto-create/link a remote (gitea, gitlab, github)"
echo " $c_flag--check-existing$c_reset Report whether the repo exists; creates nothing"
echo " $c_flag--name$c_reset $c_arg<name>$c_reset {name} substitution for --new-remote/--server"
echo " $c_flag-h$c_reset, $c_flag--help$c_reset Show this help message"
echo
echo "$c_head""Examples:$c_reset"
@@ -125,13 +159,63 @@ function mkrep --description 'Create a directory, cd into it, and git init it'
echo "$c_err""✘$c_reset --remote and --new-remote are mutually exclusive" >&2
return 1
end
if set -q _flag_server; and set -q _flag_remote
echo "$c_err""✘$c_reset --server and --remote are mutually exclusive" >&2
return 1
end
if set -q _flag_server; and set -q _flag_new_remote
echo "$c_err""✘$c_reset --server and --new-remote are mutually exclusive" >&2
return 1
end
if set -q _flag_check_existing; and set -q _flag_remote
echo "$c_err""✘$c_reset --check-existing and --remote are mutually exclusive" >&2
return 1
end
if set -q _flag_check_existing; and set -q _flag_new_remote
echo "$c_err""✘$c_reset --check-existing and --new-remote are mutually exclusive" >&2
return 1
end
if set -q _flag_no_git
if set -q _flag_remote; or set -q _flag_new_remote
echo "$c_err""✘$c_reset --remote/--new-remote require --git" >&2
if set -q _flag_remote; or set -q _flag_new_remote; or set -q _flag_server
echo "$c_err""✘$c_reset --remote/--new-remote/--server require --git" >&2
return 1
end
end
set -l srv_type ''
set -l srv_url ''
if set -q _flag_server
set srv_type $_flag_server
else if test -n "$GIT_SERVER"
set srv_type $GIT_SERVER
end
if test -n "$srv_type"
switch $srv_type
case gitea
if test -n "$GITEA_URL"
set srv_url $GITEA_URL
else if test -n "$GITEA_HOST"
set srv_url $GITEA_HOST
end
case gitlab
if test -n "$GITLAB_URL"
set srv_url $GITLAB_URL
else if test -n "$GITLAB_HOST"
set srv_url $GITLAB_HOST
end
case github
# gh defaults to github.com; no base url needed
case '*'
echo "$c_err""✘$c_reset Unrecognized server type $c_arg$srv_type$c_reset (expected gitea, gitlab, or github)" >&2
return 1
end
end
if set -q _flag_check_existing; and test -z "$srv_type"
echo "$c_err""✘$c_reset --check-existing needs a resolved server (--server, \$GIT_SERVER, or \$GITEA_URL/\$GITEA_HOST/\$GITLAB_URL/\$GITLAB_HOST)" >&2
return 1
end
set -l do_cd 1
set -q _flag_no_cd; and set do_cd 0
set -l do_mkdir 1
@@ -258,6 +342,59 @@ function mkrep --description 'Create a directory, cd into it, and git init it'
_mkrep_say $silent "$c_ok""✔$c_reset Ran remote-create command"
end
if not set -q _flag_remote; and not set -q _flag_new_remote
set -l name $_flag_name
test -z "$name"; and set name (path basename (path resolve $dir))
if set -q _flag_check_existing
if _mkrep_repo_exists $srv_type $USER $name
_mkrep_say $silent "$c_warn""→$c_reset $c_arg$USER/$name$c_reset already exists on $srv_type"
else
_mkrep_say $silent "$c_ok""✔$c_reset $c_arg$USER/$name$c_reset does not exist on $srv_type"
end
else if test -n "$srv_type"; and test $do_git -eq 1
if _mkrep_repo_exists $srv_type $USER $name
set -l url (_mkrep_remote_url $srv_type $USER $name $srv_url)
_mkrep_say $silent "$c_warn""→$c_reset $c_arg$USER/$name$c_reset already exists on $srv_type; linking instead of creating"
git remote add origin $url
or begin
echo "$c_err""✘$c_reset Failed to add remote $c_arg$url$c_reset" >&2
cd $orig_pwd
return 1
end
_mkrep_say $silent "$c_ok""✔$c_reset Linked remote $c_arg$url$c_reset"
else
set -l cmd $MKREP_REMOTE_CMD
test -z "$cmd"; and set cmd (_mkrep_default_remote_cmd $srv_type)
if string match -q '*{server}*' -- $cmd
if test -z "$srv_url"
echo "$c_err""✘$c_reset No base URL resolved for $srv_type (set \$GITEA_URL/\$GITEA_HOST or \$GITLAB_URL/\$GITLAB_HOST)" >&2
cd $orig_pwd
return 1
end
set cmd (string replace -a '{server}' $srv_url -- $cmd)
end
set cmd (string replace -a '{name}' $name -- $cmd)
set cmd (string replace -a '{user}' $USER -- $cmd)
_mkrep_verbose $silent $verbose "$c_dim""Running: $cmd$c_reset"
if test $silent -eq 1
eval $cmd >/dev/null 2>&1
else
eval $cmd
end
or begin
echo "$c_err""✘$c_reset Remote-create command failed" >&2
cd $orig_pwd
return 1
end
set -l url (_mkrep_remote_url $srv_type $USER $name $srv_url)
_mkrep_say $silent "$c_ok""✔$c_reset Created new remote $c_arg$url$c_reset on $srv_type"
end
end
end
if test $do_cd -eq 0
cd $orig_pwd
else