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,48 @@ 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+ if [ "${{ github.event_name }}" = "pull_request" ]; then
37+ BASE="${{ github.event.pull_request.base.sha }}"
38+ else
39+ BASE="${{ github.event.before }}"
40+ fi
41+
42+ CI_CHANGED=$(git diff --name-only "$BASE" HEAD -- .github/ .xlings.json || true)
43+ if [ -n "$CI_CHANGED" ]; then
44+ echo "build_all=true" >> "$GITHUB_OUTPUT"
45+ echo "CI config changed, will build all packages"
46+ else
47+ echo "build_all=false" >> "$GITHUB_OUTPUT"
48+ fi
49+
50+ CHANGED_DIRS=$(git diff --name-only "$BASE" HEAD -- packages/ tests/ | \
51+ sed -n 's|^packages/./\([^/]*\)/.*|\1|p; s|^tests/./\([^/]*\)/.*|\1|p' | \
52+ sort -u)
53+
54+ JSON="["
55+ FIRST=true
56+ for pkg in $CHANGED_DIRS; do
57+ if [ "$FIRST" = true ]; then FIRST=false; else JSON="$JSON,"; fi
58+ JSON="$JSON\"$pkg\""
59+ done
60+ JSON="$JSON]"
61+
62+ echo "packages=$JSON" >> "$GITHUB_OUTPUT"
63+ echo "Changed packages: $JSON"
5564
5665 build :
5766 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'
67+ if : needs.detect-changes.outputs.build_all == 'true' || needs.detect-changes.outputs.packages != '[]'
6468 strategy :
6569 fail-fast : false
6670 matrix :
@@ -77,98 +81,121 @@ jobs:
7781 - name : Configure (linux)
7882 if : runner.os == 'Linux'
7983 working-directory : tests
80- run : |
81- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
82- xmake f -P . -y
84+ run : xmake f -P . -y -vv
8385
8486 - name : Configure (macos)
8587 if : runner.os == 'macOS'
8688 working-directory : tests
87- run : |
88- export PATH="$HOME/.xlings/subos/current/bin:$PATH"
89- xmake f -P . -y --toolchain=llvm
89+ run : xmake f -P . -y -vv --toolchain=llvm
9090
9191 - name : Configure (windows)
9292 if : runner.os == 'Windows'
9393 working-directory : tests
94- run : |
95- $env:PATH = "$env:USERPROFILE\.xlings\subos\current\bin;$env:PATH"
96- xmake f -P . -y
94+ run : xmake f -P . -y -vv
9795
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'
96+ - name : Build and test (unix)
97+ if : runner.os != 'Windows'
10898 working-directory : tests
99+ env :
100+ BUILD_ALL : ${{ needs.detect-changes.outputs.build_all }}
101+ CHANGED_PACKAGES : ${{ needs.detect-changes.outputs.packages }}
109102 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
103+ TARGETS=""
104+ if [ "$BUILD_ALL" = "true" ]; then
105+ TARGETS=$(grep -r 'target("' */*/xmake.lua 2>/dev/null | sed 's/.*target("\([^"]*\)").*/\1/' | sort -u)
106+ echo "Building ALL targets: $TARGETS"
107+ else
108+ for pkg in $(echo "$CHANGED_PACKAGES" | tr -d '[]"' | tr ',' ' '); do
109+ TARGET="${pkg}_test"
110+ if grep -rq "target(\"$TARGET\")" */*/xmake.lua 2>/dev/null; then
111+ TARGETS="$TARGETS $TARGET"
112+ else
113+ echo "Warning: no test target '$TARGET' found for package '$pkg', skipping"
114+ fi
115+ done
116+ echo "Building changed targets: $TARGETS"
117+ fi
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+ FAILED=""
120+ for target in $TARGETS; do
121+ echo "=== Building $target ==="
122+ if ! xmake build -P . -y "$target"; then
123+ echo "FAILED to build $target"
124+ FAILED="$FAILED $target"
125+ continue
126+ fi
129127
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
128+ if [ "$target" = "llmapi_test" ]; then
129+ echo "Skipping run for $target (requires API key)"
130+ continue
131+ fi
143132
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
133+ echo "=== Running $target ==="
134+ if [ "$target" = "cmdline_test" ]; then
135+ xmake run -P . "$target" test_input
136+ else
137+ xmake run -P . "$target"
138+ fi
139+ done
159140
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'
141+ if [ -n "$FAILED" ]; then
142+ echo "::error::Failed targets:$FAILED"
143+ exit 1
144+ fi
145+
146+ - name : Build and test (windows)
147+ if : runner.os == 'Windows'
170148 working-directory : tests
149+ env :
150+ BUILD_ALL : ${{ needs.detect-changes.outputs.build_all }}
151+ CHANGED_PACKAGES : ${{ needs.detect-changes.outputs.packages }}
171152 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
153+ $targets = @()
154+ if ($env:BUILD_ALL -eq "true") {
155+ $targets = Get-ChildItem -Recurse -Filter "xmake.lua" -Path "*/*" |
156+ Select-String 'target\("([^"]+)"\)' |
157+ ForEach-Object { $_.Matches[0].Groups[1].Value } |
158+ Sort-Object -Unique
159+ Write-Host "Building ALL targets: $($targets -join ', ')"
160+ } else {
161+ $packages = $env:CHANGED_PACKAGES | ConvertFrom-Json
162+ foreach ($pkg in $packages) {
163+ $target = "${pkg}_test"
164+ $found = Get-ChildItem -Recurse -Filter "xmake.lua" -Path "*/*" |
165+ Select-String "target\(`"$target`"\)" -Quiet
166+ if ($found) {
167+ $targets += $target
168+ } else {
169+ Write-Host "Warning: no test target '$target' found for package '$pkg', skipping"
170+ }
171+ }
172+ Write-Host "Building changed targets: $($targets -join ', ')"
173+ }
174+
175+ $failed = @()
176+ foreach ($target in $targets) {
177+ Write-Host "=== Building $target ==="
178+ xmake build -P . -y $target
179+ if ($LASTEXITCODE -ne 0) {
180+ Write-Host "FAILED to build $target"
181+ $failed += $target
182+ continue
183+ }
184+
185+ if ($target -eq "llmapi_test") {
186+ Write-Host "Skipping run for $target (requires API key)"
187+ continue
188+ }
189+
190+ Write-Host "=== Running $target ==="
191+ if ($target -eq "cmdline_test") {
192+ xmake run -P . $target test_input
193+ } else {
194+ xmake run -P . $target
195+ }
196+ }
197+
198+ if ($failed.Count -gt 0) {
199+ Write-Host "::error::Failed targets: $($failed -join ', ')"
200+ exit 1
201+ }
0 commit comments