Skip to content

Commit 29f6678

Browse files
committed
fix: maybe fix CI?
1 parent aff20bc commit 29f6678

3 files changed

Lines changed: 249 additions & 4 deletions

File tree

.github/workflows/release.yml

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,29 @@ jobs:
7070
- name: Install ReportGenerator
7171
run: dotnet tool install --global dotnet-reportgenerator-globaltool
7272

73+
- name: Compute affected projects
74+
id: affected
75+
run: |
76+
NX_BASE=$(git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)
77+
echo "nx-base=${NX_BASE}" >> $GITHUB_OUTPUT
78+
AFFECTED=$(pnpm nx show projects --affected --base="${NX_BASE}" --json 2>/dev/null \
79+
| node -e "process.stdout.write(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).join(' '))")
80+
echo "NX_AFFECTED_PROJECTS=${AFFECTED}" >> $GITHUB_ENV
81+
# Write JSON for debugging artifact
82+
pnpm nx show projects --affected --base="${NX_BASE}" --json 2>/dev/null > dist/nx-affected.json || true
83+
# Print to step summary for visibility
84+
echo "## Affected Projects (base: \`${NX_BASE}\`)" >> $GITHUB_STEP_SUMMARY
85+
echo '```' >> $GITHUB_STEP_SUMMARY
86+
echo "${AFFECTED}" | tr ' ' '\n' >> $GITHUB_STEP_SUMMARY
87+
echo '```' >> $GITHUB_STEP_SUMMARY
88+
7389
- name: Run tests and generate coverage badges
7490
env:
7591
REPORTGENERATOR_LICENSE: ${{ secrets.REPORTGENERATOR_LICENSE }}
7692
CI: "true"
7793
run: |
78-
# Run tests for everything changed since the last release tag.
79-
# Falls back to the first commit if no tags exist yet.
80-
NX_BASE=$(git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)
81-
pnpm nx affected -t test --base="${NX_BASE}" --head=HEAD \
94+
pnpm nx affected -t test \
95+
--base="${{ steps.affected.outputs.nx-base }}" --head=HEAD \
8296
--output-style=stream \
8397
--collect:"XPlat Code Coverage" \
8498
--settings coverlet.runsettings \
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "test/examples",
3+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
4+
"projectType": "application",
5+
"sourceRoot": "tests/Flowthru.Tests.Examples",
6+
"tags": [ "type:test", "scope:examples" ],
7+
"targets": {
8+
"test": {
9+
"//": "Runs only affected example projects via scripts/run-tests.sh. Extra args (coverage flags etc.) are forwarded from the nx affected -t test invocation.",
10+
"executor": "nx:run-commands",
11+
"dependsOn": ["build"],
12+
"options": {
13+
"commands": ["bash scripts/run-tests.sh"],
14+
"cwd": "tests/Flowthru.Tests.Examples",
15+
"parallel": false,
16+
"forwardAllArgs": true
17+
},
18+
"cache": true,
19+
"inputs": ["default", "^production"]
20+
},
21+
"test:discovery": {
22+
"//": "Run only test discovery tests (smoke check for example project wiring)",
23+
"executor": "nx:run-commands",
24+
"options": {
25+
"commands": [ "dotnet test --filter \"FullyQualifiedName~Discovery\" --logger \"console;verbosity=normal\"" ],
26+
"cwd": "tests/Flowthru.Tests.Examples",
27+
"parallel": false
28+
}
29+
},
30+
"format": {
31+
"executor": "nx:run-commands",
32+
"options": {
33+
"command": "dotnet csharpier {projectRoot}",
34+
"cwd": "{workspaceRoot}"
35+
}
36+
},
37+
"format:check": {
38+
"executor": "nx:run-commands",
39+
"options": {
40+
"command": "dotnet csharpier {projectRoot} --check",
41+
"cwd": "{workspaceRoot}"
42+
}
43+
}
44+
}
45+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#!/usr/bin/env bash
2+
# Runs Flowthru.Tests.Examples with a NUnit filter scoped to affected examples.
3+
#
4+
# In CI, NX_AFFECTED_PROJECTS is exported by the "Compute affected projects" step
5+
# before `nx affected -t test` runs. Locally, the script computes it fresh from
6+
# the last git tag.
7+
#
8+
# Logic:
9+
# 1. Intersect affected projects with known example project names.
10+
# 2. If intersection is empty → skip (exit 0).
11+
# 3. Otherwise → run dotnet test filtered to those examples + Category=FUnit.
12+
#
13+
# All extra args ($@) are forwarded to `dotnet test` (coverage flags, loggers, etc.)
14+
set -euo pipefail
15+
16+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17+
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
18+
WORKSPACE_ROOT="$(cd "$PROJECT_DIR/../.." && pwd)"
19+
EXAMPLES_DIR="$WORKSPACE_ROOT/examples"
20+
21+
EXTRA_ARGS=("$@")
22+
23+
echo "=== Example Test Runner ==="
24+
echo "Project: $PROJECT_DIR"
25+
echo "Workspace root: $WORKSPACE_ROOT"
26+
27+
# ── 1. Get affected project list ──────────────────────────────────────────────
28+
29+
if [[ -n "${NX_AFFECTED_PROJECTS:-}" ]]; then
30+
echo "Source: NX_AFFECTED_PROJECTS env var (CI)"
31+
read -ra AFFECTED <<< "$NX_AFFECTED_PROJECTS"
32+
else
33+
echo "Source: computing from last git tag (local)"
34+
NX_BASE=$(cd "$WORKSPACE_ROOT" && \
35+
git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)
36+
echo "Base: $NX_BASE"
37+
AFFECTED_JSON=$(cd "$WORKSPACE_ROOT" && \
38+
pnpm nx show projects --affected --base="$NX_BASE" --json 2>/dev/null)
39+
read -ra AFFECTED <<< "$(node -e \
40+
"process.stdout.write(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).join(' '))" \
41+
<<< "$AFFECTED_JSON")"
42+
fi
43+
44+
echo "Affected (${#AFFECTED[@]}): ${AFFECTED[*]:-none}"
45+
46+
# ── 2. Discover example project names from disk ────────────────────────────────
47+
48+
declare -A EXAMPLE_SET
49+
while IFS= read -r csproj; do
50+
name="$(basename "$(dirname "$csproj")")"
51+
EXAMPLE_SET["$name"]=1
52+
done < <(find "$EXAMPLES_DIR" -name "*.csproj" \
53+
-not -path "*/archived/*" \
54+
-not -path "*/obj/*" \
55+
-not -path "*/bin/*")
56+
57+
echo "Discovered ${#EXAMPLE_SET[@]} example projects"
58+
59+
# ── 3. Intersect affected with examples ───────────────────────────────────────
60+
61+
AFFECTED_EXAMPLES=()
62+
for proj in "${AFFECTED[@]}"; do
63+
if [[ -n "${EXAMPLE_SET[$proj]:-}" ]]; then
64+
AFFECTED_EXAMPLES+=("$proj")
65+
fi
66+
done
67+
68+
echo "Affected examples (${#AFFECTED_EXAMPLES[@]}): ${AFFECTED_EXAMPLES[*]:-none}"
69+
70+
if [[ ${#AFFECTED_EXAMPLES[@]} -eq 0 ]]; then
71+
echo "No example projects affected — skipping example integration tests."
72+
exit 0
73+
fi
74+
75+
# ── 4. Run dotnet test filtered to affected examples ──────────────────────────
76+
# FUnit auto-discovery tests (Category=FUnit) are always included — they are
77+
# fast and verify source generator output independently of which examples changed.
78+
79+
FILTER_PARTS=("Category=FUnit")
80+
for example in "${AFFECTED_EXAMPLES[@]}"; do
81+
FILTER_PARTS+=("FullyQualifiedName~${example}")
82+
done
83+
84+
FILTER=$(IFS='|'; echo "${FILTER_PARTS[*]}")
85+
echo "NUnit filter: $FILTER"
86+
87+
dotnet test "$PROJECT_DIR" --no-build --no-restore --filter "$FILTER" "${EXTRA_ARGS[@]}"
88+
89+
90+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
91+
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
92+
WORKSPACE_ROOT="$(cd "$PROJECT_DIR/../.." && pwd)"
93+
EXAMPLES_DIR="$WORKSPACE_ROOT/examples"
94+
95+
EXTRA_ARGS=("$@")
96+
97+
echo "=== Example Test Runner ==="
98+
echo "Project: $PROJECT_DIR"
99+
echo "Workspace root: $WORKSPACE_ROOT"
100+
101+
# ── 1. Get affected project list ──────────────────────────────────────────────
102+
103+
if [[ -n "${NX_AFFECTED_PROJECTS:-}" ]]; then
104+
echo "Source: NX_AFFECTED_PROJECTS env var (CI)"
105+
read -ra AFFECTED <<< "$NX_AFFECTED_PROJECTS"
106+
else
107+
echo "Source: computing from last git tag (local)"
108+
NX_BASE=$(cd "$WORKSPACE_ROOT" && \
109+
git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)
110+
echo "Base: $NX_BASE"
111+
AFFECTED_JSON=$(cd "$WORKSPACE_ROOT" && \
112+
pnpm nx show projects --affected --base="$NX_BASE" --json 2>/dev/null)
113+
read -ra AFFECTED <<< "$(node -e \
114+
"process.stdout.write(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).join(' '))" \
115+
<<< "$AFFECTED_JSON")"
116+
fi
117+
118+
echo "Affected (${#AFFECTED[@]}): ${AFFECTED[*]:-none}"
119+
120+
# ── 2. Discover example project names from disk ────────────────────────────────
121+
122+
declare -A EXAMPLE_SET
123+
while IFS= read -r csproj; do
124+
name="$(basename "$(dirname "$csproj")")"
125+
EXAMPLE_SET["$name"]=1
126+
done < <(find "$EXAMPLES_DIR" -name "*.csproj" \
127+
-not -path "*/archived/*" \
128+
-not -path "*/obj/*" \
129+
-not -path "*/bin/*")
130+
131+
echo "Discovered ${#EXAMPLE_SET[@]} example projects"
132+
133+
# ── 3. Determine if any framework (src/) library is affected ──────────────────
134+
# A project is a "framework library" if its root directory is under src/.
135+
# This check is structural — no manual exclusion list to maintain.
136+
137+
FRAMEWORK_AFFECTED=false
138+
for proj in "${AFFECTED[@]}"; do
139+
# Skip known example and test projects
140+
[[ -n "${EXAMPLE_SET[$proj]:-}" ]] && continue
141+
# Ask NX for the project root
142+
PROJ_ROOT=$(cd "$WORKSPACE_ROOT" && \
143+
pnpm nx show project "$proj" --json 2>/dev/null | \
144+
node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));process.stdout.write(d.root||'')}catch{}" 2>/dev/null || true)
145+
if [[ "$PROJ_ROOT" == src/* ]]; then
146+
FRAMEWORK_AFFECTED=true
147+
echo "Framework project affected: $proj ($PROJ_ROOT) → running all examples"
148+
break
149+
fi
150+
done
151+
152+
# ── 4. Run tests ───────────────────────────────────────────────────────────────
153+
154+
if [[ "$FRAMEWORK_AFFECTED" == "true" ]]; then
155+
echo "Running all example integration tests."
156+
dotnet test "$PROJECT_DIR" --no-build --no-restore "${EXTRA_ARGS[@]}"
157+
exit $?
158+
fi
159+
160+
# Intersect affected with known example names
161+
AFFECTED_EXAMPLES=()
162+
for proj in "${AFFECTED[@]}"; do
163+
if [[ -n "${EXAMPLE_SET[$proj]:-}" ]]; then
164+
AFFECTED_EXAMPLES+=("$proj")
165+
fi
166+
done
167+
168+
echo "Affected examples (${#AFFECTED_EXAMPLES[@]}): ${AFFECTED_EXAMPLES[*]:-none}"
169+
170+
if [[ ${#AFFECTED_EXAMPLES[@]} -eq 0 ]]; then
171+
echo "No example projects affected — skipping example integration tests."
172+
exit 0
173+
fi
174+
175+
# FUnit discovery tests are always included (fast, assertion-only).
176+
# Integration tests scoped to affected examples via FullyQualifiedName.
177+
FILTER_PARTS=("Category=FUnit")
178+
for example in "${AFFECTED_EXAMPLES[@]}"; do
179+
FILTER_PARTS+=("FullyQualifiedName~${example}")
180+
done
181+
182+
# NUnit OR operator is |
183+
FILTER=$(IFS='|'; echo "${FILTER_PARTS[*]}")
184+
echo "NUnit filter: $FILTER"
185+
186+
dotnet test "$PROJECT_DIR" --no-build --no-restore --filter "$FILTER" "${EXTRA_ARGS[@]}"

0 commit comments

Comments
 (0)