This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new 75cbbd782 ci: refresh Swift xlang cache by toolchain (#3811)
75cbbd782 is described below
commit 75cbbd782286888c108c6ef25f4a29bb62970d15
Author: Shawn Yang <[email protected]>
AuthorDate: Thu Jul 2 20:33:15 2026 +0530
ci: refresh Swift xlang cache by toolchain (#3811)
## Why?
Swift xlang CI can restore an exact primary SwiftPM cache but still
rebuild SwiftSyntax and the release peer from scratch when the cached
build artifacts were produced with a different Swift/Xcode toolchain or
build shape. Because actions/cache does not save a replacement on a
primary-key hit, that stale cache can remain ineffective across runs
with no Swift source changes.
## What does this PR do?
- Adds a Swift/Xcode toolchain fingerprint step before the Swift package
cache restore.
- Includes the toolchain fingerprint and xlang release build shape in
the Swift cache key and restore prefix.
- Keeps the existing package/source hash so real Swift input changes
still get their own cache key.
## Verification
- Did not run local tests per request.
- Ran static whitespace check: `git diff --check`.
- Remote CI: https://github.com/apache/fory/actions/runs/28591161385
- Attempt 1 seeded Swift 6.1.2 / Xcode 16.4 cache: Swift prebuild 6m46s,
total Swift Xlang job 7m55s.
- Attempt 2 landed on Swift 6.3.2 / Xcode 26.5, missed by design due
different toolchain key, saved a second cache: prebuild 9m13s, total
10m57s.
- Attempt 3 landed on Swift 6.3.2 / Xcode 26.5 again and hit the new
key: restored 139,300,755 bytes, prebuild 1m51s, total 3m12s.
- PR checks are passing or skipped by path filters.
---
.github/workflows/ci.yml | 41 +++++++++++++++++++---
.../apache/fory/idl_tests/IdlRoundTripTest.java | 9 ++++-
.../java/org/apache/fory/xlang/SwiftXlangTest.java | 17 +++++++--
3 files changed, 60 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9f07a6b14..d98bddbc1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -460,20 +460,36 @@ jobs:
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
+ - name: Compute Swift package cache key
+ id: swift-package-cache
+ run: |
+ {
+ swift --version
+ xcodebuild -version
+ } > "$RUNNER_TEMP/swift-toolchain.txt"
+ cat "$RUNNER_TEMP/swift-toolchain.txt"
+ echo "toolchain=$(shasum -a 256 "$RUNNER_TEMP/swift-toolchain.txt" |
cut -d ' ' -f 1)" >> "$GITHUB_OUTPUT"
- name: Cache Swift package dependencies and build artifacts
+ id: swift-build-cache
uses: actions/cache@v4
with:
path: |
~/.swiftpm
~/Library/Caches/org.swift.swiftpm
swift/.build
- key: ${{ runner.os }}-${{ runner.arch }}-swiftpm-${{
hashFiles('swift/Package.resolved', 'swift/Package.swift', 'swift/Sources/**')
}}
+ key: ${{ runner.os }}-${{ runner.arch }}-swiftpm-xlang-release-${{
steps.swift-package-cache.outputs.toolchain }}-${{
hashFiles('swift/Package.resolved', 'swift/Package.swift', 'swift/Sources/**')
}}
restore-keys: |
- ${{ runner.os }}-${{ runner.arch }}-swiftpm-
+ ${{ runner.os }}-${{ runner.arch }}-swiftpm-xlang-release-${{
steps.swift-package-cache.outputs.toolchain }}-
- name: Prebuild Swift xlang peer for cache reuse
run: |
cd swift
+ if [[ "${{ steps.swift-build-cache.outputs.cache-hit }}" == "true"
&& -x .build/release/ForyXlangTests ]]; then
+ echo "Using cached Swift xlang peer at
swift/.build/release/ForyXlangTests"
+ echo "FORY_SWIFT_PEER_PREBUILT=1" >> "$GITHUB_ENV"
+ exit 0
+ fi
swift build -c release --disable-automatic-resolution --product
ForyXlangTests
+ echo "FORY_SWIFT_PEER_PREBUILT=1" >> "$GITHUB_ENV"
- name: Run Swift Xlang Test
env:
ENABLE_FORY_DEBUG_OUTPUT: "1"
@@ -507,19 +523,36 @@ jobs:
${{ runner.os }}-maven-
- name: Generate Swift IDL test code
run: python ./integration_tests/idl_tests/generate_idl.py --lang swift
+ - name: Compute Swift IDL package cache key
+ id: swift-idl-package-cache
+ run: |
+ {
+ swift --version
+ xcodebuild -version
+ } > "$RUNNER_TEMP/swift-toolchain.txt"
+ cat "$RUNNER_TEMP/swift-toolchain.txt"
+ echo "toolchain=$(shasum -a 256 "$RUNNER_TEMP/swift-toolchain.txt" |
cut -d ' ' -f 1)" >> "$GITHUB_OUTPUT"
- name: Cache Swift IDL package build artifacts
+ id: swift-idl-build-cache
uses: actions/cache@v4
with:
path: |
integration_tests/idl_tests/swift/idl_package/.build
integration_tests/idl_tests/swift/idl_package/.swiftpm
- key: ${{ runner.os }}-${{ runner.arch }}-swift-idl-package-${{
hashFiles('integration_tests/idl_tests/swift/idl_package/Package.swift',
'integration_tests/idl_tests/swift/idl_package/Package.resolved',
'swift/Package.swift', 'swift/Package.resolved', 'swift/Sources/ForyMacro/**')
}}
+ key: ${{ runner.os }}-${{ runner.arch }}-swiftpm-idl-debug-${{
steps.swift-idl-package-cache.outputs.toolchain }}-${{
hashFiles('integration_tests/idl_tests/swift/idl_package/Package.swift',
'integration_tests/idl_tests/swift/idl_package/Package.resolved',
'integration_tests/idl_tests/swift/idl_package/Sources/**',
'integration_tests/idl_tests/swift/idl_package/Tests/**',
'swift/Package.swift', 'swift/Package.resolved', 'swift/Sources/**') }}
restore-keys: |
- ${{ runner.os }}-${{ runner.arch }}-swift-idl-package-
+ ${{ runner.os }}-${{ runner.arch }}-swiftpm-idl-debug-${{
steps.swift-idl-package-cache.outputs.toolchain }}-
- name: Prebuild Swift IDL package
run: |
cd integration_tests/idl_tests/swift/idl_package
+ if [[ "${{ steps.swift-idl-build-cache.outputs.cache-hit }}" ==
"true" && -f .build/fory-swift-idl-prebuilt ]]; then
+ echo "Using cached Swift IDL package build artifacts"
+ echo "FORY_SWIFT_IDL_PREBUILT=1" >> "$GITHUB_ENV"
+ exit 0
+ fi
swift build --disable-automatic-resolution --build-tests
+ touch .build/fory-swift-idl-prebuilt
+ echo "FORY_SWIFT_IDL_PREBUILT=1" >> "$GITHUB_ENV"
- name: Run Swift IDL package tests
env:
ENABLE_FORY_DEBUG_OUTPUT: "1"
diff --git
a/integration_tests/idl_tests/java/src/test/java/org/apache/fory/idl_tests/IdlRoundTripTest.java
b/integration_tests/idl_tests/java/src/test/java/org/apache/fory/idl_tests/IdlRoundTripTest.java
index 8f3beb681..b6b9123f0 100644
---
a/integration_tests/idl_tests/java/src/test/java/org/apache/fory/idl_tests/IdlRoundTripTest.java
+++
b/integration_tests/idl_tests/java/src/test/java/org/apache/fory/idl_tests/IdlRoundTripTest.java
@@ -117,6 +117,7 @@ import tree.TreeForyModule;
import tree.TreeNode;
public class IdlRoundTripTest {
+ private static final String SWIFT_IDL_PREBUILT_ENV =
"FORY_SWIFT_IDL_PREBUILT";
@Test
public void testAddressBookRoundTripCompatible() throws Exception {
@@ -813,7 +814,13 @@ public class IdlRoundTripTest {
compatible
? "IdlRoundTripTests/testAddressBookRoundTripCompatible"
: "IdlRoundTripTests/testAddressBookRoundTripSchemaConsistent";
- command = Arrays.asList("swift", "test", "--filter", swiftTest);
+ command = new ArrayList<>(Arrays.asList("swift", "test"));
+ if ("1".equals(System.getenv(SWIFT_IDL_PREBUILT_ENV))) {
+ // CI cache keys include generated Swift IDL sources, package
inputs, and toolchain
+ // identity. Trust that explicit signal instead of letting SwiftPM
rebuild after checkout.
+ command.add("--skip-build");
+ }
+ command.addAll(Arrays.asList("--filter", swiftTest));
peerCommand.environment.put("ENABLE_FORY_DEBUG_OUTPUT", "1");
break;
case "javascript":
diff --git
a/java/fory-core/src/test/java/org/apache/fory/xlang/SwiftXlangTest.java
b/java/fory-core/src/test/java/org/apache/fory/xlang/SwiftXlangTest.java
index 15b1b9877..5f64af5a6 100644
--- a/java/fory-core/src/test/java/org/apache/fory/xlang/SwiftXlangTest.java
+++ b/java/fory-core/src/test/java/org/apache/fory/xlang/SwiftXlangTest.java
@@ -42,6 +42,7 @@ public class SwiftXlangTest extends XlangTestBase {
private static final Logger LOG =
LoggerFactory.getLogger(SwiftXlangTest.class);
private static final String SWIFT_EXECUTABLE = "swift";
private static final String SWIFT_PEER_TARGET = "ForyXlangTests";
+ private static final String SWIFT_PEER_PREBUILT_ENV =
"FORY_SWIFT_PEER_PREBUILT";
private static final File SWIFT_WORK_DIR = new File("../../swift");
private static final Path SWIFT_WORK_DIR_PATH = SWIFT_WORK_DIR.toPath();
private static final Path SWIFT_PEER_BINARY_PATH =
@@ -70,8 +71,16 @@ public class SwiftXlangTest extends XlangTestBase {
}
Assert.assertTrue(swiftInstalled, "swift is required for SwiftXlangTest");
+ if ("1".equals(System.getenv(SWIFT_PEER_PREBUILT_ENV))) {
+ // CI cache keys include Swift package inputs and toolchain identity.
Trust that explicit
+ // signal instead of file mtimes because restored cache entries can
predate checkout files.
+ usePeerBinary();
+ LOG.info("Completed ensurePeerReady for Swift xlang tests");
+ return;
+ }
+
if (isPeerBinaryUpToDate()) {
- swiftPeerBinaryPath = SWIFT_PEER_BINARY_PATH.toAbsolutePath().toString();
+ usePeerBinary();
LOG.info("Completed ensurePeerReady for Swift xlang tests");
return;
}
@@ -103,6 +112,11 @@ public class SwiftXlangTest extends XlangTestBase {
}
Assert.assertTrue(built, "failed to build Swift xlang peer target " +
SWIFT_PEER_TARGET);
+ usePeerBinary();
+ LOG.info("Completed ensurePeerReady for Swift xlang tests");
+ }
+
+ private void usePeerBinary() {
Path peerBinary = SWIFT_PEER_BINARY_PATH;
Assert.assertTrue(
Files.isRegularFile(peerBinary),
@@ -111,7 +125,6 @@ public class SwiftXlangTest extends XlangTestBase {
Files.isExecutable(peerBinary),
"Swift xlang peer binary is not executable: " +
peerBinary.toAbsolutePath());
swiftPeerBinaryPath = peerBinary.toAbsolutePath().toString();
- LOG.info("Completed ensurePeerReady for Swift xlang tests");
}
@Override
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]