66 paths :
77 - ' packages/**'
88 - ' tests/**'
9- - ' .github/workflows/ci.yml'
9+ - ' .github/**'
10+ - ' .xlings.json'
1011 pull_request :
1112 branches : [main]
1213 paths :
1314 - ' packages/**'
1415 - ' tests/**'
15- - ' .github/workflows/ci.yml'
16+ - ' .github/**'
17+ - ' .xlings.json'
1618
1719env :
1820 XLINGS_NON_INTERACTIVE : 1
@@ -21,46 +23,56 @@ jobs:
2123 detect-changes :
2224 runs-on : ubuntu-24.04
2325 outputs :
24- templates : ${{ steps.filter.outputs.templates }}
25- cmdline : ${{ steps.filter.outputs.cmdline }}
26- llmapi : ${{ steps.filter.outputs.llmapi }}
27- lua : ${{ steps.filter.outputs.lua }}
28- xpkg : ${{ steps.filter.outputs.xpkg }}
26+ packages : ${{ steps.detect.outputs.packages }}
27+ build_all : ${{ steps.detect.outputs.build_all }}
2928 steps :
3029 - uses : actions/checkout@v4
31- - uses : dorny/paths-filter@v3
32- id : filter
3330 with :
34- filters : |
35- templates:
36- - 'packages/t/templates/**'
37- - 'tests/t/templates/**'
38- - '.github/workflows/ci.yml'
39- cmdline:
40- - 'packages/c/cmdline/**'
41- - 'tests/c/cmdline/**'
42- - '.github/workflows/ci.yml'
43- llmapi:
44- - 'packages/l/llmapi/**'
45- - 'tests/l/llmapi/**'
46- - '.github/workflows/ci.yml'
47- lua:
48- - 'packages/m/mcpplibs-capi-lua/**'
49- - 'tests/l/lua/**'
50- - '.github/workflows/ci.yml'
51- xpkg:
52- - 'packages/m/mcpplibs-xpkg/**'
53- - 'tests/m/mcpplibs-xpkg/**'
54- - '.github/workflows/ci.yml'
31+ fetch-depth : 0
32+
33+ - name : Detect changed packages
34+ id : detect
35+ run : |
36+ # Determine the base ref for comparison
37+ if [ "${{ github.event_name }}" = "pull_request" ]; then
38+ BASE="${{ github.event.pull_request.base.sha }}"
39+ else
40+ BASE="${{ github.event.before }}"
41+ fi
42+
43+ # Check if CI config itself changed — if so, build all
44+ CI_CHANGED=$(git diff --name-only "$BASE" HEAD -- .github/ .xlings.json || true)
45+ if [ -n "$CI_CHANGED" ]; then
46+ echo "build_all=true" >> "$GITHUB_OUTPUT"
47+ echo "CI config changed, will build all packages"
48+ else
49+ echo "build_all=false" >> "$GITHUB_OUTPUT"
50+ fi
51+
52+ # Collect changed package names from packages/ and tests/ directories
53+ CHANGED_DIRS=$(git diff --name-only "$BASE" HEAD -- packages/ tests/ | \
54+ sed -n 's|^packages/./\([^/]*\)/.*|\1|p; s|^tests/./\([^/]*\)/.*|\1|p' | \
55+ sort -u)
56+
57+ # Build JSON array of changed packages
58+ JSON="["
59+ FIRST=true
60+ for pkg in $CHANGED_DIRS; do
61+ if [ "$FIRST" = true ]; then
62+ FIRST=false
63+ else
64+ JSON="$JSON,"
65+ fi
66+ JSON="$JSON\"$pkg\""
67+ done
68+ JSON="$JSON]"
69+
70+ echo "packages=$JSON" >> "$GITHUB_OUTPUT"
71+ echo "Changed packages: $JSON"
5572
5673 build :
5774 needs : detect-changes
58- if : >-
59- needs.detect-changes.outputs.templates == 'true' ||
60- needs.detect-changes.outputs.cmdline == 'true' ||
61- needs.detect-changes.outputs.llmapi == 'true' ||
62- needs.detect-changes.outputs.lua == 'true' ||
63- needs.detect-changes.outputs.xpkg == 'true'
75+ if : needs.detect-changes.outputs.build_all == 'true' || needs.detect-changes.outputs.packages != '[]'
6476 strategy :
6577 fail-fast : false
6678 matrix :
@@ -78,97 +90,116 @@ jobs:
7890 if : runner.os == 'Linux'
7991 working-directory : tests
8092 run : |
81- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
93+ export PATH="$HOME/.xlings/bin:$HOME/.xlings/ subos/current/bin:$PATH"
8294 xmake f -P . -y
8395
8496 - name : Configure (macos)
8597 if : runner.os == 'macOS'
8698 working-directory : tests
8799 run : |
88- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
100+ export PATH="$HOME/.xlings/bin:$HOME/.xlings/ subos/current/bin:$PATH"
89101 xmake f -P . -y --toolchain=llvm
90102
91103 - name : Configure (windows)
92104 if : runner.os == 'Windows'
93105 working-directory : tests
94106 run : |
95- $env:PATH = "$env:USERPROFILE\.xlings\subos\current\bin;$env:PATH"
107+ $env:PATH = "$env:USERPROFILE\.xlings\bin;$env:USERPROFILE\.xlings\ subos\current\bin;$env:PATH"
96108 xmake f -P . -y
97109
98- # templates
99- - name : templates (unix)
100- if : runner.os != 'Windows' && needs.detect-changes.outputs.templates == 'true'
101- working-directory : tests
102- run : |
103- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
104- xmake build -P . -y templates_test
105- xmake run -P . templates_test
106- - name : templates (windows)
107- if : runner.os == 'Windows' && needs.detect-changes.outputs.templates == 'true'
110+ - name : Build and test (unix)
111+ if : runner.os != 'Windows'
108112 working-directory : tests
113+ env :
114+ BUILD_ALL : ${{ needs.detect-changes.outputs.build_all }}
115+ CHANGED_PACKAGES : ${{ needs.detect-changes.outputs.packages }}
109116 run : |
110- $env:PATH = "$env:USERPROFILE\.xlings\subos\current\bin;$env:PATH"
111- xmake build -P . -y templates_test
112- xmake run -P . templates_test
117+ export PATH="$HOME/.xlings/bin:$HOME/.xlings/subos/current/bin:$PATH"
113118
114- # cmdline
115- - name : cmdline (unix)
116- if : runner.os != 'Windows' && needs.detect-changes.outputs.cmdline == 'true'
117- working-directory : tests
118- run : |
119- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
120- xmake build -P . -y cmdline_test
121- xmake run -P . cmdline_test test_input
122- - name : cmdline (windows)
123- if : runner.os == 'Windows' && needs.detect-changes.outputs.cmdline == 'true'
124- working-directory : tests
125- run : |
126- $env:PATH = "$env:USERPROFILE\.xlings\subos\current\bin;$env:PATH"
127- xmake build -P . -y cmdline_test
128- xmake run -P . cmdline_test test_input
119+ # Collect test targets to build
120+ TARGETS=""
121+ if [ "$BUILD_ALL" = "true" ]; then
122+ # Find all test targets from test xmake.lua files
123+ TARGETS=$(grep -r 'target("' */*/xmake.lua 2>/dev/null | sed 's/.*target("\([^"]*\)").*/\1/' | sort -u)
124+ echo "Building ALL targets: $TARGETS"
125+ else
126+ # Build only changed packages
127+ for pkg in $(echo "$CHANGED_PACKAGES" | tr -d '[]"' | tr ',' ' '); do
128+ TARGET="${pkg}_test"
129+ # Verify the target exists
130+ if grep -rq "target(\"$TARGET\")" */*/xmake.lua 2>/dev/null; then
131+ TARGETS="$TARGETS $TARGET"
132+ else
133+ echo "Warning: no test target '$TARGET' found for package '$pkg', skipping"
134+ fi
135+ done
136+ echo "Building changed targets: $TARGETS"
137+ fi
129138
130- # llmapi (build only, needs API key to run)
131- - name : llmapi (unix)
132- if : runner.os != 'Windows' && needs.detect-changes.outputs.llmapi == 'true'
133- working-directory : tests
134- run : |
135- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
136- xmake build -P . -y llmapi_test
137- - name : llmapi (windows)
138- if : runner.os == 'Windows' && needs.detect-changes.outputs.llmapi == 'true'
139- working-directory : tests
140- run : |
141- $env:PATH = "$env:USERPROFILE\.xlings\subos\current\bin;$env:PATH"
142- xmake build -P . -y llmapi_test
139+ # Build and run each target
140+ for target in $TARGETS; do
141+ echo "=== Building $target ==="
142+ xmake build -P . -y "$target"
143143
144- # lua
145- - name : lua (unix)
146- if : runner.os != 'Windows' && needs.detect-changes.outputs.lua == 'true'
147- working-directory : tests
148- run : |
149- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
150- xmake build -P . -y lua_test
151- xmake run -P . lua_test
152- - name : lua (windows)
153- if : runner.os == 'Windows' && needs.detect-changes.outputs.lua == 'true'
154- working-directory : tests
155- run : |
156- $env:PATH = "$env:USERPROFILE\.xlings\subos\current\bin;$env:PATH"
157- xmake build -P . -y lua_test
158- xmake run -P . lua_test
144+ # llmapi requires API key, only build don't run
145+ if [ "$target" = "llmapi_test" ]; then
146+ echo "Skipping run for $target (requires API key)"
147+ continue
148+ fi
159149
160- # mcpplibs-xpkg
161- - name : mcpplibs-xpkg (unix)
162- if : runner.os != 'Windows' && needs.detect-changes.outputs.xpkg == 'true'
163- working-directory : tests
164- run : |
165- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
166- xmake build -P . -y mcpplibs-xpkg_test
167- xmake run -P . mcpplibs-xpkg_test
168- - name : mcpplibs-xpkg (windows)
169- if : runner.os == 'Windows' && needs.detect-changes.outputs.xpkg == 'true'
150+ echo "=== Running $target ==="
151+ if [ "$target" = "cmdline_test" ]; then
152+ xmake run -P . "$target" test_input
153+ else
154+ xmake run -P . "$target"
155+ fi
156+ done
157+
158+ - name : Build and test (windows)
159+ if : runner.os == 'Windows'
170160 working-directory : tests
161+ env :
162+ BUILD_ALL : ${{ needs.detect-changes.outputs.build_all }}
163+ CHANGED_PACKAGES : ${{ needs.detect-changes.outputs.packages }}
171164 run : |
172- $env:PATH = "$env:USERPROFILE\.xlings\subos\current\bin;$env:PATH"
173- xmake build -P . -y mcpplibs-xpkg_test
174- xmake run -P . mcpplibs-xpkg_test
165+ $env:PATH = "$env:USERPROFILE\.xlings\bin;$env:USERPROFILE\.xlings\subos\current\bin;$env:PATH"
166+
167+ # Collect test targets
168+ $targets = @()
169+ if ($env:BUILD_ALL -eq "true") {
170+ $targets = Get-ChildItem -Recurse -Filter "xmake.lua" -Path "*/*" |
171+ Select-String 'target\("([^"]+)"\)' |
172+ ForEach-Object { $_.Matches[0].Groups[1].Value } |
173+ Sort-Object -Unique
174+ Write-Host "Building ALL targets: $($targets -join ', ')"
175+ } else {
176+ $packages = $env:CHANGED_PACKAGES | ConvertFrom-Json
177+ foreach ($pkg in $packages) {
178+ $target = "${pkg}_test"
179+ $found = Get-ChildItem -Recurse -Filter "xmake.lua" -Path "*/*" |
180+ Select-String "target\(`"$target`"\)" -Quiet
181+ if ($found) {
182+ $targets += $target
183+ } else {
184+ Write-Host "Warning: no test target '$target' found for package '$pkg', skipping"
185+ }
186+ }
187+ Write-Host "Building changed targets: $($targets -join ', ')"
188+ }
189+
190+ foreach ($target in $targets) {
191+ Write-Host "=== Building $target ==="
192+ xmake build -P . -y $target
193+
194+ if ($target -eq "llmapi_test") {
195+ Write-Host "Skipping run for $target (requires API key)"
196+ continue
197+ }
198+
199+ Write-Host "=== Running $target ==="
200+ if ($target -eq "cmdline_test") {
201+ xmake run -P . $target test_input
202+ } else {
203+ xmake run -P . $target
204+ }
205+ }
0 commit comments