410 lines
13 KiB
YAML
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
|