Skip to content

Commit 01e34c8

Browse files
committed
Add CI workflows and enable code coverage reporting
Added the `coverlet.collector` package to enable code coverage collection during test runs. Updated the solution file to include a new folder structure for GitHub workflows and added two workflow files: `alerts.yml` and `build.yml`. The `build.yml` workflow automates the build and test process, triggering on `push` and `pull_request` events. It includes steps for dependency restoration, building, testing, and uploading test results and coverage reports. The `alerts.yml` workflow sends Discord notifications when the "Build & Test" workflow fails, providing details about the failure (commit message, failing job, and step). Notifications are skipped if the webhook URL is not set.
1 parent 7036841 commit 01e34c8

File tree

4 files changed

+153
-0
lines changed

4 files changed

+153
-0
lines changed

.github/workflows/alerts.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: "⚠️ Alerts — Discord (workflow_run)"
2+
3+
on:
4+
workflow_run:
5+
workflows:
6+
- "Build & Test"
7+
types: [completed]
8+
9+
permissions:
10+
actions: read
11+
contents: read
12+
13+
jobs:
14+
notify:
15+
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
16+
runs-on: ubuntu-latest
17+
env:
18+
WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_ALERTS }}
19+
20+
steps:
21+
- name: Skip if webhook missing
22+
if: ${{ env.WEBHOOK_URL == '' }}
23+
run: echo "::warning::DISCORD_WEBHOOK_ALERTS is not set — skipping notification."
24+
25+
- name: Prepare Discord payload (commit msg + failing step)
26+
id: prep
27+
if: ${{ env.WEBHOOK_URL != '' }}
28+
uses: actions/github-script@v7
29+
with:
30+
script: |
31+
const fs = require('fs');
32+
const { owner, repo } = context.repo;
33+
const run = context.payload.workflow_run;
34+
const runId = run.id;
35+
const sha = run.head_sha;
36+
37+
// 1) First line of commit message
38+
let commitMsg = "";
39+
try {
40+
const { data: c } = await github.rest.repos.getCommit({ owner, repo, ref: sha });
41+
commitMsg = (c.commit?.message?.split('\n')[0] ?? "").trim();
42+
} catch {}
43+
44+
// 2) First failing job/step
45+
let failedJob = "", failedStep = "";
46+
try {
47+
const { data } = await github.rest.actions.listJobsForWorkflowRun({
48+
owner, repo, run_id: runId, per_page: 100
49+
});
50+
const job = (data.jobs || []).find(j => j.conclusion && j.conclusion !== 'success');
51+
if (job) {
52+
failedJob = job.name || "";
53+
const step = (job.steps || []).find(s => s.conclusion === 'failure')
54+
|| (job.steps || []).find(s => s.conclusion && s.conclusion !== 'success');
55+
if (step) failedStep = step.name || "";
56+
}
57+
} catch {}
58+
59+
const embed = {
60+
title: `🚨 FAILED: ${run.name}`,
61+
url: `https://github.com/${owner}/${repo}/actions/runs/${runId}`,
62+
color: 15158332,
63+
description: commitMsg ? `**Commit:** ${commitMsg}` : undefined,
64+
fields: [
65+
{ name: "Repository", value: `${owner}/${repo}`, inline: true },
66+
{ name: "Branch", value: run.head_branch || "-", inline: true },
67+
{ name: "Actor", value: run.actor?.login || "-", inline: true },
68+
{ name: "Commit", value: `\`${sha.substring(0,7)}\``, inline: true },
69+
].concat(
70+
(failedJob || failedStep)
71+
? [{ name: "Cause", value: `${failedJob}${failedJob && failedStep ? " → " : ""}${failedStep}`.trim(), inline: false }]
72+
: []
73+
),
74+
timestamp: new Date().toISOString()
75+
};
76+
77+
const payload = { embeds: [embed] };
78+
fs.writeFileSync('discord_payload.json', JSON.stringify(payload));
79+
core.setOutput('payload_file', 'discord_payload.json');
80+
81+
- name: Send to Discord
82+
if: ${{ env.WEBHOOK_URL != '' }}
83+
continue-on-error: true
84+
run: |
85+
curl -sS -H "Content-Type: application/json" \
86+
-d @${{ steps.prep.outputs.payload_file }} \
87+
"$WEBHOOK_URL" || echo "warn: discord notify failed"

.github/workflows/build.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: "Build & Test"
2+
3+
on:
4+
push:
5+
branches: [ "**" ]
6+
pull_request:
7+
branches: [ "**" ]
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: ci-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
test:
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Setup .NET
25+
uses: actions/setup-dotnet@v4
26+
with:
27+
dotnet-version: "10.0.x"
28+
29+
- name: Cache NuGet packages
30+
uses: actions/cache@v4
31+
with:
32+
path: ~/.nuget/packages
33+
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
34+
restore-keys: |
35+
${{ runner.os }}-nuget-
36+
37+
- name: Restore
38+
run: dotnet restore
39+
40+
- name: Build (Release)
41+
run: dotnet build --configuration Release --no-restore
42+
43+
- name: Test (with TRX + coverage)
44+
run: |
45+
dotnet test --configuration Release --no-build \
46+
--logger "trx;LogFileName=test_results.trx" \
47+
--collect "XPlat Code Coverage"
48+
49+
- name: Upload test results (TRX)
50+
if: always()
51+
uses: actions/upload-artifact@v4
52+
with:
53+
name: test-results
54+
path: |
55+
**/TestResults/*.trx
56+
**/TestResults/**/coverage.cobertura.xml
57+
if-no-files-found: ignore

DiscordArchitect.Tests/DiscordArchitect.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
</PropertyGroup>
1919

2020
<ItemGroup>
21+
<PackageReference Include="coverlet.collector" Version="6.0.4">
22+
<PrivateAssets>all</PrivateAssets>
23+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
24+
</PackageReference>
2125
<PackageReference Include="FluentAssertions" Version="8.7.0" />
2226
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
2327
<PackageReference Include="Moq" Version="4.20.72" />

DiscordArchitect.slnx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
<File Path=".gitignore" />
44
<File Path="README.md" />
55
</Folder>
6+
<Folder Name="/Solution Items/.github/" />
7+
<Folder Name="/Solution Items/.github/workflows/">
8+
<File Path="alerts.yml" />
9+
<File Path="build.yml" />
10+
</Folder>
611
<Project Path="DiscordArchitect.Tests/DiscordArchitect.Tests.csproj" Id="02f5acc5-9f9f-46bb-bbb7-b5bea6d061cd" />
712
<Project Path="DiscordArchitect/DiscordArchitect.csproj" />
813
</Solution>

0 commit comments

Comments
 (0)