Skip to content

Commit ec1bfb6

Browse files
authored
Add ci-at-desk, a script for locally running CI workflows (#24)
* Add ci-at-desk, a script for locally running CI workflows Add `crash` as an extraction keyword in run-test-helper.py Add `-ffile-prefix-map` argument to OpenUSD building (CI and documentation)
1 parent 263df8b commit ec1bfb6

44 files changed

Lines changed: 5368 additions & 130 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/scripts/build-openusd.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@
2626
from swiftusd_ci_common import *
2727

2828
def install_cmake():
29+
if which("cmake"):
30+
print("CMake is already on PATH, will not reinstall")
31+
return
32+
else:
33+
print(os.environ)
34+
print("Couldn't find CMake, will install")
35+
2936
print("Downloading CMake...")
3037
run(["curl", "-L", "https://github.com/Kitware/CMake/releases/download/v3.28.6/cmake-3.28.6-macos-universal.dmg",
3138
"--output", "CMake.dmg"],

.github/scripts/compute-openusd-build-cache-key.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@
3232
# Turn branch names like `dev` into a hash commit to avoid incorrect cache key matches
3333
clone_openusd()
3434
rev_parsed_ref = run(["git", "rev-parse", Environment.GitRef.openusd], cwd=Environment.Path.openusd, logOutput=False).output[0]
35-
build_flags = "".join(get_openusd_build_flags(Environment.TestCombination.target_platform))
35+
# Don't include the build directory when forming the cache key
36+
build_flags = get_openusd_build_flags(Environment.TestCombination.target_platform)
37+
build_flags = [x for x in build_flags if not x.startswith("/")]
38+
build_flags = "".join(build_flags)
3639

3740
result = " ".join([
3841
Environment.TestCombination.target_platform,
@@ -43,4 +46,7 @@
4346
openusd_patch_hash
4447
])
4548

46-
printAndWrite(output=f"cache-key='{result}'")
49+
# Cache keys cannot contain commas
50+
result = result.replace(",", "")
51+
52+
printAndWrite(output=f"cache-key={result}")

.github/scripts/define-test-matrix.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,44 @@
2323
import json
2424
import math
2525

26+
def get_xcodebuild_destination(target_platform):
27+
if target_platform == "macOS": return "platform=macOS,name=My Mac"
28+
elif target_platform == "iOS": return Environment.TestCombination.at_desk_iOS_xcodebuild_destination
29+
elif target_platform == "iOSSimulator": return "platform=iOS Simulator,name=iPhone 17 Pro"
30+
elif target_platform == "visionOS": return Environment.TestCombination.at_desk_visionOS_xcodebuild_destination
31+
elif target_platform == "visionOSSimulator": return "platform=visionOS Simulator,name=Apple Vision Pro (at 2732x2048)"
32+
else:
33+
print(f"Error: Unknown target '{target_platform}'")
34+
exit(1)
35+
2636
if __name__ == "__main__":
27-
target_platforms = ["macOS", "iOSSimulator", "visionOSSimulator"]
37+
target_platforms = ["macOS", "iOS", "iOSSimulator", "visionOS", "visionOSSimulator"]
2838
configs = ["Debug", "Release"]
2939
build_systems = ["xcodebuild-xcodeproj", "swiftbuild-SPM-Tests", "xcodebuild-SPM-Tests"]
3040

3141
all_combinations = []
3242
for target_platform in target_platforms:
3343
for config in configs:
3444
for build_system in build_systems:
35-
36-
# if target_platform == "macOS" and build_system == "xcodebuild-xcodeproj":
37-
# # Disabled for now
38-
# continue
39-
45+
exclusivity_keys = []
46+
4047
if build_system == "swiftbuild-SPM-Tests" and target_platform != "macOS":
4148
# swiftbuild only supports macOS
4249
continue
4350

44-
all_combinations.append({"target_platform" : target_platform, "config" : config, "build_system" : build_system})
51+
if build_system == "xcodebuild-SPM-Tests" and target_platform in ["iOS", "visionOS"]:
52+
# xcodebuild on a Swift Package doesn't support physical iOS/visionOS devices
53+
continue
54+
55+
xcodebuild_destination = get_xcodebuild_destination(target_platform)
56+
if xcodebuild_destination is None: continue
57+
58+
if target_platform in ["iOS", "visionOS"]:
59+
exclusivity_keys.append(target_platform)
60+
61+
all_combinations.append({"target_platform" : target_platform, "config" : config,
62+
"build_system" : build_system, "xcodebuild_destination" : xcodebuild_destination,
63+
"exclusivity_keys" : exclusivity_keys})
4564

4665
random.shuffle(all_combinations)
4766

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#===----------------------------------------------------------------------===#
2+
# This source file is part of github.com/apple/SwiftUsd
3+
#
4+
# Copyright © 2025 Apple Inc. and the SwiftUsd project authors.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# https://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
# SPDX-License-Identifier: Apache-2.0
19+
#===----------------------------------------------------------------------===#
20+
21+
from swiftusd_ci_common import *
22+
import argparse
23+
import re
24+
25+
def quiet_run(args):
26+
return run(args, cwd=Environment.Path.swiftusd, logOutput=False)
27+
28+
if __name__ == "__main__":
29+
parser = argparse.ArgumentParser()
30+
parser.add_argument("swiftusd_tag")
31+
args = parser.parse_args()
32+
33+
unstaged = quiet_run(["git", "status", "--porcelain=v1"]).output
34+
modified_files = []
35+
for l in unstaged:
36+
# porcelain format: <xy> <path> or <xy> <orig-path> -> <path>,
37+
# where xy is a two-character status code
38+
l = l[3:]
39+
if m := re.match("(.*)->(.*)", l):
40+
modified_files.append(m.group(1).strip())
41+
modified_files.append(m.group(2).strip())
42+
else:
43+
modified_files.append(l.strip())
44+
45+
modified_roots = set()
46+
for f in modified_files:
47+
if m := re.match("([^/]*)/.*", f):
48+
modified_roots.add(m.group(1))
49+
else:
50+
modified_roots.add(f)
51+
52+
required_roots = ["swift-package", "docs", "SwiftUsd.doccarchive"]
53+
expected_roots = ["Package.swift"]
54+
had_error = False
55+
56+
for r in required_roots:
57+
if r not in modified_roots:
58+
print(f"Error: {r} was not modified")
59+
had_error = True
60+
modified_roots.discard(r)
61+
62+
for r in expected_roots:
63+
if r not in modified_roots:
64+
print(f"Warning: {r} was not modified")
65+
modified_roots.discard(r)
66+
67+
if len(modified_roots) != 0:
68+
print(f"Error: unexpected modifications: {modified_roots}")
69+
had_error = True
70+
71+
if had_error:
72+
exit(1)
73+
74+
quiet_run(["git", "add", "-A"])
75+
quiet_run(["git", "commit", "-m", f"Publish documentation and update swift-package for SwiftUsd {args.swiftusd_tag}"])
76+
quiet_run(["git", "tag", args.swiftusd_tag])
77+
78+
79+
printAndWrite(summary=f"""To release SwiftUsd {args.swiftusd_tag}, run:
80+
```
81+
cd {Environment.Path.swiftusd}
82+
git push
83+
git push origin {args.swiftusd_tag}
84+
```
85+
Remember to run these commands in SwiftUsd-Tests and SwiftUsd-ast-answerer:
86+
```
87+
git tag {args.swiftusd_tag}
88+
git push
89+
git push origin {args.swiftusd_tag}
90+
```""")

.github/scripts/run-tests-helper.py

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def should_extract(l):
4545
if action == "build":
4646
return any([s in l for s in ["error:"]])
4747
elif action == "test":
48-
return any([s in l for s in ["failed:", "launchd"]])
48+
return any([s in l for s in ["failed:", "launchd", "crash"]])
4949

5050
def processRunResult(runResult):
5151
end = time.time()
@@ -78,22 +78,52 @@ def processRunResult(runResult):
7878

7979
def prepare_to_build_tests():
8080
print("Preparing to build tests...")
81+
run(["swift", "package", "--package-path", "ReconfigurePbxprojPackageDependency", "clean"],
82+
cwd=Environment.Path.swiftusd_tests)
8183
run(["swift", "run", "--package-path", "ReconfigurePbxprojPackageDependency",
8284
"ReconfigurePbxprojPackageDependency", "SwiftUsdTests.xcodeproj/project.pbxproj",
8385
"--replace", "https://github.com/apple/SwiftUsd", "--with", "SwiftUsd"],
8486
cwd=Environment.Path.swiftusd_tests)
85-
if not (Environment.Path.swiftusd_tests / "SwiftUsd").exists():
86-
(Environment.Path.swiftusd_tests / "SwiftUsd").symlink_to(Environment.Path.swiftusd)
87+
88+
if (Environment.Path.swiftusd_tests / "SwiftUsd").exists():
89+
os.unlink(Environment.Path.swiftusd_tests / "SwiftUsd")
90+
(Environment.Path.swiftusd_tests / "SwiftUsd").symlink_to(Environment.Path.swiftusd)
8791
run(["python3", "make-spm-tests.py", "--local", "--force"],
8892
cwd=Environment.Path.swiftusd_tests)
8993

90-
def get_xcodebuild_destination():
91-
if Environment.TestCombination.target_platform == "macOS": return "platform=macOS,name=My Mac"
92-
elif Environment.TestCombination.target_platform == "iOSSimulator": return "platform=iOS Simulator,name=iPhone 17 Pro"
93-
elif Environment.TestCombination.target_platform == "visionOSSimulator": return "platform=visionOS Simulator,name=Apple Vision Pro (at 2732x2048)"
94+
def conditionalCommonArgs():
95+
result = []
96+
97+
def handleJobs(x, singleMinus):
98+
nonlocal result
99+
try:
100+
if int(x) > 0:
101+
result += ["-jobs" if singleMinus else "--jobs", x]
102+
except:
103+
pass
104+
105+
def handleDevelopmentTeam():
106+
nonlocal result
107+
if Environment.TestCombination.at_desk_development_team:
108+
result += [f"DEVELOPMENT_TEAM={Environment.TestCombination.at_desk_development_team}"]
109+
110+
if Environment.TestCombination.build_system == "xcodebuild-xcodeproj":
111+
handleJobs(Environment.TestCombination.at_desk_xcodebuild_jobs, True)
112+
handleDevelopmentTeam()
113+
114+
elif Environment.TestCombination.build_system == "swiftbuild-SPM-Tests":
115+
handleJobs(Environment.TestCombination.at_desk_swiftbuild_jobs, False)
116+
117+
elif Environment.TestCombination.build_system == "xcodebuild-SPM-Tests":
118+
handleJobs(Environment.TestCombination.at_desk_xcodebuild_jobs, True)
119+
handleDevelopmentTeam()
120+
94121
else:
95-
print(f"Error: Unknown target '{Environment.TestCombination.target_platform}'")
122+
print(f"Error: Unknown build system {Environment.TestCombination.build_system}")
96123
exit(1)
124+
125+
126+
return result
97127

98128
def do_xcodebuild_xcodeproj_tests(action):
99129
build_or_run_test_suite(
@@ -106,11 +136,11 @@ def do_xcodebuild_xcodeproj_tests(action):
106136
],
107137
buildTestCommonArgs=[
108138
"-verbose", "-skipMacroValidation",
109-
"-scheme", "UnitTests",
139+
"-scheme", "UnitTests",
110140
"-configuration", Environment.TestCombination.config,
111-
"-destination", get_xcodebuild_destination(),
141+
"-destination", Environment.TestCombination.xcodebuild_destination,
112142
"OTHER_SWIFT_FLAGS=$(inherited) -DSWIFTUSD_TESTS_SUPPRESS_PERFORMANCE_FAILURES",
113-
],
143+
] + conditionalCommonArgs(),
114144
cwd=Environment.Path.swiftusd_tests,
115145
action=action,
116146
)
@@ -119,10 +149,14 @@ def do_swiftbuild_spm_tests(action):
119149
env = os.environ.copy()
120150
env["SWIFT_BACKTRACE"] = "interactive=no"
121151

122-
# Set DEVELOPER_DIR to work around
123-
# error: cannot load module 'SwiftCompilerPlugin' built with SDK 'macosx26.0' when using SDK 'macosx26.2'
124-
# https://github.com/apple/SwiftUsd/actions/runs/21256906902/job/61175337955
125-
env["DEVELOPER_DIR"] = "/Applications/Xcode-latest.app"
152+
# todo: revisit this, setting it here means that
153+
# xcodebuild -version in the logs is misleading because
154+
# it's computed without this environment variable
155+
if os.path.exists("/Applications/Xcode-latest.app"):
156+
# Set DEVELOPER_DIR to work around
157+
# error: cannot load module 'SwiftCompilerPlugin' built with SDK 'macosx26.0' when using SDK 'macosx26.2'
158+
# https://github.com/apple/SwiftUsd/actions/runs/21256906902/job/61175337955
159+
env["DEVELOPER_DIR"] = "/Applications/Xcode-latest.app"
126160

127161
build_or_run_test_suite(
128162
name="swiftbuild-SPM-Tests",
@@ -134,7 +168,7 @@ def do_swiftbuild_spm_tests(action):
134168
"-Xswiftc", "-DOPENUSD_SWIFT_BUILD_FROM_CLI", "-Xcxx", "-DOPENUSD_SWIFT_BUILD_FROM_CLI",
135169
"--configuration", Environment.TestCombination.config.lower(),
136170
"-Xswiftc", "-DSWIFTUSD_TESTS_SUPPRESS_PERFORMANCE_FAILURES",
137-
],
171+
] + conditionalCommonArgs(),
138172
cwd=Environment.Path.swiftusd_tests / "SPM-Tests",
139173
action=action,
140174
env=env
@@ -153,9 +187,9 @@ def do_xcodebuild_spm_tests(action):
153187
"-verbose", "-skipMacroValidation",
154188
"-scheme", "SPM-Tests-Package",
155189
"-config", Environment.TestCombination.config,
156-
"-destination", get_xcodebuild_destination(),
190+
"-destination", Environment.TestCombination.xcodebuild_destination,
157191
"OTHER_SWIFT_FLAGS=$(inherited) -DSWIFTUSD_TESTS_SUPPRESS_PERFORMANCE_FAILURES",
158-
],
192+
] + conditionalCommonArgs(),
159193
cwd=Environment.Path.swiftusd_tests / "SPM-Tests",
160194
action=action,
161195
)
@@ -198,4 +232,4 @@ def run_tests(args, subparsers):
198232

199233
args = parser.parse_args()
200234

201-
args.func(args)
235+
args.func(args)

.github/scripts/swiftusd_ci_common/environment.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ class TestCombination:
3737
config = os.getenv("CONFIG")
3838
build_system = os.getenv("BUILD_SYSTEM")
3939
github_run_id = os.getenv("GITHUB_RUN_ID")
40+
xcodebuild_destination = os.getenv("XCODEBUILD_DESTINATION")
41+
at_desk_iOS_xcodebuild_destination = os.getenv("ATDESK_IOS_XCODEBUILD_DESTINATION")
42+
at_desk_visionOS_xcodebuild_destination = os.getenv("ATDESK_VISIONOS_XCODEBUILD_DESTINATION")
43+
at_desk_swiftbuild_jobs = os.getenv("ATDESK_SWIFTBUILD_JOBS")
44+
at_desk_xcodebuild_jobs = os.getenv("ATDESK_XCODEBUILD_JOBS")
45+
at_desk_development_team = os.getenv("ATDESK_DEVELOPMENT_TEAM")
4046

4147
class Path:
4248
swiftusd = _getenvpath("SWIFTUSD_PATH")
@@ -48,4 +54,4 @@ class Path:
4854
tmp_dir = _getenvpath("RUNNER_TEMP")
4955
github_workspace = _getenvpath("GITHUB_WORKSPACE")
5056
matrix_result = _getenvpath("MATRIX_RESULT_PATH")
51-
matrix_results = _getenvpath("MATRIX_RESULTS_PATH")
57+
matrix_results = _getenvpath("MATRIX_RESULTS_PATH")

.github/scripts/swiftusd_ci_common/openusd_building.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,26 @@ def clone_openusd(checkout=None):
3232
run(["git", "checkout", checkout], cwd=Environment.Path.openusd, logOutput=False)
3333

3434
def get_openusd_build_flags(target):
35+
file_prefix_map = f"--build-args=USD,\"-DCMAKE_CXX_FLAGS_INIT=-ffile-prefix-map={Environment.Path.openusd}=OpenUSD\""
36+
3537
if target == "macOS":
3638
return ["--embree", "--imageio", "--alembic", "--openvdb", "--no-python",
37-
"--ignore-homebrew", "--build-target", "native", openusd_build_dir("macOS")]
39+
"--ignore-homebrew", "--build-target", "native", openusd_build_dir("macOS"), file_prefix_map]
3840

3941
if target == "iOS":
4042
return ["--imageio", "--alembic", "--no-python", "--ignore-homebrew",
41-
"--build-target", "iOS", openusd_build_dir("iOS")]
43+
"--build-target", "iOS", openusd_build_dir("iOS"), file_prefix_map]
4244

4345
if target == "iOSSimulator":
4446
return ["--imageio", "--alembic", "--no-python", "--ignore-homebrew",
45-
"--build-target", "iOSSimulator", openusd_build_dir("iOSSimulator")]
47+
"--build-target", "iOSSimulator", openusd_build_dir("iOSSimulator"), file_prefix_map]
4648

4749
if target == "visionOS":
4850
return ["--imageio", "--alembic", "--no-python", "--ignore-homebrew",
49-
"--build-target", "visionOS", openusd_build_dir("visionOS")]
51+
"--build-target", "visionOS", openusd_build_dir("visionOS"), file_prefix_map]
5052

5153
if target == "visionOSSimulator":
5254
return ["--imageio", "--alembic", "--no-python", "--ignore-homebrew",
53-
"--build-target", "visionOSSimulator", openusd_build_dir("visionOSSimulator")]
55+
"--build-target", "visionOSSimulator", openusd_build_dir("visionOSSimulator"), file_prefix_map]
5456

55-
raise ValueError(f"Unknown target {target}")
57+
raise ValueError(f"Unknown target {target}")

.github/scripts/swiftusd_ci_common/subprocesses.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,7 @@ def run(args, cwd=None, env=None, input=None, logCmd=True, logOutput=True, check
6767

6868
exit(result.returncode)
6969

70-
return result
70+
return result
71+
72+
def which(cmd):
73+
return run(["which", cmd], logCmd=False, logOutput=False, check=False).returncode == 0

.github/scripts/swiftusd_ci_common/test_matrix_results.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ def __init__(self):
4040
raw_xcodebuild_version = "\n".join(run(["xcodebuild", "-version"]).output)
4141
short_xcodebuild_version = re.search(r"Xcode (.*)", raw_xcodebuild_version).group(1) + " (" + re.search(r"Build version (.*)", raw_xcodebuild_version).group(1) + ")"
4242
if Environment.GitRef.swiftusd and Environment.Path.swiftusd:
43-
swiftusd_ref = run(["git", "rev-parse", Environment.GitRef.swiftusd], cwd=Environment.Path.swiftusd).output[0]
43+
swiftusd_ref = run(["git", "rev-parse", Environment.GitRef.swiftusd], cwd=Environment.Path.swiftusd, check=False).output[0]
4444
else:
4545
swiftusd_ref = "null"
4646

4747
if Environment.GitRef.swiftusd_tests and Environment.Path.swiftusd_tests:
48-
swiftusd_tests_ref = run(["git", "rev-parse", Environment.GitRef.swiftusd_tests], cwd=Environment.Path.swiftusd_tests).output[0]
48+
swiftusd_tests_ref = run(["git", "rev-parse", Environment.GitRef.swiftusd_tests], cwd=Environment.Path.swiftusd_tests, check=False).output[0]
4949
else:
5050
swiftusd_tests_ref = "null"
5151

0 commit comments

Comments
 (0)