Skip to content

Commit ea8ee3b

Browse files
authored
Merge pull request #1822 from bcgov/dev
Dev
2 parents de070de + 12a1bc9 commit ea8ee3b

6 files changed

Lines changed: 585 additions & 24 deletions

File tree

Lines changed: 197 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,210 @@
1-
name: Dev - Branch Protection
1+
name: Dev - CI & Unit Tests
2+
23
permissions:
34
contents: read
5+
pull-requests: write
46

57
on:
68
pull_request:
79
branches:
810
- dev
911

1012
jobs:
13+
# ---------------------------------------------------------------------
14+
# 1. Validate PR source branch
15+
# ---------------------------------------------------------------------
1116
check-dev-branch:
17+
runs-on: ubuntu-latest
18+
outputs:
19+
branch-allowed: ${{ steps.branch-check.outputs.allowed }}
20+
steps:
21+
- name: Validate PR source branch
22+
id: branch-check
23+
run: |
24+
echo "Source branch: ${GITHUB_HEAD_REF}"
25+
if [[ ${GITHUB_HEAD_REF} =~ ^feature/ ]] || \
26+
[[ ${GITHUB_HEAD_REF} =~ ^hotfix/ ]] || \
27+
[[ ${GITHUB_HEAD_REF} =~ ^bugfix/ ]] || \
28+
[[ ${GITHUB_HEAD_REF} == "test" ]] || \
29+
[[ ${GITHUB_HEAD_REF} == "main" ]]; then
30+
echo "allowed=true" >> $GITHUB_OUTPUT
31+
else
32+
echo "❌ ERROR: PR into dev must come from:"
33+
echo " feature/*, hotfix/*, bugfix/*, test, or main"
34+
echo "allowed=false" >> $GITHUB_OUTPUT
35+
exit 1
36+
fi
37+
# ---------------------------------------------------------------------
38+
# 2. Discover all *Tests.csproj files and output into a matrix array
39+
# ---------------------------------------------------------------------
40+
discover-test-projects:
41+
needs: check-dev-branch
42+
if: needs.check-dev-branch.outputs.branch-allowed == 'true'
43+
runs-on: ubuntu-latest
44+
outputs:
45+
matrix: ${{ steps.discover.outputs.matrix }}
46+
steps:
47+
- uses: actions/checkout@v4
48+
49+
- id: discover
50+
run: |
51+
echo "🔍 Discovering test projects..."
52+
PROJECTS=$(find applications/Unity.GrantManager -name "*Tests.csproj")
53+
echo "$PROJECTS"
54+
# Convert list to JSON array for GitHub matrix
55+
MATRIX=$(printf '%s\n' $PROJECTS | jq -R -s -c 'split("\n")[:-1]')
56+
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
57+
# ---------------------------------------------------------------------
58+
# 3. Run tests for each project in parallel (matrix)
59+
# ---------------------------------------------------------------------
60+
test-project:
61+
needs: discover-test-projects
62+
runs-on: ubuntu-latest
63+
64+
strategy:
65+
fail-fast: false
66+
matrix:
67+
project: ${{ fromJson(needs.discover-test-projects.outputs.matrix) }}
68+
69+
steps:
70+
- uses: actions/checkout@v4
71+
72+
- uses: actions/setup-dotnet@v4
73+
with:
74+
dotnet-version: "9.0.x"
75+
76+
- name: Ensure TestResults folder exists
77+
run: mkdir -p TestResults
78+
79+
- name: Run unit tests
80+
run: |
81+
NAME=$(basename "${{ matrix.project }}" .csproj)
82+
TRX="TestResults/${NAME}.trx"
83+
echo "▶ Running: $NAME"
84+
dotnet test "${{ matrix.project }}" \
85+
--logger "trx;LogFileName=${NAME}.trx" \
86+
--results-directory TestResults
87+
88+
- uses: actions/upload-artifact@v4
89+
with:
90+
name: test-output-${{ strategy.job-index }}
91+
path: TestResults/
92+
93+
# ---------------------------------------------------------------------
94+
# 4. Merge all TRX and produce final results
95+
# ---------------------------------------------------------------------
96+
aggregate-results:
97+
needs: test-project
1298
runs-on: ubuntu-latest
1399
steps:
14-
- name: Check branch
100+
- uses: actions/download-artifact@v4
101+
with:
102+
path: artifacts/
103+
- name: Install ReportGenerator
104+
run: dotnet tool install -g dotnet-reportgenerator-globaltool
105+
106+
- name: Add dotnet tools to PATH
107+
run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH
108+
109+
- name: List TRX files
110+
run: |
111+
echo "🔍 TRX files:"
112+
find artifacts/ -name "*.trx"
113+
114+
115+
- name: Extract totals from merged trx files
116+
id: extract
15117
run: |
16-
if [[ ${GITHUB_HEAD_REF} =~ ^feature/ ]] || [[ ${GITHUB_HEAD_REF} == 'test' ]] || [[ ${GITHUB_HEAD_REF} == 'main' ]] || [[ ${GITHUB_HEAD_REF} =~ ^hotfix/ ]] || [[ ${GITHUB_HEAD_REF} =~ ^bugfix/ ]]; then
17-
echo ""
18-
echo "Notice: Pull Request into dev should come from a merged 'feature/*', 'hotfix/*', 'bugfix/*', 'test', or 'main' branch"
19-
echo "Notice: The dev branch is for new features, hotfixes, bugfixes and accepts merge, squash or rebase commits"
20-
exit 0
21-
fi
118+
PASSED=0
119+
FAILED=0
120+
SKIPPED=0
121+
for file in artifacts/**/*.trx; do
122+
COUNTERS=$(grep "<Counters " "$file")
123+
PASSED_FILE=$(echo "$COUNTERS" | sed -n 's/.*passed="\([0-9]*\)".*/\1/p')
124+
FAILED_FILE=$(echo "$COUNTERS" | sed -n 's/.*failed="\([0-9]*\)".*/\1/p')
125+
NOT_EXECUTED_FILE=$(echo "$COUNTERS" | sed -n 's/.*notExecuted="\([0-9]*\)".*/\1/p')
126+
PASSED=$((PASSED + PASSED_FILE))
127+
FAILED=$((FAILED + FAILED_FILE))
128+
SKIPPED=$((SKIPPED + NOT_EXECUTED_FILE))
129+
done
130+
131+
echo "Passed: $PASSED, Failed: $FAILED, Skipped: $SKIPPED"
132+
echo "passed=$PASSED" >> $GITHUB_OUTPUT
133+
echo "failed=$FAILED" >> $GITHUB_OUTPUT
134+
echo "skipped=$SKIPPED" >> $GITHUB_OUTPUT
135+
136+
- uses: actions/upload-artifact@v4
137+
with:
138+
name: merged-test-results
139+
path: merged/
140+
141+
- name: Build test badge
142+
id: badge
143+
run: |
144+
if [[ "${{ steps.extract.outputs.failed }}" -gt 0 ]]; then
145+
echo "badge=![Tests](https://img.shields.io/badge/Tests-Failing-red)" >> $GITHUB_OUTPUT
146+
else
147+
echo "badge=![Tests](https://img.shields.io/badge/Tests-Passing-brightgreen)" >> $GITHUB_OUTPUT
148+
fi
149+
- name: Post PR Comment
150+
uses: peter-evans/create-or-update-comment@v4
151+
with:
152+
issue-number: ${{ github.event.pull_request.number }}
153+
body: |
154+
## 🧪 Unit Test Results (Parallel Execution)
155+
${{ steps.badge.outputs.badge }}
156+
### 📊 Summary
157+
| Result | Count |
158+
|--------|-------|
159+
| ✅ Passed | `${{ steps.extract.outputs.passed }}` |
160+
| ❌ Failed | `${{ steps.extract.outputs.failed }}` |
161+
| ⚠️ Skipped | `${{ steps.extract.outputs.skipped }}` |
162+
### 📄 HTML Reports
163+
- **Merged Tests (HTML):** Included in artifacts
164+
_Generated automatically by CI._
165+
- name: Send Microsoft Teams Notification
166+
env:
167+
WEBHOOK_URL: ${{ secrets.TEAMS_UNITY_NOTIFICATIONS_CHANNEL }} # NOSONAR
168+
PR_TITLE: ${{ github.event.pull_request.title }}
169+
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
170+
PR_NUMBER: ${{ github.event.pull_request.number }}
171+
PASSED: ${{ steps.extract.outputs.failed == '0' && 'true' || 'false' }}
172+
PASSED_COUNT: ${{ steps.extract.outputs.passed }}
173+
FAILED_COUNT: ${{ steps.extract.outputs.failed }}
174+
SKIPPED_COUNT: ${{ steps.extract.outputs.skipped }}
175+
run: |
176+
if [[ "$PASSED" == "true" ]]; then
177+
COLOR="00FF00"
178+
STATUS="🟢 Tests Passed $PR_TITLE (by $PR_AUTHOR)"
179+
else
180+
COLOR="FF0000"
181+
STATUS="🔴 Tests Failed $PR_TITLE (by $PR_AUTHOR)"
182+
fi
183+
JSON=$(cat <<EOF
184+
{
185+
"@type": "MessageCard",
186+
"@context": "http://schema.org/extensions",
187+
"themeColor": "$COLOR",
188+
"activityImage": "https://bcgov.github.io/unity-docs/images/UnityLogo.png",
189+
"summary": "Unit Test Results",
190+
"title": "$STATUS - PR #$PR_NUMBER",
191+
"sections": [{
192+
"facts": [
193+
{ "name": "Passed", "value": "$PASSED_COUNT" },
194+
{ "name": "Failed", "value": "$FAILED_COUNT" },
195+
{ "name": "Skipped", "value": "$SKIPPED_COUNT" }
196+
],
197+
"markdown": true
198+
}]
199+
}
200+
EOF
201+
)
202+
203+
if [ -n "$WEBHOOK_URL" ]; then
204+
curl -H "Content-Type: application/json" -d "$JSON" "$WEBHOOK_URL"
205+
else
206+
echo "⚠️ TEAMS_NOTIFICATION_WEBHOOK_URL secret not configured, skipping notification"
207+
fi
208+
- name: Fail if tests failed
209+
if: steps.extract.outputs.failed != '0'
210+
run: exit 1

0 commit comments

Comments
 (0)