>_EXECUTIVE SUMMARY
zsh-travis opens the Travis CI build page for the current project directly from the prompt. cd into a repo that has a .travis.yml at its top level, type tb, and the latest build log opens in the browser — no tab-switching, no URL-pasting. The plugin gates on .travis.yml, reads git config --get remote.origin.url for the upstream slug, strips the scheme + .com + .git, probes https://travis-ci.com/<slug> and falls back to https://travis-ci.org/<slug> on a 404, then hands the URL to a platform-detected browser opener. Source: 103 zsh lines across 1 plugin entry + 8 autoload functions. Pinned by 12 @test blocks across 3 zunit files.
~ARCHITECTURE
Single entry point that defines getOpenCommand, caches ZPWR_OPEN_CMD, declares the four t* aliases, then autoloads every function under autoload/ via autoload -Uz "${0:h}/autoload/"*(.:t). Each function is its own one-file unit — lazy-loaded on first use. The three branch/build/PR verbs are thin wrappers that call trav-git with a path suffix; trav-git chains the four private helpers.
| File / Group | Lines | Role |
|---|---|---|
travis.plugin.zsh |
42 | Plugin entry (symlinked as zsh-travis.plugin.zsh). Defines getOpenCommand (guarded by (( $+functions[getOpenCommand] ))); caches its result in ZPWR_OPEN_CMD only when unset; declares the four aliases tg/tb/tbr/tpr; sets the Zsh Plugin Standard 0= header; appends ${0:h}/autoload to fpath; autoloads all 8 functions. |
autoload/trav-git |
10 | Main verb behind tg. Runs __trav_check_yml; on success calls __trav_get_url "$@" then __trav_open $finalurl; on failure prints No .travis.yml file found. to stderr. |
autoload/trav-git-build · trav-git-br · trav-git-pr |
4 / 4 / 5 | Path-suffix wrappers. trav-git-build calls trav-git "/builds", trav-git-br → "/branches", trav-git-pr → "/pull_requests". Behind tb / tbr / tpr. |
autoload/__trav_check_yml |
6 | Gate. Tests $(git rev-parse --show-toplevel)/.travis.yml exists; returns 1 when absent. |
autoload/__trav_common_url |
14 | Slug builder. Reads remote.origin.url, strips https:// / http:// / ssh:// / git:// + .com + .git, appends the path-suffix arg. |
autoload/__trav_get_url |
12 | Host probe. Builds https://travis-ci.com/$url; if curl -s --head --request GET sees 404 Not Found, falls back to https://travis-ci.org/$url; sets finalurl. |
autoload/__trav_open |
6 | Launcher. Runs ${=ZPWR_OPEN_CMD} "$1" 2>/dev/null — word-split so nohup xdg-open / cmd.exe /c start '' expand to argv correctly. |
| Total source | 103 | 1 entry (42) + 8 autoloads (61) · pure zsh · no completion files |
$VERB CONTRACT
Four user-facing verbs, each fronted by a two-letter alias. The three suffixed verbs delegate to trav-git with a literal path argument; trav-git chains the four private helpers. The behavior table is the exact dispatch each verb performs.
| Verb (alias) | Path suffix | Behavior |
|---|---|---|
trav-git (tg) | (none) | Main Travis page. __trav_check_yml → __trav_get_url → __trav_open $finalurl. Prints No .travis.yml file found. to stderr if the gate fails. |
trav-git-build (tb) | /builds | trav-git "/builds" — latest build log. |
trav-git-br (tbr) | /branches | trav-git "/branches" — current-branch build history. |
trav-git-pr (tpr) | /pull_requests | trav-git "/pull_requests" — open PR builds. |
=HELPERS & URL REWRITE
The slug is built by string-substitution on remote.origin.url — no parsing library, the substitution chain is the contract. Each row is the exact transform applied in __trav_common_url and the probe logic in __trav_get_url.
| Helper | Input | Transform / output |
|---|---|---|
__trav_check_yml | cwd | Sets trav_file="$(git rev-parse --show-toplevel)/.travis.yml"; test -f $trav_file || return 1. |
__trav_common_url | remote.origin.url | Strip https://, http://, ssh://, git://; strip .com; strip .git; append $1 (path suffix). Result in $url. |
__trav_get_url | $url | tempurl="https://travis-ci.com/$url"; if curl -s --head --request GET $tempurl | grep "404 Not Found" matches, finalurl="https://travis-ci.org/$url", else finalurl="$tempurl". |
__trav_open | $finalurl | ${=ZPWR_OPEN_CMD} "$1" 2>/dev/null. |
getOpenCommand | $ZPWR_OS_TYPE | Maps darwin→open, cygwin→cygstart, linux→nohup xdg-open (or cmd.exe /c start '' on WSL), msys→start ''; unknown prints unsupported + returns 1. |
#TEST COVERAGE
12 @test blocks across 3 zunit files. t-aliases.zsh carries the bulk (7) — it sources the plugin and asserts each alias resolves to its canonical trav-git* function, that all four verbs + getOpenCommand are defined, and that re-sourcing is idempotent. t-contract.zsh pins the install-path shape; t-syntax.zsh runs zsh -n over the entry + autoload tree. The CI suite runs them under zunit on Ubuntu — no live Travis API required.
| File | Tests | Pins |
|---|---|---|
t-aliases.zsh | 7 | tg→trav-git, tb→trav-git-build, tbr→trav-git-br, tpr→trav-git-pr alias bodies; all four trav-git* fns defined; getOpenCommand defined; idempotent re-source keeps the same t* alias count. |
t-contract.zsh | 3 | Entrypoint stem (travis) matches the dir basename under the zsh- prefix rule; entrypoint parses under zsh -n; every _* completion file starts with #compdef (passes trivially — there are none). |
t-syntax.zsh | 2 | zsh -n over every *.zsh in the plugin root and every file under autoload/. |
| Total | 12 | 3 zunit files · alias-surface + install-contract + syntax |
/INTEGRATION
.com / .org host fallback
__trav_get_url probes travis-ci.com first with a curl --head request and only falls back to travis-ci.org when the probe returns 404 Not Found. The split came from the historical .org/.com Travis migration — the plugin works against whichever host actually serves the repo.
Cross-platform opener
getOpenCommand resolves the browser-launch command from $ZPWR_OS_TYPE: open on macOS, nohup xdg-open on Linux, cygstart on Cygwin, start on MSYS, and cmd.exe /c start under WSL (kernel release contains microsoft). Cached in ZPWR_OPEN_CMD at source time.
Fail-safe gating
Every verb runs __trav_check_yml first. Outside a Travis-tracked repo it prints a single stderr line and does nothing — so the t* aliases are safe to keep bound globally without misfiring in non-Travis directories.
git as the source of truth
The repo slug comes straight from git config --get remote.origin.url and the top level from git rev-parse --show-toplevel. No config file, no hardcoded org — the URL tracks wherever origin points.
Lazy autoload + Zsh Plugin Standard
Each verb and helper is one file under autoload/, registered via autoload -Uz — nothing is parsed until first call. The plugin honors the Zsh Plugin Standard 0= header so ${0:h} resolves under zinit / oh-my-zsh / antibody / antigen / bare source.
!DESIGN DECISIONS
Verb-per-path-suffix, not flags
Rather than one trav-git --builds with option parsing, the plugin ships four named verbs. trav-git-build / -br / -pr are three-line wrappers that call trav-git "/builds" etc. The page you want is the verb you type — and each gets its own two-letter alias.
Probe the host, don't guess it
The Travis .org/.com split means a static base URL would break for half of repos. The curl --head probe in __trav_get_url resolves the live host at call time instead of hardcoding one.
Fail-safe over fail-loud
No .travis.yml = one stderr line, no error spew, no nonzero-cascade. The verbs stay bindable everywhere without polluting non-Travis directories.
Word-split open command
__trav_open uses ${=ZPWR_OPEN_CMD} (the = forces word-splitting) so multi-word openers like nohup xdg-open and cmd.exe /c start '' reach the OS as separate argv entries rather than one impossible command name.
Guarded function definition
getOpenCommand is defined behind (( $+functions[getOpenCommand] )) || so re-sourcing the plugin (or co-existing with zpwr's own copy) does not redefine it — the idempotency the alias test pins.
Verb-as-file, not verb-as-block
8 separate files under autoload/ instead of one mega-file. Each lazy-loads on first call, so cold-startup cost is just the 42-line entry parse. Editing one verb does not invalidate a compiled .zwc for the others.
@FOOTPRINT
- Disk: 8 files under
autoload/+ the plugin entry (symlinked aszsh-travis.plugin.zsh→travis.plugin.zsh). No compiled artifacts, no completion files. - Startup cost: 42-line entry parse + one
getOpenCommandcall to populateZPWR_OPEN_CMD+autoload -Uzregistration (no body parse). - Runtime cost: per verb — one
git rev-parse, onegit config, onecurl --headprobe, one browser-open subprocess. - External tools:
git(required, for the top level + remote URL),curl(required, for the host probe), and a platform browser opener (open/xdg-open/cygstart/start) selected bygetOpenCommand. - Gate: a
.travis.ymlat the repo top level. Absent it, every verb printsNo .travis.yml file found.to stderr and returns.