secubox-openwrt/.github/workflows/test-validate.yml
2025-12-28 09:09:12 +01:00

410 lines
13 KiB
YAML

name: Test & Validate Packages
on:
push:
branches: [main, master, develop]
pull_request:
branches: [main, master]
jobs:
# ============================================
# Lint and validate package structure
# ============================================
lint:
runs-on: ubuntu-latest
name: Lint & Validate
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install validators
run: |
sudo apt-get update
sudo apt-get install -y shellcheck jq
- name: Validate Makefile structure
run: |
echo "📋 Validating Makefile structure..."
ERRORS=0
for makefile in luci-app-*/Makefile; do
if [[ -f "$makefile" ]]; then
PKG=$(dirname "$makefile")
echo " 🔍 Checking $PKG..."
# Required fields
REQUIRED_FIELDS=(
"PKG_NAME"
"PKG_VERSION"
"PKG_RELEASE"
"PKG_LICENSE"
)
for field in "${REQUIRED_FIELDS[@]}"; do
if ! grep -q "^${field}:=" "$makefile"; then
echo " ❌ Missing: $field"
ERRORS=$((ERRORS + 1))
fi
done
# Check for include statements
if ! grep -q "include.*luci.mk\|include.*package.mk" "$makefile"; then
echo " ❌ Missing include statement (luci.mk or package.mk)"
ERRORS=$((ERRORS + 1))
fi
fi
done
if [[ $ERRORS -gt 0 ]]; then
echo "❌ Found $ERRORS errors"
exit 1
fi
echo "✅ All Makefiles valid"
- name: Validate JSON files
run: |
echo "📋 Validating JSON files..."
ERRORS=0
while IFS= read -r jsonfile; do
echo " 🔍 Checking $jsonfile..."
if ! jq empty "$jsonfile" 2>/dev/null; then
echo " ❌ Invalid JSON"
ERRORS=$((ERRORS + 1))
fi
done < <(find . -name "*.json" -type f)
if [[ $ERRORS -gt 0 ]]; then
echo "❌ Found $ERRORS JSON errors"
exit 1
fi
echo "✅ All JSON files valid"
- name: Validate JavaScript syntax
run: |
echo "📋 Validating JavaScript files..."
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
ERRORS=0
while IFS= read -r jsfile; do
echo " 🔍 Checking $jsfile..."
if ! node --check "$jsfile" 2>/dev/null; then
echo " ❌ Syntax error"
ERRORS=$((ERRORS + 1))
fi
done < <(find . -name "*.js" -type f ! -path "*/node_modules/*")
if [[ $ERRORS -gt 0 ]]; then
echo "❌ Found $ERRORS JavaScript errors"
exit 1
fi
echo "✅ All JavaScript files valid"
- name: Validate shell scripts
run: |
echo "📋 Validating shell scripts..."
WARNINGS=0
# Check RPCD scripts
while IFS= read -r script; do
echo " 🔍 Checking $script..."
shellcheck -s sh "$script" || WARNINGS=$((WARNINGS + 1))
done < <(find . -path "*/rpcd/*" -type f 2>/dev/null)
# Check init scripts
while IFS= read -r script; do
echo " 🔍 Checking $script..."
shellcheck -s sh "$script" || WARNINGS=$((WARNINGS + 1))
done < <(find . -path "*/init.d/*" -type f 2>/dev/null)
if [[ $WARNINGS -gt 0 ]]; then
echo "⚠️ Found $WARNINGS shellcheck warnings (non-blocking)"
fi
echo "✅ Shell script validation complete"
- name: Check file permissions
run: |
echo "📋 Checking file permissions..."
ERRORS=0
# RPCD scripts should be executable
while IFS= read -r script; do
if [[ ! -x "$script" ]]; then
echo " ❌ Not executable: $script"
chmod +x "$script"
ERRORS=$((ERRORS + 1))
fi
done < <(find . -path "*/usr/libexec/rpcd/*" -type f 2>/dev/null)
# Init scripts should be executable
while IFS= read -r script; do
if [[ ! -x "$script" ]]; then
echo " ❌ Not executable: $script"
chmod +x "$script"
ERRORS=$((ERRORS + 1))
fi
done < <(find . -path "*/etc/init.d/*" -type f 2>/dev/null)
if [[ $ERRORS -gt 0 ]]; then
echo "⚠️ Fixed $ERRORS permission issues"
fi
echo "✅ File permissions checked"
- name: Validate package structure
run: |
echo "📋 Validating package structure..."
for pkg in luci-app-*/; do
if [[ -d "$pkg" ]]; then
echo " 📦 Checking $pkg..."
# Required
if [[ ! -f "${pkg}Makefile" ]]; then
echo " ❌ Missing required: Makefile"
exit 1
fi
# Recommended
RECOMMENDED=(
"htdocs/luci-static/resources"
"root/usr/share/luci/menu.d"
"root/usr/share/rpcd/acl.d"
)
for rec in "${RECOMMENDED[@]}"; do
if [[ ! -e "${pkg}${rec}" ]]; then
echo " ⚠️ Missing recommended: $rec"
fi
done
fi
done
echo "✅ Package structure valid"
# ============================================
# Quick build test on x86_64
# ============================================
test-build:
runs-on: ubuntu-latest
name: Test Build (x86_64)
needs: lint
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential clang flex bison g++ gawk \
gcc-multilib g++-multilib gettext git libncurses5-dev \
libssl-dev python3-setuptools python3-dev rsync unzip zlib1g-dev wget ninja-build
- name: Cache OpenWrt SDK
uses: actions/cache@v4
id: cache-sdk
with:
path: ~/sdk
key: openwrt-sdk-23.05.5-x86-64-test-v2
- name: Download OpenWrt SDK
if: steps.cache-sdk.outputs.cache-hit != 'true'
run: |
SDK_URL="https://downloads.openwrt.org/releases/23.05.5/targets/x86/64"
SDK_FILE=$(curl -sL "$SDK_URL/" | grep -oP 'openwrt-sdk[^"]+\.tar\.xz' | head -1)
wget -q "${SDK_URL}/${SDK_FILE}" -O /tmp/sdk.tar.xz
mkdir -p ~/sdk
tar -xf /tmp/sdk.tar.xz -C ~/sdk --strip-components=1
- name: Prepare SDK
run: |
cd ~/sdk
# Remove unwanted feeds from feeds.conf.default BEFORE updating feeds
if [[ -f "feeds.conf.default" ]]; then
sed -i '/telephony/d' feeds.conf.default
sed -i '/routing/d' feeds.conf.default
echo "✅ Removed telephony and routing from feeds.conf.default"
fi
echo "🔄 Updating feeds..."
if ! ./scripts/feeds update -a 2>&1 | tee feed-update.log; then
echo "⚠️ Feed update had errors:"
tail -30 feed-update.log
echo "Continuing anyway..."
fi
echo "📦 Installing feeds..."
if ! ./scripts/feeds install -a 2>&1 | tee feed-install.log; then
echo "⚠️ Feed install had warnings, checking directories..."
fi
# Verify feeds were created
echo "🔍 Verifying feeds..."
for feed in packages luci; do
if [[ -d "feeds/$feed" ]]; then
FEED_SIZE=$(du -sh "feeds/$feed" 2>/dev/null | cut -f1 || echo "?")
echo " ✅ feeds/$feed ($FEED_SIZE)"
else
echo " ❌ feeds/$feed missing!"
ls -la feeds/ || echo "feeds directory doesn't exist"
exit 1
fi
done
# Final cleanup of unwanted feeds
rm -f feeds/telephony.index feeds/routing.index 2>/dev/null || true
rm -rf feeds/telephony feeds/routing 2>/dev/null || true
make defconfig
- name: Copy packages
run: |
# IMPORTANT: Copy packages DIRECTLY into package/, not into a subdirectory
for pkg in luci-app-*/; do
if [[ -d "$pkg" && -f "${pkg}Makefile" ]]; then
PKG_NAME=$(basename "$pkg")
echo "📦 Copying $PKG_NAME..."
cp -r "$pkg" ~/sdk/package/
fi
done
echo ""
echo "📋 Packages in SDK:"
ls -d ~/sdk/package/luci-app-*/ 2>/dev/null || echo "No packages found"
- name: Configure packages
run: |
cd ~/sdk
# Enable packages
for pkg in ~/sdk/package/luci-app-*/; do
if [[ -d "$pkg" ]]; then
PKG_NAME=$(basename "$pkg")
echo "CONFIG_PACKAGE_${PKG_NAME}=m" >> .config
echo "✅ Enabled: $PKG_NAME"
fi
done
# Final cleanup before defconfig
rm -f feeds/telephony.index feeds/routing.index 2>/dev/null || true
rm -rf feeds/telephony feeds/routing 2>/dev/null || true
make defconfig
- name: Build packages
run: |
cd ~/sdk
echo "🔨 Building packages..."
BUILT=0
FAILED=0
# Build each package individually with timeout
for pkg in ~/sdk/package/luci-app-*/; do
if [[ -d "$pkg" ]]; then
PKG_NAME=$(basename "$pkg")
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📦 Building: $PKG_NAME"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Build with 5 minute timeout per package
if timeout 5m make package/${PKG_NAME}/compile V=s -j$(nproc) 2>&1; then
echo "✅ Built: $PKG_NAME"
BUILT=$((BUILT + 1))
else
echo "❌ Failed: $PKG_NAME"
FAILED=$((FAILED + 1))
fi
fi
done
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📊 Build Summary"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Built: $BUILT packages"
echo "Failed: $FAILED packages"
if [[ $BUILT -eq 0 ]]; then
echo "❌ No packages were built!"
exit 1
fi
- name: Verify output
run: |
echo "📋 Built packages:"
find ~/sdk/bin -name "luci-app-*.ipk" -exec ls -la {} \;
PKG_COUNT=$(find ~/sdk/bin -name "luci-app-*.ipk" | wc -l)
echo ""
echo "📦 Total packages built: $PKG_COUNT"
if [[ $PKG_COUNT -eq 0 ]]; then
echo "❌ No packages were built!"
exit 1
fi
echo "✅ Build test passed"
# ============================================
# Generate documentation
# ============================================
docs:
runs-on: ubuntu-latest
name: Generate Docs
needs: lint
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate package list
run: |
echo "# SecuBox Packages" > PACKAGES.md
echo "" >> PACKAGES.md
echo "Auto-generated package documentation." >> PACKAGES.md
echo "" >> PACKAGES.md
echo "| Package | Version | Description |" >> PACKAGES.md
echo "|---------|---------|-------------|" >> PACKAGES.md
for makefile in luci-app-*/Makefile; do
if [[ -f "$makefile" ]]; then
PKG_NAME=$(grep "^PKG_NAME:=" "$makefile" | cut -d'=' -f2)
PKG_VERSION=$(grep "^PKG_VERSION:=" "$makefile" | cut -d'=' -f2)
PKG_TITLE=$(grep "^LUCI_TITLE:=" "$makefile" | cut -d'=' -f2- | sed 's/^[[:space:]]*//')
# Fallback if LUCI_TITLE not found
if [[ -z "$PKG_TITLE" ]]; then
PKG_TITLE=$(grep "TITLE:=" "$makefile" | head -1 | cut -d'=' -f2- | sed 's/^[[:space:]]*//')
fi
echo "| $PKG_NAME | $PKG_VERSION | $PKG_TITLE |" >> PACKAGES.md
fi
done
echo "" >> PACKAGES.md
echo "---" >> PACKAGES.md
echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> PACKAGES.md
echo "📋 Generated PACKAGES.md:"
cat PACKAGES.md
- name: Upload docs
uses: actions/upload-artifact@v4
with:
name: documentation
path: PACKAGES.md