Skip to content

ci: allow additional known root-level module files in stow-test check #28

ci: allow additional known root-level module files in stow-test check

ci: allow additional known root-level module files in stow-test check #28

Workflow file for this run

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