Skip to content

Commit 35958a8

Browse files
authored
Merge branch 'main' into 43-monitoring-implement-prometheus-grafana-with-alerting
2 parents afc3d37 + 65f65ba commit 35958a8

80 files changed

Lines changed: 9885 additions & 935 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/build-and-test-client.yml‎

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ jobs:
4343
run: npm ci
4444

4545
- name: Lint code
46+
id: lint
4647
run: npm run lint
4748
continue-on-error: true
4849

4950
- name: Run tests if test files exist (.test.* or in __tests__ directories)
51+
id: run-tests
5052
run: |
5153
# Only look in directories that exist to avoid find errors
5254
paths=""
@@ -58,12 +60,18 @@ jobs:
5860
if [ -n "$test_files" ]; then
5961
echo "Test files found:"
6062
echo "$test_files"
61-
npm run test
63+
echo "tests_found=true" >> $GITHUB_OUTPUT
64+
# Run tests and capture output
65+
npm run test 2>&1 | tee test-output.txt
66+
TEST_EXIT_CODE=${PIPESTATUS[0]}
67+
echo "test_exit_code=$TEST_EXIT_CODE" >> $GITHUB_OUTPUT
6268
else
6369
echo "No test files found (no *.test.* or __tests__/*). Skipping tests."
70+
echo "tests_found=false" >> $GITHUB_OUTPUT
6471
fi
6572
else
6673
echo "No test or src directories found, skipping tests."
74+
echo "tests_found=false" >> $GITHUB_OUTPUT
6775
fi
6876
6977
- name: Build client
@@ -87,4 +95,70 @@ jobs:
8795
echo "No build output found - Build and Test Client workflow failed."
8896
exit 1
8997
fi
98+
- name: Post workflow summary
99+
if: always()
100+
run: |
101+
echo "## Workflow Summary" >> $GITHUB_STEP_SUMMARY
102+
echo "- Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
103+
echo "- Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
104+
echo "- Branch: ${{ github.ref }}" >> $GITHUB_STEP_SUMMARY
105+
echo "- Node Version: $(node -v)" >> $GITHUB_STEP_SUMMARY
106+
107+
echo "" >> $GITHUB_STEP_SUMMARY
108+
echo "### Test Results" >> $GITHUB_STEP_SUMMARY
109+
110+
if [ "${{ steps.run-tests.outputs.tests_found }}" = "true" ]; then
111+
if [ "${{ steps.run-tests.outputs.test_exit_code }}" = "0" ]; then
112+
echo "✅ **Tests Passed**" >> $GITHUB_STEP_SUMMARY
113+
else
114+
echo "❌ **Tests Failed**" >> $GITHUB_STEP_SUMMARY
115+
fi
116+
117+
# Strip ANSI escape codes from test-output.txt
118+
if [ -f test-output.txt ]; then
119+
sed -r "s/\x1B\[[0-9;]*[mK]//g" test-output.txt > test-clean.txt
120+
121+
# Extract test statistics
122+
TEST_STATS=$(grep -E "Test Files|Tests" test-clean.txt | tail -2)
123+
if [ -n "$TEST_STATS" ]; then
124+
echo "" >> $GITHUB_STEP_SUMMARY
125+
echo "**Test Statistics:**" >> $GITHUB_STEP_SUMMARY
126+
echo '```' >> $GITHUB_STEP_SUMMARY
127+
echo "$TEST_STATS" >> $GITHUB_STEP_SUMMARY
128+
echo '```' >> $GITHUB_STEP_SUMMARY
129+
fi
130+
131+
# Extract and filter coverage summary from cleaned output
132+
COVERAGE_INFO=$(awk '/Coverage report from v8/,0' test-clean.txt | grep -E '^All files|^ src/services|^ src/services' | head -n 20)
133+
if [ -n "$COVERAGE_INFO" ]; then
134+
echo "" >> $GITHUB_STEP_SUMMARY
135+
echo "**Coverage Summary (src/services only):**" >> $GITHUB_STEP_SUMMARY
136+
echo '```' >> $GITHUB_STEP_SUMMARY
137+
echo "$COVERAGE_INFO" >> $GITHUB_STEP_SUMMARY
138+
echo '```' >> $GITHUB_STEP_SUMMARY
139+
fi
140+
fi
141+
else
142+
echo "⚠️ **No tests found** - Skipped test execution" >> $GITHUB_STEP_SUMMARY
143+
fi
144+
145+
echo "" >> $GITHUB_STEP_SUMMARY
146+
echo "### Build Results" >> $GITHUB_STEP_SUMMARY
90147
148+
if [ -d dist ]; then
149+
echo "✅ **Build successful** - Output found in dist/" >> $GITHUB_STEP_SUMMARY
150+
BUILD_SIZE=$(du -sh dist 2>/dev/null | cut -f1)
151+
if [ -n "$BUILD_SIZE" ]; then
152+
echo "- Build size: $BUILD_SIZE" >> $GITHUB_STEP_SUMMARY
153+
fi
154+
else
155+
echo "❌ **Build failed** - No dist/ directory found" >> $GITHUB_STEP_SUMMARY
156+
fi
157+
158+
echo "" >> $GITHUB_STEP_SUMMARY
159+
echo "### Code Quality" >> $GITHUB_STEP_SUMMARY
160+
if [ "${{ steps.lint.outcome }}" = "success" ]; then
161+
echo "✅ **Linting passed**" >> $GITHUB_STEP_SUMMARY
162+
else
163+
echo "⚠️ **Linting failed** (continued on error)" >> $GITHUB_STEP_SUMMARY
164+
fi

‎.github/workflows/build-and-test-server.yml‎

Lines changed: 178 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ jobs:
2222
test-gateway:
2323
name: Build & Test Gateway
2424
runs-on: ubuntu-latest
25-
services:
26-
redis:
27-
image: redis:7-alpine
28-
ports:
29-
- 6379:6379
3025
defaults:
3126
run:
3227
working-directory: server/skillforge-gateway
@@ -39,29 +34,77 @@ jobs:
3934
distribution: 'temurin'
4035
cache: 'gradle'
4136
- uses: ./.github/actions/create-dotenv
42-
- name: Build and test
37+
- name: Build application
4338
env:
4439
SPRING_PROFILES_ACTIVE: test
45-
REDIS_HOST: redis
46-
REDIS_PORT: 6379
40+
JWT_SECRET: test-jwt-secret-key-for-testing-only
41+
JWT_EXPIRATION_MS: 3600000
4742
run: ./gradlew build --no-daemon --scan
43+
- name: Run unit tests with coverage
44+
env:
45+
SPRING_PROFILES_ACTIVE: test
46+
JWT_SECRET: test-jwt-secret-key-for-testing-only
47+
JWT_EXPIRATION_MS: 3600000
48+
run: ./gradlew clean test jacocoTestReport --no-daemon --info
49+
- name: Upload coverage reports
50+
uses: actions/upload-artifact@v4
51+
with:
52+
name: coverage-reports-gateway-service
53+
path: ${{ github.workspace }}/server/skillforge-gateway/build/reports/jacoco/test/
54+
retention-days: 30
55+
- name: Extract coverage metrics
56+
if: always()
57+
run: |
58+
COVERAGE_XML="build/reports/jacoco/test/jacocoTestReport.xml"
59+
if [ -f "$COVERAGE_XML" ]; then
60+
# Extract missed and covered line counts
61+
LINE_MISSED=$(grep 'counter type="LINE"' "$COVERAGE_XML" | sed -n 's/.*missed="\([0-9]*\)".*/\1/p')
62+
LINE_COVERED=$(grep 'counter type="LINE"' "$COVERAGE_XML" | sed -n 's/.*covered="\([0-9]*\)".*/\1/p')
63+
64+
BRANCH_MISSED=$(grep 'counter type="BRANCH"' "$COVERAGE_XML" | sed -n 's/.*missed="\([0-9]*\)".*/\1/p')
65+
BRANCH_COVERED=$(grep 'counter type="BRANCH"' "$COVERAGE_XML" | sed -n 's/.*covered="\([0-9]*\)".*/\1/p')
66+
67+
LINE_TOTAL=$((LINE_MISSED + LINE_COVERED))
68+
BRANCH_TOTAL=$((BRANCH_MISSED + BRANCH_COVERED))
69+
70+
if [ "$LINE_TOTAL" -gt 0 ]; then
71+
LINE_PERCENT=$(echo "scale=1; 100 * $LINE_COVERED / $LINE_TOTAL" | bc -l)
72+
else
73+
LINE_PERCENT=0.0
74+
fi
75+
76+
if [ "$BRANCH_TOTAL" -gt 0 ]; then
77+
BRANCH_PERCENT=$(echo "scale=1; 100 * $BRANCH_COVERED / $BRANCH_TOTAL" | bc -l)
78+
else
79+
BRANCH_PERCENT=0.0
80+
fi
81+
82+
echo "LINE_PERCENT=$LINE_PERCENT" >> $GITHUB_ENV
83+
echo "BRANCH_PERCENT=$BRANCH_PERCENT" >> $GITHUB_ENV
84+
else
85+
echo "COVERAGE FILE NOT FOUND"
86+
echo "LINE_PERCENT=0.0" >> $GITHUB_ENV
87+
echo "BRANCH_PERCENT=0.0" >> $GITHUB_ENV
88+
fi
4889
- name: Post workflow summary
4990
if: always()
5091
run: |
5192
echo "## Workflow Summary" >> $GITHUB_STEP_SUMMARY
5293
echo "- Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
5394
echo "- Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
5495
echo "- Branch: ${{ github.ref }}" >> $GITHUB_STEP_SUMMARY
55-
echo "- Run: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
56-
96+
echo "## 📊 Test Coverage Summary" >> $GITHUB_STEP_SUMMARY
97+
echo "### Gateway Service Coverage" >> $GITHUB_STEP_SUMMARY
98+
echo "- **Line Coverage**: ${{ env.LINE_PERCENT }}%" >> $GITHUB_STEP_SUMMARY
99+
echo "- **Branch Coverage**: ${{ env.BRANCH_PERCENT }}%" >> $GITHUB_STEP_SUMMARY
100+
echo "" >> $GITHUB_STEP_SUMMARY
101+
echo "### Coverage Reports" >> $GITHUB_STEP_SUMMARY
102+
echo "- ✅ **HTML Report** successfully generated" >> $GITHUB_STEP_SUMMARY
103+
echo "- 🧾 XML Report: Available for CI/CD integration" >> $GITHUB_STEP_SUMMARY
104+
echo "- 📁 Navigate to \`coverage-reports/index.html\` inside the artifact to open the report." >> $GITHUB_STEP_SUMMARY
57105
test-user-service:
58106
name: Build & Test User Service
59107
runs-on: ubuntu-latest
60-
services:
61-
mongo:
62-
image: mongo:7
63-
ports:
64-
- 27017:27017
65108
defaults:
66109
run:
67110
working-directory: server/skillforge-user
@@ -74,30 +117,77 @@ jobs:
74117
distribution: 'temurin'
75118
cache: 'gradle'
76119
- uses: ./.github/actions/create-dotenv
77-
- name: Build and test
120+
- name: Build application
78121
env:
79122
SPRING_PROFILES_ACTIVE: test
80-
JWT_SECRET: test-jwt-secret
123+
JWT_SECRET: test-jwt-secret-key-for-testing-only
81124
JWT_EXPIRATION_MS: 3600000
82-
MONGO_URL: mongodb://localhost:27017/test
83-
run: ./gradlew build --no-daemon --scan
125+
run: ./gradlew build -x test --no-daemon
126+
- name: Run unit tests with coverage
127+
env:
128+
SPRING_PROFILES_ACTIVE: test
129+
JWT_SECRET: test-jwt-secret-key-for-testing-only
130+
JWT_EXPIRATION_MS: 3600000
131+
run: ./gradlew clean test jacocoTestReport --no-daemon --info
132+
- name: Upload coverage reports
133+
uses: actions/upload-artifact@v4
134+
with:
135+
name: coverage-reports-user-service
136+
path: ${{ github.workspace }}/server/skillforge-user/build/reports/jacoco/test/
137+
retention-days: 30
138+
- name: Extract coverage metrics
139+
if: always()
140+
run: |
141+
COVERAGE_XML="build/reports/jacoco/test/jacocoTestReport.xml"
142+
if [ -f "$COVERAGE_XML" ]; then
143+
# Extract missed and covered line counts
144+
LINE_MISSED=$(grep 'counter type="LINE"' "$COVERAGE_XML" | sed -n 's/.*missed="\([0-9]*\)".*/\1/p')
145+
LINE_COVERED=$(grep 'counter type="LINE"' "$COVERAGE_XML" | sed -n 's/.*covered="\([0-9]*\)".*/\1/p')
146+
147+
BRANCH_MISSED=$(grep 'counter type="BRANCH"' "$COVERAGE_XML" | sed -n 's/.*missed="\([0-9]*\)".*/\1/p')
148+
BRANCH_COVERED=$(grep 'counter type="BRANCH"' "$COVERAGE_XML" | sed -n 's/.*covered="\([0-9]*\)".*/\1/p')
149+
150+
LINE_TOTAL=$((LINE_MISSED + LINE_COVERED))
151+
BRANCH_TOTAL=$((BRANCH_MISSED + BRANCH_COVERED))
152+
153+
if [ "$LINE_TOTAL" -gt 0 ]; then
154+
LINE_PERCENT=$(echo "scale=1; 100 * $LINE_COVERED / $LINE_TOTAL" | bc -l)
155+
else
156+
LINE_PERCENT=0.0
157+
fi
158+
159+
if [ "$BRANCH_TOTAL" -gt 0 ]; then
160+
BRANCH_PERCENT=$(echo "scale=1; 100 * $BRANCH_COVERED / $BRANCH_TOTAL" | bc -l)
161+
else
162+
BRANCH_PERCENT=0.0
163+
fi
164+
165+
echo "LINE_PERCENT=$LINE_PERCENT" >> $GITHUB_ENV
166+
echo "BRANCH_PERCENT=$BRANCH_PERCENT" >> $GITHUB_ENV
167+
else
168+
echo "COVERAGE FILE NOT FOUND"
169+
echo "LINE_PERCENT=0.0" >> $GITHUB_ENV
170+
echo "BRANCH_PERCENT=0.0" >> $GITHUB_ENV
171+
fi
84172
- name: Post workflow summary
85173
if: always()
86174
run: |
87175
echo "## Workflow Summary" >> $GITHUB_STEP_SUMMARY
88176
echo "- Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
89177
echo "- Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
90178
echo "- Branch: ${{ github.ref }}" >> $GITHUB_STEP_SUMMARY
91-
echo "- Run: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
92-
179+
echo "## 📊 Test Coverage Summary" >> $GITHUB_STEP_SUMMARY
180+
echo "### User Service Coverage" >> $GITHUB_STEP_SUMMARY
181+
echo "- **Line Coverage**: ${{ env.LINE_PERCENT }}%" >> $GITHUB_STEP_SUMMARY
182+
echo "- **Branch Coverage**: ${{ env.BRANCH_PERCENT }}%" >> $GITHUB_STEP_SUMMARY
183+
echo "" >> $GITHUB_STEP_SUMMARY
184+
echo "### Coverage Reports" >> $GITHUB_STEP_SUMMARY
185+
echo "- ✅ **HTML Report** successfully generated" >> $GITHUB_STEP_SUMMARY
186+
echo "- 🧾 XML Report: Available for CI/CD integration" >> $GITHUB_STEP_SUMMARY
187+
echo "- 📁 Navigate to \`coverage-reports/index.html\` inside the artifact to open the report." >> $GITHUB_STEP_SUMMARY
93188
test-course-service:
94189
name: Build & Test Course Service
95190
runs-on: ubuntu-latest
96-
services:
97-
mongo:
98-
image: mongo:7
99-
ports:
100-
- 27017:27017
101191
defaults:
102192
run:
103193
working-directory: server/skillforge-course
@@ -110,18 +200,74 @@ jobs:
110200
distribution: 'temurin'
111201
cache: 'gradle'
112202
- uses: ./.github/actions/create-dotenv
113-
- name: Build and test
203+
204+
- name: Build application
114205
env:
115206
SPRING_PROFILES_ACTIVE: test
116-
MONGO_URL: mongodb://localhost:27017/test
117-
SERVER_HOST_GENAI: localhost
118-
SERVER_PORT_GENAI: 8888
119-
run: ./gradlew build --no-daemon --scan
207+
JWT_SECRET: test-jwt-secret-key-for-testing-only
208+
JWT_EXPIRATION_MS: 3600000
209+
run: ./gradlew build -x test --no-daemon
210+
211+
- name: Run unit tests with coverage
212+
env:
213+
SPRING_PROFILES_ACTIVE: test
214+
JWT_SECRET: test-jwt-secret-key-for-testing-only
215+
JWT_EXPIRATION_MS: 3600000
216+
run: ./gradlew clean test jacocoTestReport --no-daemon --info
217+
218+
- name: Upload coverage reports
219+
uses: actions/upload-artifact@v4
220+
with:
221+
name: coverage-reports-course-service
222+
path: ${{ github.workspace }}/server/skillforge-course/build/reports/jacoco/test/
223+
retention-days: 30
224+
- name: Extract coverage metrics
225+
if: always()
226+
run: |
227+
COVERAGE_XML="build/reports/jacoco/test/jacocoTestReport.xml"
228+
if [ -f "$COVERAGE_XML" ]; then
229+
# Extract missed and covered line counts
230+
LINE_MISSED=$(grep 'counter type="LINE"' "$COVERAGE_XML" | sed -n 's/.*missed="\([0-9]*\)".*/\1/p')
231+
LINE_COVERED=$(grep 'counter type="LINE"' "$COVERAGE_XML" | sed -n 's/.*covered="\([0-9]*\)".*/\1/p')
232+
233+
BRANCH_MISSED=$(grep 'counter type="BRANCH"' "$COVERAGE_XML" | sed -n 's/.*missed="\([0-9]*\)".*/\1/p')
234+
BRANCH_COVERED=$(grep 'counter type="BRANCH"' "$COVERAGE_XML" | sed -n 's/.*covered="\([0-9]*\)".*/\1/p')
235+
236+
LINE_TOTAL=$((LINE_MISSED + LINE_COVERED))
237+
BRANCH_TOTAL=$((BRANCH_MISSED + BRANCH_COVERED))
238+
239+
if [ "$LINE_TOTAL" -gt 0 ]; then
240+
LINE_PERCENT=$(echo "scale=1; 100 * $LINE_COVERED / $LINE_TOTAL" | bc -l)
241+
else
242+
LINE_PERCENT=0.0
243+
fi
244+
245+
if [ "$BRANCH_TOTAL" -gt 0 ]; then
246+
BRANCH_PERCENT=$(echo "scale=1; 100 * $BRANCH_COVERED / $BRANCH_TOTAL" | bc -l)
247+
else
248+
BRANCH_PERCENT=0.0
249+
fi
250+
251+
echo "LINE_PERCENT=$LINE_PERCENT" >> $GITHUB_ENV
252+
echo "BRANCH_PERCENT=$BRANCH_PERCENT" >> $GITHUB_ENV
253+
else
254+
echo "COVERAGE FILE NOT FOUND"
255+
echo "LINE_PERCENT=0.0" >> $GITHUB_ENV
256+
echo "BRANCH_PERCENT=0.0" >> $GITHUB_ENV
257+
fi
120258
- name: Post workflow summary
121259
if: always()
122260
run: |
123261
echo "## Workflow Summary" >> $GITHUB_STEP_SUMMARY
124262
echo "- Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
125263
echo "- Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
126264
echo "- Branch: ${{ github.ref }}" >> $GITHUB_STEP_SUMMARY
127-
echo "- Run: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
265+
echo "## 📊 Test Coverage Summary" >> $GITHUB_STEP_SUMMARY
266+
echo "### Course Service Coverage" >> $GITHUB_STEP_SUMMARY
267+
echo "- **Line Coverage**: ${{ env.LINE_PERCENT }}%" >> $GITHUB_STEP_SUMMARY
268+
echo "- **Branch Coverage**: ${{ env.BRANCH_PERCENT }}%" >> $GITHUB_STEP_SUMMARY
269+
echo "" >> $GITHUB_STEP_SUMMARY
270+
echo "### Coverage Reports" >> $GITHUB_STEP_SUMMARY
271+
echo "- ✅ **HTML Report** successfully generated" >> $GITHUB_STEP_SUMMARY
272+
echo "- 🧾 XML Report: Available for CI/CD integration" >> $GITHUB_STEP_SUMMARY
273+
echo "- 📁 Navigate to \`coverage-reports/index.html\` inside the artifact to open the report." >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)