name: Frontend (React) on: push: paths: - 'frontend/**' - '.gitea/workflows/frontend.yml' pull_request: paths: - 'frontend/**' env: REGISTRY: gitea.example.com IMAGE_PREFIX: labfusion SERVICE_NAME: frontend jobs: test: runs-on: [self-hosted] env: RUNNER_TOOL_CACHE: /toolcache defaults: run: working-directory: ./frontend strategy: matrix: node-version: [20] steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Cache npm dependencies uses: actions/cache@v4 with: path: | ~/.npm node_modules ~/.cache/node-gyp key: npm-${{ runner.os }}-${{ matrix.node-version }}-${{ hashFiles('frontend/package-lock.json') }} restore-keys: | npm-${{ runner.os }}-${{ matrix.node-version }}- npm-${{ runner.os }}- npm- fail-on-cache-miss: false - name: Install dependencies run: | if [ -f package-lock.json ]; then npm ci else npm install fi - name: Run linting run: | npm run lint npm run lint:fix --dry-run - name: Run security audit run: | npm audit --audit-level=moderate npm audit fix --dry-run - name: Run tests run: | npx vitest run --coverage --reporter=verbose - name: Verify coverage files run: | echo "Checking coverage files..." ls -la coverage/ echo "Required coverage files:" if [ -f "coverage/lcov.info" ]; then echo "✓ lcov.info found" else echo "✗ lcov.info missing" fi if [ -f "coverage/clover.xml" ]; then echo "✓ clover.xml found" else echo "✗ clover.xml missing" fi - name: Send results to SonarQube run: | echo "Sending Frontend results to SonarQube..." # Install SonarQube Scanner for Node.js npm install -g @sonar/scan # Run SonarQube analysis sonar-scanner \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ -Dsonar.projectKey=labfusion-frontend \ -Dsonar.projectName=LabFusion Frontend \ -Dsonar.sources=src \ -Dsonar.tests=src \ -Dsonar.sources.inclusions=**/*.js,**/*.jsx \ -Dsonar.sources.exclusions=**/*.test.js,**/*.test.jsx,**/*.spec.js,**/*.spec.jsx,src/index.js,src/setupTests.js \ -Dsonar.tests.inclusions=**/*.test.js,**/*.test.jsx,**/*.spec.js,**/*.spec.jsx \ -Dsonar.coverage.exclusions=**/*.test.js,**/*.test.jsx,**/*.spec.js,**/*.spec.jsx,src/index.js,src/setupTests.js \ -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info \ -Dsonar.coverageReportPaths=coverage/clover.xml - name: Test results summary if: always() run: | echo "Test results available in pipeline logs" echo "Coverage report: frontend/coverage/" echo "Vitest test results: frontend/test-results/" build: runs-on: [self-hosted] needs: test defaults: run: working-directory: ./frontend steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Node.js 20 uses: actions/setup-node@v4 with: node-version: '20' - name: Cache npm dependencies uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-20-${{ hashFiles('frontend/package-lock.json') }} restore-keys: | ${{ runner.os }}-node-20- ${{ runner.os }}-node- - name: Install dependencies run: | if [ -f package-lock.json ]; then npm ci else npm install fi - name: Build application run: | npm run build npm run build:analyze - name: Build artifacts summary run: | echo "Build artifacts created in frontend/build/" echo "Build analysis available in pipeline logs" - name: Build Docker image (test only) run: docker build -t frontend:test . lighthouse: runs-on: [self-hosted] needs: build if: github.event_name == 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 - name: Build application for Lighthouse run: | cd frontend npm ci npm run build - name: Run Lighthouse CI uses: treosh/lighthouse-ci-action@v10 with: configPath: './frontend/.lighthouserc.json' uploadArtifacts: true temporaryPublicStorage: true