aboutsummaryrefslogtreecommitdiffstats
path: root/examples/tools/test-clone.sh
blob: 02879a245d1ace588c4489b84656dcbc2b04dc33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/bin/bash
# desktop-assistant tool check: clone.sh against a scratch tree and a stub git.
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# test-clone.sh: CLONE_ROOT and CLONE_MAP point at a throwaway dir, and git is
# a stub that records its argv and creates the clone target, so nothing hits
# the network or the real tree. Prints "ok" or one FAIL line per broken case.

set -u
here=$(dirname "$0")
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
export CLONE_ROOT=$tmp/git
export CLONE_MAP=$tmp/clone-hosts
export GIT_LOG=$tmp/git.log
: > "$GIT_LOG"
mkdir -p "$tmp/bin"

cat > "$tmp/bin/git" <<'EOF'
#!/bin/bash
printf '%s\n' "$*" >> "$GIT_LOG"
printf 'prompt=%s askpass=%s\n' "${GIT_TERMINAL_PROMPT-}" "${SSH_ASKPASS-unset}" >> "$GIT_LOG"
[ "$1" = clone ] && mkdir -p "${@: -1}"
exit 0
EOF
chmod +x "$tmp/bin/git"
PATH=$tmp/bin:$PATH
export PATH

fail=0
check() { [ "$2" = "$3" ] || { echo "FAIL $1: got '$2', want '$3'"; fail=1; }; }
contains() { case "$2" in *"$3"*) ;; *) echo "FAIL $1: '$2' lacks '$3'"; fail=1 ;; esac; }
count() { grep -cF -- "$1" "$GIT_LOG" || true; }
mapcount() { grep -cF -- "$1" "$CLONE_MAP" || true; }

# Known host, clean copy: seeded map, straight clone, no question. Owner and
# repo both go in the target folder name.
out=$("$here/clone.sh" https://github.com/a/b.git)
check "github clone" "$out" "cloned https://github.com/a/b.git into $CLONE_ROOT/GITHUB/a-b"
check "seed" "$(cat "$CLONE_MAP")" \
    "$(printf '%s\t%s\n' github.com GITHUB gitlab.com GITLAB forge.slackware.nl FORGE)"
check "no prompts" "$(count 'prompt=0 askpass=unset')" "1"
check "clone argv" "$(count "clone -- https://github.com/a/b.git $CLONE_ROOT/GITHUB/a-b")" "1"

# Host case does not matter.
out=$("$here/clone.sh" https://GitHub.com/a/up)
check "host case" "$out" "cloned https://GitHub.com/a/up into $CLONE_ROOT/GITHUB/a-up"

# Trailing slash and .git are not part of the repo name.
out=$("$here/clone.sh" https://gitlab.com/a/c.git/)
check "gitlab repo" "$out" "cloned https://gitlab.com/a/c.git into $CLONE_ROOT/GITLAB/a-c"

# A self-named repo is not doubled (firefly-iii/firefly-iii -> firefly-iii).
out=$("$here/clone.sh" https://github.com/firefly-iii/firefly-iii.git)
check "self-named" "$out" \
    "cloned https://github.com/firefly-iii/firefly-iii.git into $CLONE_ROOT/GITHUB/firefly-iii"

# No owner in the URL: the plain repo name.
out=$("$here/clone.sh" git@github.com:solo.git)
check "no owner" "$out" "cloned git@github.com:solo.git into $CLONE_ROOT/GITHUB/solo"

# A nested group keeps only its last segment as the owner.
out=$("$here/clone.sh" https://gitlab.com/group/sub/thing.git)
check "subgroup" "$out" \
    "cloned https://gitlab.com/group/sub/thing.git into $CLONE_ROOT/GITLAB/sub-thing"

# Unknown host: ask, do nothing, name the folder to offer.
out=$("$here/clone.sh" https://codeberg.org/a/d)
contains "unknown asks" "$out" "no folder for host codeberg.org"
contains "unknown label" "$out" "to=CODEBERG"
check "unknown no clone" "$(count "$CLONE_ROOT/CODEBERG/a-d")" "0"

# Approved folder: clone there and remember it.
out=$("$here/clone.sh" https://codeberg.org/a/d CODEBERG)
check "approved clone" "$out" "cloned https://codeberg.org/a/d into $CLONE_ROOT/CODEBERG/a-d"
check "remembered" "$(mapcount 'codeberg.org')" "1"
check "remembered pair" "$(grep -F 'codeberg.org' "$CLONE_MAP")" \
    "$(printf 'codeberg.org\tCODEBERG')"

# Next clone of that host asks nothing.
out=$("$here/clone.sh" https://codeberg.org/a/e)
check "remembered clone" "$out" "cloned https://codeberg.org/a/e into $CLONE_ROOT/CODEBERG/a-e"

# Re-approving the same folder does not duplicate the map line.
"$here/clone.sh" https://codeberg.org/a/f CODEBERG >/dev/null
check "no duplicate map line" "$(mapcount 'codeberg.org')" "1"

# Already cloned: ask, do not clone again; update pulls.
out=$("$here/clone.sh" https://github.com/a/b.git)
contains "already asks" "$out" "already cloned at $CLONE_ROOT/GITHUB/a-b"
check "already no reclone" "$(count "clone -- https://github.com/a/b.git")" "1"
out=$("$here/clone.sh" https://github.com/a/b.git "" 0)
contains "update=0 asks" "$out" "already cloned"
out=$("$here/clone.sh" https://github.com/a/b.git "" 1)
contains "update says" "$out" "updated $CLONE_ROOT/GITHUB/a-b"
check "update argv" "$(count "-C $CLONE_ROOT/GITHUB/a-b pull --ff-only")" "1"

# Bad input is refused before anything is created.
"$here/clone.sh" "" >/dev/null 2>&1; check "empty url" "$?" "1"
"$here/clone.sh" not-a-url >/dev/null 2>&1; check "not a url" "$?" "1"
"$here/clone.sh" https://github.com/a/.. >/dev/null 2>&1; check "bad repo" "$?" "1"
"$here/clone.sh" https://codeberg.org/a/z ../escape >/dev/null 2>&1; check "bad to" "$?" "1"

[ $fail = 0 ] && echo "ok"
exit $fail