diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd91d3895..f1f5a2353 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -171,12 +171,15 @@ jobs: secrets: OPENAI_API_KEY: "${{ secrets.OPENAI_API_KEY }}" ANTHROPIC_API_KEY: "${{ secrets.ANTHROPIC_API_KEY }}" + CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" test-frontend-unit: needs: [path-filter, set-ci-condition] name: Run Frontend Unit Tests if: ${{ needs.path-filter.outputs.frontend == 'true' && needs.set-ci-condition.outputs.should-run-tests == 'true' }} uses: ./.github/workflows/jest_test.yml + secrets: + CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" test-frontend: needs: [path-filter, set-ci-condition] diff --git a/.github/workflows/jest_test.yml b/.github/workflows/jest_test.yml index e61e46aa4..0fe533017 100644 --- a/.github/workflows/jest_test.yml +++ b/.github/workflows/jest_test.yml @@ -2,6 +2,9 @@ name: Run Frontend Jest Unit Tests on: workflow_call: + secrets: + CODECOV_TOKEN: + required: false inputs: ref: description: "(Optional) ref to checkout" @@ -65,6 +68,16 @@ jobs: junitxml-title: Unit Test Results junitxml-path: src/frontend/test-results/junit.xml + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: src/frontend/coverage/lcov.info + flags: frontend + name: frontend-coverage + fail_ci_if_error: false + directory: src/frontend/coverage/ + - name: Upload Coverage Reports uses: actions/upload-artifact@v4 if: always() diff --git a/.github/workflows/python_test.yml b/.github/workflows/python_test.yml index 660ce99bc..3177d09a0 100644 --- a/.github/workflows/python_test.yml +++ b/.github/workflows/python_test.yml @@ -7,6 +7,8 @@ on: required: true ANTHROPIC_API_KEY: required: true + CODECOV_TOKEN: + required: false inputs: python-versions: description: "(Optional) Python versions to test" @@ -50,11 +52,13 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.ref || github.ref }} + - name: Setup Node.js uses: actions/setup-node@v4 id: setup-node with: node-version: ${{ env.NODE_VERSION }} + - name: "Setup Environment" uses: astral-sh/setup-uv@v6 with: @@ -62,15 +66,37 @@ jobs: cache-dependency-glob: "uv.lock" python-version: ${{ matrix.python-version }} prune-cache: false + - name: Install the project run: uv sync + - name: Run unit tests uses: nick-fields/retry@v3 with: timeout_minutes: 12 max_attempts: 2 - command: make unit_tests args="-x -vv --splits ${{ matrix.splitCount }} --group ${{ matrix.group }} --reruns 5" + command: make unit_tests args="-x -vv --splits ${{ matrix.splitCount }} --group ${{ matrix.group }} --reruns 5 --cov --cov-report=xml --cov-report=html" + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + if: matrix.python-version == '3.10' + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage.xml + flags: backend + name: backend-coverage-group-${{ matrix.group }} + fail_ci_if_error: false + directory: ./ + + - name: Upload coverage artifacts + uses: actions/upload-artifact@v4 + if: matrix.python-version == '3.10' + with: + name: backend-coverage-report-group-${{ matrix.group }} + path: | + coverage.xml + htmlcov/ + retention-days: 30 integration-tests: diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..371ddee8d --- /dev/null +++ b/codecov.yml @@ -0,0 +1,85 @@ +codecov: + # Don't block CI if codecov fails to process reports + require_ci_to_pass: false + notify: + after_n_builds: 1 # Comment after each report (don't wait for all) + +coverage: + precision: 2 + round: down + # Display range from 30-100% to provide meaningful color gradients + range: "30...100" + + status: + project: + # Overall project coverage target + default: + target: 60% + threshold: 3% + + # Backend coverage strategy: Aspirational target for progress tracking + # Current coverage: ~33%, Target: 55% (intentionally higher than current) + # This creates visual progress indicators (red->yellow->green) without blocking PRs + # Shows improvement over time while encouraging better test coverage + backend: + target: 55% + # Threshold: Allowable drop in coverage before failing the check + # 5% = coverage can drop from 33% to 28% without failing status + # Higher threshold to avoid blocking PRs during improvement phase + threshold: 5% + flags: + - backend + + # Frontend coverage: Realistic target based on current state + # Current coverage: ~70%, maintains existing high standards + frontend: + target: 70% + # Threshold: Allowable drop in coverage before failing the check + # 2% = coverage can drop from 70% to 68% without failing status + # Stricter threshold to maintain established quality standards + threshold: 2% + flags: + - frontend + + # New code coverage requirements - encourages well-tested new features + patch: + default: + target: 70% + threshold: 3% + +# PR comment configuration - what information to show in coverage reports +comment: + layout: "reach,diff,flags,tree" # Show coverage, changes, flags, and file tree + behavior: default + require_changes: false # Comment even if no changes + require_base: false # Don't require base branch comparison + require_head: true # Require current branch coverage + +# Define separate coverage tracking for frontend and backend +flags: + backend: + paths: + - src/backend/ + carryforward: true # Preserve coverage data across builds if missing + frontend: + paths: + - src/frontend/ + carryforward: true # Preserve coverage data across builds if missing + +# Files/directories to exclude from coverage calculations +ignore: + # Database migrations - infrastructure code, not business logic + - "src/backend/base/langflow/alembic/**" + # Test files themselves don't need coverage + - "src/backend/tests/**" + - "src/frontend/tests/**" + - "src/frontend/test-results/**" + # Build artifacts and dependencies + - "**/__pycache__/**" + - "**/*.pyc" + - "**/node_modules/**" + - "**/coverage/**" + # Python package init files - typically just imports + - "**/__init__.py" + # Database migrations + - "**/migrations/**" \ No newline at end of file