Skip to content

Commit 6f6b5be

Browse files
authored
Merge pull request #2 from xsh-lib/feature/zsh-support
feat: generated libraries are zsh-ready (test scaffold + full shell CI)
2 parents d4f8634 + 0005bf7 commit 6f6b5be

5 files changed

Lines changed: 137 additions & 2 deletions

File tree

.github/workflows/setup.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ jobs:
6464
mv /tmp/$REPO_NAME/* .
6565
# And .gitignore too:
6666
mv /tmp/$REPO_NAME/.gitignore .
67+
# And the generated CI workflow (hidden .github dir isn't matched by
68+
# the glob above); the template's own .github/workflows/ already
69+
# exists here (setup.yml was just removed from it).
70+
mv /tmp/$REPO_NAME/.github/workflows/test.yml .github/workflows/
6771
6872
- name: Force push new repo contents
6973
uses: stefanzweifel/git-auto-commit-action@v4

cookiecutter.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
"lib_name": "",
33
"description": "",
44
"github_username": "",
5-
"author_name": ""
5+
"author_name": "",
6+
"_copy_without_render": [".github/workflows/test.yml"]
67
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches: [main, master]
6+
pull_request:
7+
branches: [main, master]
8+
9+
# This workflow is copied verbatim by cookiecutter (see _copy_without_render in
10+
# cookiecutter.json) so GitHub's ${{ ... }} expressions survive generation. It
11+
# is self-describing — it loads whatever repo it lives in via
12+
# ${{ github.repository }}, so no per-library edits are needed.
13+
14+
jobs:
15+
test:
16+
runs-on: ${{ matrix.os }}
17+
container: ${{ matrix.container }}
18+
name: ${{ matrix.label }}
19+
defaults:
20+
run:
21+
shell: bash
22+
# Mirror alexzhangs/xsh's shell matrix: bash 3.2 / 4.4 / 5.x + zsh 5.x.
23+
# Utilities run under zsh's ksh emulation (provided by xsh >= 0.7.0).
24+
strategy:
25+
fail-fast: false
26+
matrix:
27+
include:
28+
- { os: ubuntu-latest, container: '', shell_path: /bin/bash, label: bash-5.x-linux }
29+
- { os: macos-latest, container: '', shell_path: /bin/bash, label: bash-3.2-macos }
30+
- { os: macos-latest, container: '', shell_path: brew, label: bash-5.x-macos }
31+
- { os: ubuntu-latest, container: rockylinux:8, shell_path: /bin/bash, label: bash-4.4-linux }
32+
- { os: macos-latest, container: '', shell_path: /bin/zsh, label: zsh-5.x-macos }
33+
- { os: ubuntu-latest, container: '', shell_path: /usr/bin/zsh, label: zsh-5.x-linux }
34+
35+
steps:
36+
- name: Pre-install git (rockylinux container)
37+
if: matrix.container != ''
38+
run: dnf install -y git
39+
40+
- name: Install dependencies (rockylinux container)
41+
if: matrix.container != ''
42+
run: |
43+
dnf install -y --allowerasing coreutils
44+
dnf install -y gawk sed file findutils diffutils procps-ng which tar gzip python3
45+
command -v python >/dev/null 2>&1 || ln -sf "$(command -v python3)" /usr/local/bin/python
46+
git config --global --add safe.directory '*'
47+
48+
- name: Install zsh (Linux)
49+
if: matrix.container == '' && runner.os == 'Linux' && contains(matrix.shell_path, 'zsh')
50+
run: sudo apt-get update && sudo apt-get install -y zsh
51+
52+
- name: Install Homebrew bash (macOS bash 5.x)
53+
if: matrix.shell_path == 'brew'
54+
run: |
55+
brew install bash
56+
echo "SHELL_PATH=$(brew --prefix)/bin/bash" >> "$GITHUB_ENV"
57+
58+
- name: Set shell path
59+
if: matrix.shell_path != 'brew'
60+
run: echo "SHELL_PATH=${{ matrix.shell_path }}" >> "$GITHUB_ENV"
61+
62+
- name: Install xsh
63+
run: |
64+
git clone --depth=50 --branch=master https://github.com/alexzhangs/xsh.git /tmp/xsh
65+
bash /tmp/xsh/install.sh
66+
67+
- name: Load dependency library xsh-lib/core
68+
run: |
69+
source ~/.xshrc
70+
xsh load xsh-lib/core
71+
72+
- name: Load library from current branch
73+
run: |
74+
source ~/.xshrc
75+
xsh load -b "${{ github.head_ref || github.ref_name }}" "${{ github.repository }}"
76+
77+
- name: Run tests (${{ matrix.label }})
78+
# test.sh self-sources ~/.xshrc, so running it under $SHELL_PATH makes
79+
# the utilities execute under that shell (bash, or zsh's ksh emulation).
80+
run: |
81+
"$SHELL_PATH" ~/.xsh/repo/"${{ github.repository }}"/test.sh

{{cookiecutter.lib_name}}/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ About xsh and its libraries, check out [xsh document](https://github.com/alexzha
66

77
## Requirements
88

9-
1. bash
9+
1. bash or zsh
1010

1111
Tested with bash:
1212
* 4.3.48 on Linux
1313
* 3.2.57 on macOS
1414

15+
The utilities also run under **zsh** (the default shell on modern macOS);
16+
xsh executes them under zsh's ksh emulation. Requires xsh >= 0.7.0 for zsh.
17+
1518
## Dependency
1619

1720
1. xsh-lib/core

{{cookiecutter.lib_name}}/test.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/bin/bash
2+
#
3+
# Tests for this xsh library. Plain assertions, no external test framework
4+
# (mirrors xsh-lib/core/test.sh). Runs under bash and zsh.
5+
#
6+
# Usage:
7+
# xsh load xsh-lib/core <user>/<this-lib> # one-time
8+
# bash test.sh # or: zsh test.sh
9+
#
10+
11+
# Make the `xsh` function available when run as a child process. Under bash it
12+
# is inherited as an exported function (no-op here); zsh cannot export functions,
13+
# so a child `zsh test.sh` sources ~/.xshrc to define xsh as a real zsh function
14+
# (otherwise it would only see the bin/xsh shim, which runs bash). This is what
15+
# lets the utilities execute under zsh's ksh emulation.
16+
if ! type xsh 2>/dev/null | grep -q 'function'; then
17+
# shellcheck source=/dev/null
18+
. ~/.xshrc
19+
fi
20+
21+
set -e -o pipefail
22+
23+
# Derive the library's LPUE prefix from xsh.lib (its `name=` field).
24+
__dir=$(cd "$(dirname "$0")" && pwd)
25+
__lib=$(awk -F= '/^name=/{print $2; exit}' "$__dir/xsh.lib")
26+
[ -n "$__lib" ] || { echo "test.sh: could not read library name from xsh.lib" >&2; exit 1; }
27+
28+
xsh log info "xsh list ${__lib}/"
29+
xsh list "${__lib}/*" >/dev/null
30+
31+
# import-smoke: every function utility sources cleanly (under zsh each is
32+
# sourced with the injected `emulate -L ksh`). A brand-new library has no
33+
# utilities yet, so this loop is a no-op until you add some.
34+
xsh log info "import-smoke: all ${__lib} function utilities"
35+
while read -r __lpue; do
36+
[ -z "$__lpue" ] && continue
37+
xsh import "$__lpue"
38+
done < <(xsh list "${__lib}/*" | awk '$1 == "[functions]" {print $2}')
39+
40+
# TODO: add functional assertions for your utilities, e.g.
41+
# [[ $(xsh ${__lib}/some/util arg) == expected ]]
42+
43+
echo
44+
echo "All tests passed."
45+
46+
exit

0 commit comments

Comments
 (0)