Skip to content

feat: startup-quality product page + scripts v3.3.8 #43

feat: startup-quality product page + scripts v3.3.8

feat: startup-quality product page + scripts v3.3.8 #43

Workflow file for this run

name: πŸ§ͺ CI β€” Lint & Health
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
ci:
name: Node ${{ matrix.node }} on ubuntu-latest
runs-on: ubuntu-latest
strategy:
matrix:
node: ['20', '22']
fail-fast: false
steps:
- name: ⬇️ Checkout
uses: actions/checkout@v4
- name: 🟒 Setup Node.js ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
# ── Shell syntax checks ──────────────────────────────────────────────────
- name: 🐚 Shell syntax check (bash -n)
run: |
set -euo pipefail
FAIL=0
for f in \
setup.sh \
setup-termux-widget.sh \
install-termux.sh \
update.sh \
start.sh \
doctor.sh \
bin/isotope; do
if [ -f "$f" ]; then
if bash -n "$f" 2>/dev/null; then
echo "βœ… $f"
else
echo "❌ $f β€” syntax error"
bash -n "$f" || true
FAIL=1
fi
else
echo "⚠️ $f β€” not found (skipping)"
fi
done
[ "$FAIL" -eq 0 ] || exit 1
- name: πŸ” ShellCheck
run: |
set -euo pipefail
if ! command -v shellcheck >/dev/null 2>&1; then
echo "Installing shellcheck..."
sudo apt-get install -y shellcheck >/dev/null 2>&1
fi
echo "shellcheck $(shellcheck --version | head -2 | tail -1)"
FAIL=0
for f in \
setup.sh \
setup-termux-widget.sh \
install-termux.sh \
update.sh \
start.sh \
doctor.sh \
bin/isotope; do
if [ -f "$f" ]; then
# SC1090: can't follow sourced file β€” expected in this codebase
# SC1091: not following include β€” expected
# SC2148: no shebang for sourced files β€” not applicable
if shellcheck -x -e SC1090,SC1091 "$f"; then
echo "βœ… $f"
else
echo "⚠️ $f β€” shellcheck warnings (non-fatal for now)"
fi
else
echo "⚠️ $f β€” not found (skipping)"
fi
done
# ShellCheck is advisory in CI for now β€” uncomment to make it block:
# [ "$FAIL" -eq 0 ] || exit 1
# ── Node syntax ──────────────────────────────────────────────────────────
- name: βœ… Node.js syntax check β€” server.mjs
run: node --check server.mjs
# ── Required files ───────────────────────────────────────────────────────
- name: πŸ“ Required files present
run: |
set -euo pipefail
FAIL=0
REQUIRED=(
server.mjs
package.json
setup.sh
setup.bat
install.ps1
install-termux.sh
setup-termux-widget.sh
update.sh
update.bat
start.sh
start.bat
doctor.sh
doctor.bat
bin/isotope
bin/isotope.bat
isotope-complete.sql
.env.example
README.md
CHANGELOG.md
TERMUX_WIDGET.md
)
for f in "${REQUIRED[@]}"; do
if [ -f "$f" ]; then
echo "βœ… $f"
else
echo "❌ $f β€” MISSING"
FAIL=1
fi
done
[ "$FAIL" -eq 0 ] || exit 1
# ── No hardcoded secrets ─────────────────────────────────────────────────
- name: πŸ”’ No hardcoded secrets
run: |
set -euo pipefail
if grep -rE 'SUPABASE_SERVICE_ROLE_KEY\s*=\s*eyJ' \
--include="*.mjs" --include="*.js" --include="*.sh" .; then
echo "❌ Hardcoded service-role key detected!"
exit 1
fi
echo "βœ… No hardcoded secrets"
# ── Schema stats ─────────────────────────────────────────────────────────
- name: πŸ“‹ Schema file stats
run: |
set -euo pipefail
for f in isotope-complete.sql community-patch-v4.sql performance-patch.sql; do
if [ -f "$f" ]; then
echo "=== $f ==="
echo " Size : $(wc -c < "$f") bytes"
echo " Lines : $(wc -l < "$f")"
echo " Tables : $(grep -c 'CREATE TABLE' "$f" || echo 0)"
echo " Funcs : $(grep -c 'CREATE OR REPLACE FUNCTION' "$f" || echo 0)"
echo " Policies: $(grep -c 'CREATE POLICY' "$f" || echo 0)"
else
echo "⚠️ $f not found β€” skipping"
fi
done
# ── Termux simulation ─────────────────────────────────────────────────────
- name: πŸ“± Termux simulation β€” platform detection
run: |
set -euo pipefail
echo "Simulating Termux environment..."
export TERMUX_VERSION="ci-test"
export PREFIX="/data/data/com.termux/files/usr"
# Test that setup.sh correctly detects 'termux' platform when vars are set
DETECTED=$(
TERMUX_VERSION="$TERMUX_VERSION" PREFIX="$PREFIX" \
node -e "
const { execSync } = require('child_process');
const out = execSync(
'bash -c \\'source setup.sh --yes --no-start --termux-ci 2>&1 | head -5 || true\\'',
{ env: { ...process.env, TERMUX_VERSION: \"ci-test\", PREFIX: \"/data/data/com.termux/files/usr\" }, timeout: 10000 }
).toString().trim();
console.log(out);
" 2>/dev/null || echo "skipped"
)
echo "Termux simulation output (first 5 lines):"
echo "$DETECTED" | head -5
echo "βœ… Termux simulation completed (full install requires real Android device)"
# ── Smoke test ────────────────────────────────────────────────────────────
- name: πŸš€ Smoke test β€” server starts and responds
run: |
set -uo pipefail
SUPABASE_URL=https://placeholder.supabase.co \
SUPABASE_ANON_KEY=placeholder_anon_key \
SESSION_SECRET=ci_smoke_test_secret_not_real \
ADMIN_SECRET=ci_admin_placeholder \
NODE_ENV=test \
PORT=3099 \
node server.mjs &
SERVER_PID=$!
echo "Server PID: $SERVER_PID β€” polling /api/health..."
STATUS="000"
for i in $(seq 1 40); do
sleep 0.5
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
http://127.0.0.1:3099/api/health 2>/dev/null || echo "000")
if [ "$STATUS" != "000" ]; then
echo " HTTP $STATUS after ${i} attempts"
break
fi
printf ' Attempt %d: waiting...\n' "$i"
done
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
echo "Final health status: $STATUS"
case "$STATUS" in
2*|3*|4*|5*)
echo "βœ… Server started and responded (HTTP $STATUS)"
;;
*)
echo "❌ Server did not respond (got: $STATUS)"
exit 1
;;
esac
# ── Release zip simulation ────────────────────────────────────────────────
- name: πŸ“¦ Release zip β€” build + verify extract
run: |
set -euo pipefail
VERSION="$(node -e "process.stdout.write(require('./package.json').version)")"
echo "Building release zip for v$VERSION..."
zip -qr "isotope-v${VERSION}-ci-test.zip" . \
--exclude ".git/*" \
--exclude "node_modules/*" \
--exclude ".env" \
--exclude "*.log" \
--exclude ".github/*" \
--exclude "screenshots/*" \
--exclude "*.zip"
echo "Archive: $(wc -c < "isotope-v${VERSION}-ci-test.zip") bytes"
# Extract to a fresh dir and check required files are present
TMPDIR="$(mktemp -d)"
unzip -q "isotope-v${VERSION}-ci-test.zip" -d "$TMPDIR"
echo "Verifying extracted release..."
FAIL=0
for f in server.mjs package.json setup.sh install-termux.sh bin/isotope .env.example; do
if [ -f "$TMPDIR/$f" ]; then
echo " βœ… $f"
else
echo " ❌ $f β€” missing from zip"
FAIL=1
fi
done
rm -rf "$TMPDIR" "isotope-v${VERSION}-ci-test.zip"
[ "$FAIL" -eq 0 ] || exit 1
echo "βœ… Release zip contains all required files"
# ── Docs validation ──────────────────────────────────────────────────────
- name: πŸ“ Docs + README validation
run: |
set -euo pipefail
node scripts/validate-docs.mjs || {
echo "⚠️ Docs validation had errors β€” see output above"
exit 1
}
# ── Upload logs on failure ────────────────────────────────────────────────
- name: πŸ“€ Upload CI logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: ci-logs-node${{ matrix.node }}-${{ github.run_id }}
path: |
~/.isotope/logs/
/tmp/isotope-ci-*.log
if-no-files-found: ignore
retention-days: 7