v3.4.1 de8f68e

install_next_test.sh RawHistoryFolder

1#!/bin/sh
2set -eu
3
4ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
5PASS=0
6FAIL=0
7SHA=0123456789abcdef0123456789abcdef01234567
8
9fail() {
10    echo "not ok - $1"
11    FAIL=$((FAIL + 1))
12}
13
14pass() {
15    echo "ok - $1"
16    PASS=$((PASS + 1))
17}
18
19run_case() {
20    shift
21    case_dir=$(mktemp -d)
22    mkdir -p "$case_dir/bin" "$case_dir/home" "$case_dir/install"
23
24    cat >"$case_dir/bin/uname" <<'EOF'
25#!/bin/sh
26[ "$1" = "-s" ] && echo Linux || echo x86_64
27EOF
28    cat >"$case_dir/bin/id" <<'EOF'
29#!/bin/sh
30[ "$1" = "-u" ] && { echo 1000; exit 0; }
31exec /usr/bin/id "$@"
32EOF
33    cat >"$case_dir/bin/curl" <<EOF
34#!/bin/sh
35printf '%s\n' "\$*" >>'$case_dir/curl.log'
36case "\$*" in
37  *api.github.com/repos/bnema/gordon/commits/next*) printf '%s\n' '{"sha":"$SHA"}' ;;
38  *codeload.github.com/bnema/gordon/tar.gz/$SHA*) : >'$case_dir/source.tar.gz' ;;
39  *github.com/bnema/gordon/releases/latest*) printf '%s' "\${MOCK_LATEST_URL-https://github.com/bnema/gordon/releases/tag/v9.9.9}" ;;
40  *) exit 90 ;;
41esac
42EOF
43    cat >"$case_dir/bin/tar" <<EOF
44#!/bin/sh
45printf '%s\n' "\$*" >>'$case_dir/tar.log'
46case "\$1" in
47  -tzf) printf '%s\n' 'gordon-$SHA/' 'gordon-$SHA/go.mod' 'gordon-$SHA/main.go' ;;
48  -tvzf) printf '%s\n' 'drwxr-xr-x root/root 0 date gordon-$SHA/' '-rw-r--r-- root/root 0 date gordon-$SHA/go.mod' '-rw-r--r-- root/root 0 date gordon-$SHA/main.go' ;;
49  -xzf)
50    while [ "\$#" -gt 0 ]; do
51      if [ "\$1" = -C ]; then
52        shift
53        mkdir -p "\$1/gordon-$SHA"
54        printf 'module example\n\ngo 1.27\n' >"\$1/gordon-$SHA/go.mod"
55        : >"\$1/gordon-$SHA/main.go"
56        exit 0
57      fi
58      shift
59    done
60    ;;
61esac
62EOF
63    cat >"$case_dir/bin/go" <<EOF
64#!/bin/sh
65printf '%s\n' "GOOS=\${GOOS-} GOARCH=\${GOARCH-} GOTOOLCHAIN=\${GOTOOLCHAIN-} \$*" >>'$case_dir/go.log'
66if [ "\$1 \$2" = 'env GOVERSION' ]; then echo go1.27.1; exit 0; fi
67if [ "\$1" = build ]; then
68  while [ "\$#" -gt 0 ]; do [ "\$1" = -o ] && { shift; : >"\$1"; chmod 755 "\$1"; exit 0; }; shift; done
69fi
70exit 91
71EOF
72    cat >"$case_dir/bin/install" <<EOF
73#!/bin/sh
74printf '%s\n' "\$*" >>'$case_dir/install.log'
75cp "\$3" "\$4"
76EOF
77    cat >"$case_dir/bin/mv" <<EOF
78#!/bin/sh
79printf '%s\n' "\$*" >>'$case_dir/mv.log'
80[ "\$1" = -f ] && shift
81/bin/mv "\$1" "\$2"
82EOF
83    chmod +x "$case_dir/bin/"*
84    mkdir -p "$case_dir/tmp"
85
86    if (PATH="$case_dir/bin:/usr/bin:/bin" HOME="$case_dir/home" SHELL=/bin/bash TMPDIR="$case_dir/tmp" GORDON_UPDATE_PATH=0 "$@") >"$case_dir/out" 2>&1; then
87        status=0
88    else
89        status=$?
90    fi
91}
92
93test_next_build() {
94    run_case next-build env GORDON_CHANNEL=next sh "$ROOT/install.sh"
95    [ "$status" -eq 0 ] || { cat "$case_dir/out"; fail "next channel builds pinned source"; return; }
96    if grep -q "commits/next" "$case_dir/curl.log" &&
97        grep -q "codeload.github.com/bnema/gordon/tar.gz/$SHA" "$case_dir/curl.log" &&
98        grep -q -- "-X main.version=next-$SHA" "$case_dir/go.log" &&
99        grep -q "GOOS=linux GOARCH=amd64 GOTOOLCHAIN=local" "$case_dir/go.log" &&
100        grep -q "UNVERIFIED DEVELOPMENT BUILD" "$case_dir/out" &&
101        [ -x "$case_dir/home/.local/bin/gordon" ]; then
102        pass "next channel builds pinned source"
103    else
104        fail "next channel builds pinned source"
105    fi
106}
107
108test_conflicts() {
109    run_case version-conflict env GORDON_CHANNEL=next GORDON_VERSION=v1.2.3 sh "$ROOT/install.sh"
110    if [ "$status" -ne 0 ] && grep -q "GORDON_VERSION cannot be used" "$case_dir/out"; then
111        pass "next rejects GORDON_VERSION"
112    else
113        fail "next rejects GORDON_VERSION"
114    fi
115
116    run_case prerelease-conflict env GORDON_CHANNEL=next GORDON_PRERELEASE=1 sh "$ROOT/install.sh"
117    if [ "$status" -ne 0 ] && grep -q "GORDON_PRERELEASE cannot be used" "$case_dir/out"; then
118        pass "next rejects GORDON_PRERELEASE"
119    else
120        fail "next rejects GORDON_PRERELEASE"
121    fi
122}
123
124test_go_version() {
125    run_case old-go env GORDON_CHANNEL=next MOCK_GO_VERSION=unused sh "$ROOT/install.sh"
126    # Replace the mock after setup, then run once more in the same fixture.
127    cat >"$case_dir/bin/go" <<'EOF'
128#!/bin/sh
129[ "$1 $2" = 'env GOVERSION' ] && { echo go1.26.9; exit 0; }
130exit 91
131EOF
132    chmod +x "$case_dir/bin/go"
133    if (PATH="$case_dir/bin:/usr/bin:/bin" HOME="$case_dir/home" SHELL=/bin/bash TMPDIR="$case_dir/tmp" GORDON_UPDATE_PATH=0 GORDON_CHANNEL=next sh "$ROOT/install.sh") >"$case_dir/out" 2>&1; then status=0; else status=$?; fi
134    if [ "$status" -ne 0 ] && grep -q "requires Go 1.27 or newer" "$case_dir/out"; then
135        pass "next enforces go.mod Go version"
136    else
137        fail "next enforces go.mod Go version"
138    fi
139}
140
141test_default_and_path_modes() {
142    run_case default-dir env GORDON_CHANNEL=next sh "$ROOT/install.sh"
143    if [ "$status" -eq 0 ] && [ -x "$case_dir/home/.local/bin/gordon" ] &&
144        grep -q "export PATH='${case_dir}/home/.local/bin':\$PATH" "$case_dir/out"; then
145        pass "default install is user-local and prints current-shell instruction"
146    else
147        fail "default install is user-local and prints current-shell instruction"
148    fi
149
150    run_case path-present env GORDON_CHANNEL=next sh "$ROOT/install.sh"
151    if (PATH="$case_dir/bin:$case_dir/home/.local/bin:/usr/bin:/bin" HOME="$case_dir/home" SHELL=/bin/bash TMPDIR="$case_dir/tmp" GORDON_UPDATE_PATH=0 GORDON_CHANNEL=next sh "$ROOT/install.sh") >"$case_dir/out" 2>&1; then status=0; else status=$?; fi
152    if [ "$status" -eq 0 ] && ! grep -q "Add Gordon to the current shell" "$case_dir/out"; then
153        pass "existing PATH needs no update"
154    else
155        fail "existing PATH needs no update"
156    fi
157
158    run_case forced-no env GORDON_CHANNEL=next GORDON_UPDATE_PATH=0 sh "$ROOT/install.sh"
159    if [ "$status" -eq 0 ] && [ ! -e "$case_dir/home/.bashrc" ]; then
160        pass "forced no does not modify shell config"
161    else
162        fail "forced no does not modify shell config"
163    fi
164
165    run_case invalid-update env GORDON_CHANNEL=next GORDON_UPDATE_PATH=maybe sh "$ROOT/install.sh"
166    if [ "$status" -ne 0 ] && grep -q "must be 0 or 1" "$case_dir/out"; then
167        pass "invalid PATH mode is rejected"
168    else
169        fail "invalid PATH mode is rejected"
170    fi
171
172    run_case unsafe-dir env GORDON_CHANNEL=next GORDON_INSTALL_DIR="/tmp/unsafe
173path" sh "$ROOT/install.sh"
174    if [ "$status" -ne 0 ] && grep -q "unsafe control character" "$case_dir/out"; then
175        pass "control characters in install directory are rejected"
176    else
177        fail "control characters in install directory are rejected"
178    fi
179
180    run_case trailing-newline env GORDON_CHANNEL=next GORDON_INSTALL_DIR="/tmp/unsafe
181" sh "$ROOT/install.sh"
182    if [ "$status" -ne 0 ] && grep -q "unsafe control character" "$case_dir/out"; then
183        pass "trailing newline in install directory is rejected"
184    else
185        fail "trailing newline in install directory is rejected"
186    fi
187}
188
189test_shell_updates() {
190    for shell in bash zsh fish; do
191        run_case "shell-$shell" env GORDON_CHANNEL=next GORDON_UPDATE_PATH=1 SHELL="/usr/bin/$shell" sh "$ROOT/install.sh"
192        case "$shell" in
193            bash) config=$case_dir/home/.bashrc; expected="export PATH='${case_dir}/home/.local/bin':\$PATH" ;;
194            zsh) config=$case_dir/home/.zshrc; expected="export PATH='${case_dir}/home/.local/bin':\$PATH" ;;
195            fish) config=$case_dir/home/.config/fish/config.fish; expected="fish_add_path '${case_dir}/home/.local/bin'" ;;
196        esac
197        if [ "$status" -eq 0 ] && grep -Fq "$expected" "$config"; then
198            pass "$shell PATH update"
199        else
200            fail "$shell PATH update"
201        fi
202    done
203
204    run_case idempotent env GORDON_CHANNEL=next GORDON_UPDATE_PATH=1 SHELL=/bin/bash sh "$ROOT/install.sh"
205    first_case=$case_dir
206    if (PATH="$case_dir/bin:/usr/bin:/bin" HOME="$case_dir/home" SHELL=/bin/bash TMPDIR="$case_dir/tmp" GORDON_UPDATE_PATH=1 GORDON_CHANNEL=next sh "$ROOT/install.sh") >>"$case_dir/out" 2>&1 &&
207        [ "$(grep -c '^# >>> Gordon installer PATH >>>$' "$case_dir/home/.bashrc")" -eq 1 ]; then
208        pass "PATH marker block is idempotent"
209    else
210        cat "$first_case/out"
211        fail "PATH marker block is idempotent"
212    fi
213
214    run_case unsupported env GORDON_CHANNEL=next GORDON_UPDATE_PATH=1 SHELL=/bin/ksh sh "$ROOT/install.sh"
215    if [ "$status" -eq 0 ] && grep -q "unsupported or missing SHELL" "$case_dir/out"; then
216        pass "unsupported shell gets manual instructions"
217    else
218        fail "unsupported shell gets manual instructions"
219    fi
220}
221
222test_explicit_global_override() {
223    run_case home-bin env GORDON_CHANNEL=next sh "$ROOT/install.sh"
224    if (PATH="$case_dir/bin:/usr/bin:/bin" HOME="$case_dir/home" SHELL=/bin/bash TMPDIR="$case_dir/tmp" GORDON_UPDATE_PATH=1 GORDON_INSTALL_DIR="$case_dir/home/bin" GORDON_CHANNEL=next sh "$ROOT/install.sh") >"$case_dir/out" 2>&1; then status=0; else status=$?; fi
225    if [ "$status" -eq 0 ] && [ -x "$case_dir/home/bin/gordon" ] &&
226        grep -Fq "export PATH='${case_dir}/home/bin':\$PATH" "$case_dir/home/.bashrc"; then
227        pass "HOME bin override is installed and added to PATH"
228    else
229        fail "HOME bin override is installed and added to PATH"
230    fi
231
232    run_case global env GORDON_CHANNEL=next sh "$ROOT/install.sh"
233    if (PATH="$case_dir/bin:/usr/bin:/bin" HOME="$case_dir/home" SHELL=/bin/bash TMPDIR="$case_dir/tmp" GORDON_UPDATE_PATH=0 GORDON_INSTALL_DIR="$case_dir/install" GORDON_CHANNEL=next sh "$ROOT/install.sh") >"$case_dir/out" 2>&1; then status=0; else status=$?; fi
234    if [ "$status" -eq 0 ] && [ -x "$case_dir/install/gordon" ]; then
235        pass "explicit global install override is preserved"
236    else
237        fail "explicit global install override is preserved"
238    fi
239
240    run_case sudo-default env SUDO_USER=test-user GORDON_CHANNEL=next sh "$ROOT/install.sh"
241    if [ "$status" -ne 0 ] && grep -q "Refusing a default user-local install" "$case_dir/out" && [ ! -e "$case_dir/home/.local/bin/gordon" ]; then
242        pass "sudo default install is refused"
243    else
244        fail "sudo default install is refused"
245    fi
246}
247
248test_stable_latest_without_api() {
249    run_case stable-latest env sh "$ROOT/install.sh"
250    # The mock refuses the checksum download; resolution is what is tested.
251    if grep -q "Resolved version: v9.9.9" "$case_dir/out" &&
252        grep -q "github.com/bnema/gordon/releases/download/v9.9.9/checksums.txt" "$case_dir/curl.log" &&
253        ! grep -q "api.github.com" "$case_dir/curl.log"; then
254        pass "stable latest resolves from the release redirect without the API"
255    else
256        cat "$case_dir/out"
257        fail "stable latest resolves from the release redirect without the API"
258    fi
259
260    run_case stable-latest-bad env MOCK_LATEST_URL='https://github.com/bnema/gordon/releases' sh "$ROOT/install.sh"
261    if [ "$status" -ne 0 ] && grep -q "Could not determine latest stable version" "$case_dir/out" &&
262        ! grep -q "releases/download" "$case_dir/curl.log"; then
263        pass "unexpected latest redirect is rejected"
264    else
265        cat "$case_dir/out"
266        fail "unexpected latest redirect is rejected"
267    fi
268
269    run_case stable-latest-unsafe env MOCK_LATEST_URL='https://github.com/bnema/gordon/releases/tag/v1.0.0;rm' sh "$ROOT/install.sh"
270    if [ "$status" -ne 0 ] && grep -q "Could not determine latest stable version" "$case_dir/out"; then
271        pass "unsafe latest tag is rejected"
272    else
273        cat "$case_dir/out"
274        fail "unsafe latest tag is rejected"
275    fi
276}
277
278test_stable_latest_without_api
279test_next_build
280test_conflicts
281test_go_version
282test_default_and_path_modes
283test_shell_updates
284test_explicit_global_override
285printf '%s passed, %s failed\n' "$PASS" "$FAIL"
286[ "$FAIL" -eq 0 ]

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close