ci: allow additional known root-level module files in stow-test check #28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| jobs: | |
| shell-lint: | |
| name: Bash lint & syntax check | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Do NOT automatically fail the checkout step if submodules use SSH and are not accessible | |
| # Instead we'll attempt to fetch submodules later and continue if they cannot be fetched. | |
| - uses: actions/checkout@v4 | |
| with: | |
| lfs: true | |
| # avoid automatic failure from actions/checkout when submodule fetch needs SSH | |
| submodules: false | |
| - name: Install shellcheck | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y shellcheck | |
| - name: Bash syntax check | |
| run: | | |
| for f in ./scripts/*.sh; do bash -n "$f"; done | |
| - name: Check executable bit on shebang files | |
| run: | | |
| set -e | |
| fail=0 | |
| files=$(git ls-files || true) | |
| if [ -n "$files" ]; then | |
| for f in $files; do | |
| if [ -f "$f" ]; then | |
| if head -n1 "$f" | grep -q '^#!'; then | |
| mode=$(git ls-files --stage "$f" | awk '{print $1}') | |
| if [ "$mode" != "100755" ]; then | |
| echo "$f has shebang but is not executable in index (mode: $mode). Run: git update-index --chmod=+x $f" | |
| fail=1 | |
| fi | |
| fi | |
| fi | |
| done | |
| fi | |
| if [ "$fail" -eq 1 ]; then exit 1; fi | |
| - name: Run shellcheck | |
| run: | | |
| for f in ./scripts/*.sh; do shellcheck "$f" || true; done | |
| powershell-lint: | |
| name: PowerShell lint | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| lfs: true | |
| submodules: false | |
| - name: Install PSScriptAnalyzer | |
| shell: pwsh | |
| run: | | |
| Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser | |
| - name: Analyze PowerShell scripts | |
| shell: pwsh | |
| run: | | |
| Invoke-ScriptAnalyzer -Path scripts\*.ps1 -Recurse | |
| lfs-and-submodule-check: | |
| name: LFS & submodules | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| lfs: true | |
| submodules: false | |
| - name: Detect submodules defined in .gitmodules (no network access) | |
| run: | | |
| # We intentionally DO NOT try to fetch or update submodules from CI. | |
| # Some submodules are private and accessible only via the maintainer's SSH key. | |
| # Instead we check that the .gitmodules file exists and contains submodule entries. | |
| if [ -f .gitmodules ]; then | |
| echo ".gitmodules found:"; cat .gitmodules | |
| # List submodule paths and urls | |
| git config -f .gitmodules --get-regexp '^submodule\..*\.path' || true | |
| git config -f .gitmodules --get-regexp '^submodule\..*\.url' || true | |
| COUNT=$(git config -f .gitmodules --get-regexp '^submodule\..*\.path' | wc -l || true) | |
| if [ "$COUNT" -gt 0 ]; then | |
| echo "SUBMODULES_PRESENT=true" >> $GITHUB_ENV | |
| else | |
| echo "SUBMODULES_PRESENT=false" >> $GITHUB_ENV | |
| fi | |
| else | |
| echo ".gitmodules not present" | |
| echo "SUBMODULES_PRESENT=false" >> $GITHUB_ENV | |
| fi | |
| - name: Validate submodules | |
| if: env.SUBMODULES_PRESENT == 'true' | |
| run: | | |
| git submodule status --recursive | |
| - name: Skip submodule validation (not available) | |
| if: env.SUBMODULES_PRESENT == 'false' | |
| run: | | |
| echo "Submodules not available in this runner (probably SSH-only URLs). Skipping validation." | |
| - name: Check LFS tracked assets | |
| run: | | |
| git lfs ls-files || true | |
| - name: Check .gitattributes includes assets/** | |
| run: | | |
| grep -E '^assets/\*\* filter=lfs' .gitattributes | |
| stow-test: | |
| name: Verify modules with stow | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| lfs: true | |
| submodules: false | |
| - name: Install stow and tools | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y stow | |
| - name: Stow-test (create temp target and apply all modules) | |
| run: | | |
| set -e | |
| TMP=$(mktemp -d) | |
| echo "Testing stow modules with target: $TMP" | |
| cd modules | |
| # Iterate modules and try to stow to temporary directory | |
| for m in */ ; do | |
| m=$(basename "$m") | |
| # Skip modules that include system-level files (e.g. etc/) to avoid attempting to apply them | |
| if find "$m" -mindepth 1 -maxdepth 2 -type f -path '*/etc/*' | read; then | |
| echo "Skipping module: $m (contains system-level files under etc/)" | |
| continue | |
| fi | |
| echo "Testing module: $m" | |
| # Use explicit target to avoid modifying home | |
| stow -v -t "$TMP" "$m" || { echo "stow failed for module: $m"; exit 1; } | |
| done | |
| # Check at least one symlink was created | |
| SYMLINKS_COUNT=$(find "$TMP" -type l | wc -l || true) | |
| echo "Symlinks created: $SYMLINKS_COUNT" | |
| if [ "$SYMLINKS_COUNT" -lt 1 ]; then | |
| echo "No symlinks created by stow; verify module structure" | |
| ls -R "$TMP" || true | |
| exit 1 | |
| fi | |
| - name: Check for top-level files in modules that could pollute $HOME | |
| run: | | |
| set -e | |
| cd modules | |
| FAIL=0 | |
| ALLOWED='^config.fish$|^init.vim$|^settings.json$|^config.json$|^chrome-flags.conf$|^README.md$' | |
| for m in */ ; do | |
| m=$(basename "$m") | |
| # find files in module root (not dotfiles) that are not in our allowed list | |
| while IFS= read -r -d $'\0' f; do | |
| fname=$(basename "$f") | |
| if [[ ! "$fname" =~ $ALLOWED ]] && [[ ! "$fname" =~ ^\..+ ]]; then | |
| echo "Module $m contains root-level file that may install to \$HOME: $fname" >&2 | |
| FAIL=1 | |
| fi | |
| done < <(find "$m" -maxdepth 1 -type f -print0 || true) | |
| done | |
| if [ "$FAIL" -eq 1 ]; then | |
| echo "Top-level files detected in modules. Either move them into a .config/ tree, make them dotfiles (start with .), or ensure installer mapping handles them." >&2 | |
| exit 1 | |
| fi | |
| - name: Cleanup | |
| run: | | |
| echo "Removing temp"; rm -rf "$TMP" || true |