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
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:

permissions:
contents: read
pull-requests: write

concurrency:
group: ci-${{ github.ref }}
Expand Down Expand Up @@ -66,6 +67,16 @@ jobs:
path: backend/coverage/
retention-days: 14

- name: Upload backend coverage to Codecov
if: always()
uses: codecov/codecov-action@v4
continue-on-error: true
with:
files: backend/coverage/lcov.info
flags: backend
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false

# ---------------------------------------------------------------
# Frontend — lint, type-check, test, build
# ---------------------------------------------------------------
Expand Down Expand Up @@ -110,6 +121,16 @@ jobs:
path: frontend/coverage/
retention-days: 14

- name: Upload frontend coverage to Codecov
if: always()
uses: codecov/codecov-action@v4
continue-on-error: true
with:
files: frontend/coverage/lcov.info
flags: frontend
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false

# ---------------------------------------------------------------
# Contract — Rust/Soroban build, test, clippy, format
# ---------------------------------------------------------------
Expand Down
128 changes: 104 additions & 24 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ on:
permissions:
contents: read
checks: write
pull-requests: write

concurrency:
group: quality-${{ github.ref }}
cancel-in-progress: true

env:
COVERAGE_TARGET: '70'

jobs:
# ---------------------------------------------------------------
# Backend coverage + quality
Expand All @@ -36,27 +40,27 @@ jobs:
run: cd backend && npm run test:coverage || echo "⚠️ Coverage warnings (non-blocking)"
env:
NODE_ENV: test
- name: Check coverage threshold
- name: Enforce minimum coverage threshold (70%)
run: |
cd backend
if [ -f coverage/coverage-summary.json ]; then
COVERAGE=$(node -pe "Math.round(JSON.parse(require('fs').readFileSync('coverage/coverage-summary.json', 'utf8')).total.lines.pct)")
echo "Backend line coverage: ${COVERAGE}%"
if [ "$COVERAGE" -lt 50 ]; then
echo "::error::Backend coverage ${COVERAGE}% is below 50% threshold"
exit 1
fi
echo "✅ Backend coverage ${COVERAGE}% meets threshold"
else
echo "::warning::No coverage summary found"
fi
node ../scripts/check-coverage.mjs "${{ env.COVERAGE_TARGET }}"
- name: Upload coverage artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: backend-quality-coverage
path: backend/coverage/
retention-days: 30
- name: Upload to Codecov
if: always()
uses: codecov/codecov-action@v4
continue-on-error: true
with:
files: backend/coverage/lcov.info
flags: backend
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
verbose: true

# ---------------------------------------------------------------
# Frontend coverage + quality
Expand All @@ -75,27 +79,81 @@ jobs:
- name: Run tests with coverage
continue-on-error: true
run: cd frontend && npm run test:coverage || echo "⚠️ Coverage warnings (non-blocking)"
- name: Check coverage threshold
- name: Enforce minimum coverage threshold (70%)
run: |
cd frontend
if [ -f coverage/coverage-summary.json ]; then
COVERAGE=$(node -pe "Math.round(JSON.parse(require('fs').readFileSync('coverage/coverage-summary.json', 'utf8')).total.lines.pct)")
echo "Frontend line coverage: ${COVERAGE}%"
if [ "$COVERAGE" -lt 15 ]; then
echo "::error::Frontend coverage ${COVERAGE}% is below 50% threshold"
exit 1
fi
echo "✅ Frontend coverage ${COVERAGE}% meets threshold"
else
echo "::warning::No coverage summary found"
fi
node ../scripts/check-coverage.mjs "${{ env.COVERAGE_TARGET }}"
- name: Upload coverage artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: frontend-quality-coverage
path: frontend/coverage/
retention-days: 30
- name: Upload to Codecov
if: always()
uses: codecov/codecov-action@v4
continue-on-error: true
with:
files: frontend/coverage/lcov.info
flags: frontend
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
verbose: true

# ---------------------------------------------------------------
# Coverage trend reporting
# ---------------------------------------------------------------
coverage-trend:
name: Coverage Trend Report
runs-on: ubuntu-latest
needs: [backend-quality, frontend-quality]
if: always()
steps:
- uses: actions/checkout@v4
- name: Download backend coverage
uses: actions/download-artifact@v4
with:
name: backend-quality-coverage
path: coverage/backend
continue-on-error: true
- name: Download frontend coverage
uses: actions/download-artifact@v4
with:
name: frontend-quality-coverage
path: coverage/frontend
continue-on-error: true
- name: Restore coverage history
id: trend_cache
uses: actions/cache@v4
with:
path: coverage-trend-history.json
key: coverage-trend-${{ github.ref_name }}-${{ github.run_number }}
restore-keys: |
coverage-trend-${{ github.ref_name }}-
- name: Generate coverage trend report
run: node scripts/coverage-trend.mjs "${{ env.COVERAGE_TARGET }}"
env:
GITHUB_SHA: ${{ github.sha }}
GITHUB_RUN_NUMBER: ${{ github.run_number }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_STEP_SUMMARY: ${{ GITHUB_STEP_SUMMARY }}
- name: Save updated coverage history
if: always()
uses: actions/cache/save@v4
with:
path: coverage-trend-history.json
key: coverage-trend-${{ github.ref_name }}-${{ github.run_number }}
- name: Upload trend report artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-trend-report
path: |
coverage-trend.json
coverage-trend-history.json
coverage-trend.md
retention-days: 90

# ---------------------------------------------------------------
# Code format check (non-blocking lint)
Expand All @@ -119,3 +177,25 @@ jobs:
cd frontend
npm install
npm run lint || echo "⚠️ Frontend lint warnings (non-blocking)"

# ---------------------------------------------------------------
# Summary gate — all jobs must pass
# ---------------------------------------------------------------
quality-summary:
name: Quality Summary
runs-on: ubuntu-latest
needs: [backend-quality, frontend-quality, format-check]
if: always()
steps:
- name: Check results
run: |
echo "Backend Coverage: ${{ needs.backend-quality.result }}"
echo "Frontend Coverage: ${{ needs.frontend-quality.result }}"
echo "Format Check: ${{ needs.format-check.result }}"
if [[ "${{ needs.backend-quality.result }}" != "success" || \
"${{ needs.frontend-quality.result }}" != "success" || \
"${{ needs.format-check.result }}" != "success" ]]; then
echo "::error::One or more code-quality jobs failed"
exit 1
fi
echo "✅ All code-quality jobs passed"
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,25 @@

> Decentralized utility payment platform powered by Stellar blockchain

[![CI Pipeline](https://github.com/DevScoopee/nepa/actions/workflows/ci.yml/badge.svg)](https://github.com/DevScoopee/nepa/actions/workflows/ci.yml)
[![Code Quality](https://github.com/DevScoopee/nepa/actions/workflows/code-quality.yml/badge.svg)](https://github.com/DevScoopee/nepa/actions/workflows/code-quality.yml)
[![Backend Coverage](https://codecov.io/github/DevScoopee/nepa/branch/main/graph/badge.svg?flag=backend)](https://codecov.io/github/DevScoopee/nepa)
[![Frontend Coverage](https://codecov.io/github/DevScoopee/nepa/branch/main/graph/badge.svg?flag=frontend)](https://codecov.io/github/DevScoopee/nepa)
[![codecov](https://codecov.io/github/DevScoopee/nepa/branch/main/graph/badge.svg)](https://codecov.io/github/DevScoopee/nepa)

A modern microservices platform enabling seamless electricity and water bill payments through blockchain technology.

## 📊 Code Coverage

Minimum coverage threshold: **70%** (lines, statements, functions, branches) enforced in CI via Jest `coverageThreshold` and [Codecov](https://codecov.io/github/DevScoopee/nepa).

| Area | Command | Report |
|------|---------|--------|
| Backend | `cd backend && npm run test:coverage` | `backend/coverage/lcov-report/index.html` |
| Frontend | `cd frontend && npm run test:coverage` | `frontend/coverage/lcov-report/index.html` |

Coverage trends are reported on every CI run (see the **Coverage Trend Report** job summary) and tracked historically on Codecov.

## 🏗️ Project Structure

```
Expand Down
11 changes: 10 additions & 1 deletion backend/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,17 @@ module.exports = {
coverageReporters: [
'text',
'lcov',
'html'
'html',
'json-summary'
],
coverageThreshold: {
global: {
branches: 70,
functions: 70,
lines: 70,
statements: 70
}
},
setupFilesAfterEnv: ['<rootDir>/tests/setup.ts'],
testTimeout: 10000,
moduleNameMapper: {
Expand Down
58 changes: 58 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
codecov:
require_ci_to_pass: true
max_report_age: off

coverage:
precision: 2
round: down
range: 50..90

status:
project:
default:
target: 70%
threshold: 1%
if_ci_failed: error
backend:
target: 70%
threshold: 1%
flags:
- backend
frontend:
target: 70%
threshold: 1%
flags:
- frontend
patch:
default:
target: 70%
threshold: 5%
only_pulls: true

flags:
backend:
paths:
- backend/
carryforward: true
frontend:
paths:
- frontend/
carryforward: true

comment:
layout: reach, diff, flags, files, footer
behavior: default
require_changes: false
require_base: false
require_head: true

ignore:
- '**/*.d.ts'
- '**/dist/**'
- '**/build/**'
- '**/node_modules/**'
- 'backend/tests/**'
- 'backend/scripts/**'
- 'frontend/src/setupTests.ts'
- 'frontend/src/assets/**'
- 'frontend/src/contracts/**'
26 changes: 26 additions & 0 deletions coverage-trend-history.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[
{
"run": "42",
"sha": "abc1234",
"ref": "main",
"date": "2026-08-23T14:02:36.763Z",
"backend": {
"lines": null,
"statements": null,
"functions": null,
"branches": null
},
"frontend": {
"lines": null,
"statements": null,
"functions": null,
"branches": null
},
"combined": {
"lines": null,
"statements": null,
"functions": null,
"branches": null
}
}
]
24 changes: 24 additions & 0 deletions coverage-trend.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"run": "42",
"sha": "abc1234",
"ref": "main",
"date": "2026-08-23T14:02:36.763Z",
"backend": {
"lines": null,
"statements": null,
"functions": null,
"branches": null
},
"frontend": {
"lines": null,
"statements": null,
"functions": null,
"branches": null
},
"combined": {
"lines": null,
"statements": null,
"functions": null,
"branches": null
}
}
21 changes: 21 additions & 0 deletions coverage-trend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 📈 Coverage Trend Report

**Run:** #42 | **Ref:** `main` | **Commit:** abc1234

| Metric | Backend | Frontend | Combined | vs Previous Run |
|--------|---------|----------|----------|-----------------|
| lines | ❓ no data | ❓ no data | ❓ no data | n/a |
| statements | ❓ no data | ❓ no data | ❓ no data | n/a |
| functions | ❓ no data | ❓ no data | ❓ no data | n/a |
| branches | ❓ no data | ❓ no data | ❓ no data | n/a |

**Minimum threshold:** 70%

<details>
<summary>History (recent runs)</summary>

| Run | Date | Lines % | Functions % | Branches % (combined) |
|-----|------|---------|-------------|----------------------|
| #42 | 2026-08-23 | n/a | n/a | n/a |

</details>
Loading