Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 22 additions & 274 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Frontend CI/CD Enhanced
name: Frontend CI/CD Optimized

on:
push:
Expand All @@ -15,19 +15,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: write
checks: write

env:
NODE_VERSION: '20.x'
WORKING_DIR: 'ui/trading-bot-ui'

jobs:
test:
build-and-test:
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
run:
working-directory: ui/trading-bot-ui
Expand All @@ -36,291 +26,49 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js with caching
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
node-version: '20'
cache: 'npm'
cache-dependency-path: ui/trading-bot-ui/package-lock.json

- name: Cache node modules
uses: actions/cache@v4
with:
path: |
ui/trading-bot-ui/node_modules
~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('ui/trading-bot-ui/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install dependencies
run: |
echo "Installing frontend dependencies..."
if [ -f "package-lock.json" ]; then
npm ci --prefer-offline --no-audit
else
npm install --prefer-offline --no-audit
fi

# Verify critical dependencies
echo "Verifying critical dependencies..."
npm list react react-dom @mui/material || echo "Some packages may be missing"
run: npm ci --prefer-offline --no-audit

- name: Run ESLint
- name: Fast Lint & Type Check
run: |
echo "Running ESLint checks..."
if [ -f ".eslintrc.js" ] || [ -f ".eslintrc.json" ] || [ -f "eslint.config.js" ] || grep -q '"eslint"' package.json; then
if npm run lint 2>&1 | tee ../eslint-results.log; then
echo "ESLint passed"
echo "eslint_status=passed" >> $GITHUB_ENV
else
echo "ESLint found issues"
echo "eslint_status=failed" >> $GITHUB_ENV
# Don't fail the workflow, just report
fi
else
echo "No ESLint configuration found, running default check"
if npx eslint src/ --ext .js,.jsx,.ts,.tsx --format=compact --max-warnings=0; then
echo "ESLint default check passed"
else
echo "ESLint default check found issues"
fi
fi
npm run lint || echo "Linting failed but continuing"
npx tsc --noEmit || echo "Type check failed but continuing"

- name: Run Prettier check
run: |
echo "Checking code formatting with Prettier..."
if [ -f ".prettierrc" ] || [ -f ".prettierrc.json" ] || [ -f "prettier.config.js" ]; then
if npx prettier --check src/ 2>&1 | tee ../prettier-results.log; then
echo "Prettier check passed"
echo "prettier_status=passed" >> $GITHUB_ENV
else
echo "Code formatting issues found"
echo "prettier_status=failed" >> $GITHUB_ENV
fi
else
echo "No Prettier configuration found, using defaults"
if npx prettier --check "src/**/*.{js,jsx,ts,tsx,css,json}" 2>&1 | tee ../prettier-results.log; then
echo "Prettier default check passed"
else
echo "Formatting issues found with defaults"
fi
fi

- name: Type checking
run: |
echo "Running TypeScript type checking..."
if [ -f "tsconfig.json" ]; then
if npx tsc --noEmit 2>&1 | tee ../typecheck-results.log; then
echo "Type checking passed"
echo "typecheck_status=passed" >> $GITHUB_ENV
else
echo "Type checking found issues"
echo "typecheck_status=failed" >> $GITHUB_ENV
fi
else
echo "No TypeScript configuration found, skipping type check"
echo "typecheck_status=skipped" >> $GITHUB_ENV
fi

- name: Run tests
- name: Build Application
env:
CI: true
WATCHMAN_DISABLE_CI: 1
run: |
echo "Running frontend tests..."

# Check if tests exist
if [ -d "src/__tests__" ] || [ -f "src/App.test.js" ] || find src -name "*.test.js" -o -name "*.test.jsx" -o -name "*.test.ts" -o -name "*.test.tsx" | grep -q .; then
echo "Running existing tests..."
npm test -- --coverage --watchAll=false --ci --testResultsProcessor=jest-junit --passWithNoTests 2>&1 | tee ../test-results.log

# Check if coverage directory exists
if [ -d "coverage" ]; then
echo "Coverage report generated"
echo "test_coverage=available" >> $GITHUB_ENV
fi
else
echo "No tests found, creating basic smoke test..."
mkdir -p src/__tests__

# Create a simple smoke test file
echo "import { render } from '@testing-library/react';" > src/__tests__/App.smoke.test.js
echo "import App from '../App';" >> src/__tests__/App.smoke.test.js
echo "" >> src/__tests__/App.smoke.test.js
echo "test('renders without crashing', () => {" >> src/__tests__/App.smoke.test.js
echo " try {" >> src/__tests__/App.smoke.test.js
echo " render(<App />);" >> src/__tests__/App.smoke.test.js
echo " expect(true).toBe(true);" >> src/__tests__/App.smoke.test.js
echo " } catch (error) {" >> src/__tests__/App.smoke.test.js
echo " console.warn('App render failed:', error.message);" >> src/__tests__/App.smoke.test.js
echo " expect(true).toBe(true);" >> src/__tests__/App.smoke.test.js
echo " }" >> src/__tests__/App.smoke.test.js
echo "});" >> src/__tests__/App.smoke.test.js

# Install testing dependencies if not present
if ! npm list @testing-library/react &>/dev/null; then
npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event
fi

npm test -- --coverage --watchAll=false --ci --passWithNoTests 2>&1 | tee ../test-results.log || echo "Basic tests completed"
echo "test_coverage=basic" >> $GITHUB_ENV
fi

- name: Bundle size analysis
run: |
echo "Analyzing bundle size..."

# Check if build directory exists first
if [ ! -d "build" ]; then
echo "Build directory not found, skipping bundle analysis"
exit 0
fi

# Simple bundle size check without external script
if [ -d "build/static/js" ]; then
echo "Checking JavaScript bundle sizes:"
find build/static/js -name "*.js" ! -name "*.map" -exec ls -lh {} \; | awk '{print $9 ": " $5}'

# Calculate total size in bytes (more portable approach)
TOTAL_SIZE=$(find build/static/js -name "*.js" ! -name "*.map" -exec wc -c {} \; 2>/dev/null | awk '{sum+=$1} END {print sum+0}' || echo "0")

# Convert to MB (use basic arithmetic for portability)
if [ "$TOTAL_SIZE" -gt 0 ]; then
TOTAL_MB=$(echo "$TOTAL_SIZE" | awk '{printf "%.2f", $1/1024/1024}')
echo "Total JS bundle size: ${TOTAL_MB}MB"

# Check if bundle is too large (5MB = 5242880 bytes)
if [ "$TOTAL_SIZE" -gt 5242880 ]; then
echo "Warning: Bundle size is quite large (>5MB)"
exit 1
else
echo "Bundle size is acceptable"
fi
else
echo "Could not calculate bundle size"
fi
else
echo "No JavaScript bundles found to analyze"
fi

- name: Build application
env:
REACT_APP_API_URL: ${{ secrets.REACT_APP_API_URL || 'http://localhost:8000' }}
REACT_APP_WS_URL: ${{ secrets.REACT_APP_WS_URL || 'ws://localhost:8000' }}
REACT_APP_VERSION: ${{ github.sha }}
GENERATE_SOURCEMAP: false
CI: true
NODE_OPTIONS: --max_old_space_size=4096
run: |
echo "Building React application..."
echo "API URL: $REACT_APP_API_URL"
echo "WS URL: $REACT_APP_WS_URL"
echo "Version: $REACT_APP_VERSION"

npm run build 2>&1 | tee ../build-output.log

BUILD_EXIT_CODE=$?

if [ $BUILD_EXIT_CODE -eq 0 ]; then
echo "Build completed successfully"
echo "build_status=success" >> $GITHUB_ENV
else
echo "Build failed"
echo "build_status=failed" >> $GITHUB_ENV
exit 1
fi

- name: Validate build output
run: |
echo "Validating build output..."

# Check if build directory exists
if [ ! -d "build" ]; then
echo "❌ Build directory not found"
exit 1
fi

# Check critical files
REQUIRED_FILES=("build/index.html" "build/static/js" "build/static/css")

for file in "${REQUIRED_FILES[@]}"; do
if [ ! -e "$file" ]; then
echo "Required file/directory missing: $file"
exit 1
else
echo "Found: $file"
fi
done

# Check build size
BUILD_SIZE=$(du -sh build | cut -f1)
echo "Build size: $BUILD_SIZE"

# List build contents
echo "Build contents:"
find build -type f -name "*.js" -o -name "*.css" -o -name "*.html" | head -10

echo "Build validation completed"

- name: Upload build artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: frontend-build
path: |
ui/trading-bot-ui/build/
ui/trading-bot-ui/coverage/
retention-days: 7

- name: Upload test results
run: npm run build

- name: Upload Build Artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: frontend-test-results
path: |
eslint-results.log
prettier-results.log
typecheck-results.log
test-results.log
audit-results.json
build-output.log
retention-days: 30
name: production-build
path: ui/trading-bot-ui/build/
retention-days: 1

deploy:
runs-on: ubuntu-latest
needs: test
needs: build-and-test
if: github.ref == 'refs/heads/main'
defaults:
run:
working-directory: ui/trading-bot-ui

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
- name: Download Build Artifact
uses: actions/download-artifact@v4
with:
node-version: '20.x'
cache: 'npm'
cache-dependency-path: ui/trading-bot-ui/package-lock.json

- name: Install and build
run: |
npm ci --prefer-offline --no-audit || npm install --prefer-offline --no-audit
npm run build
env:
REACT_APP_API_URL: ${{ secrets.REACT_APP_API_URL }}
REACT_APP_WS_URL: ${{ secrets.REACT_APP_WS_URL }}
GENERATE_SOURCEMAP: false
CI: true
NODE_OPTIONS: --max_old_space_size=4096
name: production-build
path: build

- name: Deploy to Netlify
uses: netlify/actions/cli@master
if: ${{ secrets.NETLIFY_AUTH_TOKEN != '' && secrets.NETLIFY_SITE_ID != '' }}
with:
args: deploy --prod --dir=ui/trading-bot-ui/build
args: deploy --prod --dir=build
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
2 changes: 1 addition & 1 deletion .github/workflows/pr-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ jobs:

- name: Install dependencies
run: |
pip install google-generativeai PyGithub pandas upstox-python-sdk
pip install google-generativeai PyGithub pandas upstox-python-sdk httpx sqlalchemy psycopg2-binary

- name: Run Automated Backtest
env:
Expand Down
Loading
Loading