Skip to content

Commit 7a18042

Browse files
authored
Support Xcode16's new synchronized folder format (#48)
* Add a failing test case * Update tuist/XcodeProj * Support fileSystemSynchronizedGroups * Remove unused arguments * Fix typo
1 parent 27000cc commit 7a18042

8 files changed

Lines changed: 130 additions & 35 deletions

File tree

Package.resolved

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ let package = Package(
6969
],
7070
products: products,
7171
dependencies: [
72-
.package(url: "https://github.com/tuist/XcodeProj.git", .upToNextMajor(from: "8.24.1")),
72+
.package(url: "https://github.com/tuist/XcodeProj.git", .upToNextMajor(from: "9.0.2")),
7373
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMajor(from: "1.2.0")),
7474
.package(url: "https://github.com/kylef/PathKit.git", .upToNextMinor(from: "1.0.0")),
7575
.package(url: "https://github.com/onevcat/Rainbow", .upToNextMajor(from: "4.0.0")),

Sources/DependencyCalculator/DependencyGraph.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,11 @@ extension WorkspaceInfo {
318318
file.paths(projectFolder: path.parent())
319319
} ?? []))
320320

321+
// Synchronized Groups Files
322+
filesPaths = filesPaths.union(
323+
Set(fileSystemSynchronizedGroupsFiles(target: target, projectFolder: path.parent()))
324+
)
325+
321326
// Establish dependencies based on linked frameworks build phase
322327
try target.frameworksBuildPhase()?.files?.forEach { file in
323328
guard let path = file.file?.path else {
@@ -372,4 +377,31 @@ extension WorkspaceInfo {
372377
return false
373378
}
374379
}
380+
381+
/// Search all files specified in fileSystemSynchronizedGroups.
382+
/// Currently, file extensions are note considered at all, so all files in the folder are subject to the search.
383+
/// NOTE: FileSystemSynchronizedFileExceptionSet is not suppored yet.
384+
///
385+
/// ref: https://github.com/tuist/XcodeGraph/pull/108
386+
/// The implementation of `XcodeGraph` only considers cases where the root is a folder.
387+
/// so customizations have also been added.
388+
private static func fileSystemSynchronizedGroupsFiles(
389+
target: PBXNativeTarget,
390+
projectFolder: Path
391+
) -> [Path] {
392+
guard let fileSystemSynchronizedGroups = target.fileSystemSynchronizedGroups else { return [] }
393+
var paths: [Path] = []
394+
fileSystemSynchronizedGroups.forEach { group in
395+
let folderPath: Path?
396+
switch group.sourceTree {
397+
case .absolute, .sourceRoot, .group:
398+
folderPath = try? group.fullPath(sourceRoot: projectFolder)
399+
default:
400+
folderPath = group.path.map { Path($0) }
401+
}
402+
guard let folderPath else { return }
403+
paths.append(contentsOf: (try? folderPath.recursiveChildren()) ?? [])
404+
}
405+
return paths
406+
}
375407
}

Tests/SelectiveTestingTests/ExampleProject/ExampleProject.xcodeproj/project.pbxproj

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 56;
6+
objectVersion = 70;
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
09B9B09D2DB72E40005B6CD5 /* GroupContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B9B09A2DB72E40005B6CD5 /* GroupContentView.swift */; };
1011
276DB5BF29B144C900E5C615 /* ExampleProjectApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 276DB5BE29B144C900E5C615 /* ExampleProjectApp.swift */; };
1112
276DB5C329B144C900E5C615 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 276DB5C229B144C900E5C615 /* Assets.xcassets */; };
1213
276DB5C629B144C900E5C615 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 276DB5C529B144C900E5C615 /* Preview Assets.xcassets */; };
@@ -23,7 +24,6 @@
2324
27F4680929B145F900A93E94 /* ExampleTargetLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F4680829B145F900A93E94 /* ExampleTargetLibrary.swift */; };
2425
27F4680C29B1482E00A93E94 /* ExamplePackage in Frameworks */ = {isa = PBXBuildFile; productRef = 27F4680B29B1482E00A93E94 /* ExamplePackage */; };
2526
B24BBDBD2CAD7228005E6DAC /* Example.xib in Resources */ = {isa = PBXBuildFile; fileRef = B24BBDBC2CAD7228005E6DAC /* Example.xib */; };
26-
FDE924012A5C5AC300D61FD3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE924002A5C5AC300D61FD3 /* ContentView.swift */; };
2727
/* End PBXBuildFile section */
2828

2929
/* Begin PBXContainerItemProxy section */
@@ -72,6 +72,7 @@
7272
/* End PBXCopyFilesBuildPhase section */
7373

7474
/* Begin PBXFileReference section */
75+
09B9B09A2DB72E40005B6CD5 /* GroupContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupContentView.swift; sourceTree = "<group>"; };
7576
276DB5BB29B144C900E5C615 /* ExampleProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleProject.app; sourceTree = BUILT_PRODUCTS_DIR; };
7677
276DB5BE29B144C900E5C615 /* ExampleProjectApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleProjectApp.swift; sourceTree = "<group>"; };
7778
276DB5C229B144C900E5C615 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -91,9 +92,12 @@
9192
27F4680A29B1469D00A93E94 /* ExamplePackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = ExamplePackage; sourceTree = "<group>"; };
9293
B24BBDBB2CAD7228005E6DAC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Example.xib; sourceTree = "<group>"; };
9394
B24BBDBF2CAD7244005E6DAC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Example.strings; sourceTree = "<group>"; };
94-
FDE924002A5C5AC300D61FD3 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
9595
/* End PBXFileReference section */
9696

97+
/* Begin PBXFileSystemSynchronizedRootGroup section */
98+
095EE0952DB8E35400EACE2E /* DeepFolder */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = DeepFolder; sourceTree = "<group>"; };
99+
/* End PBXFileSystemSynchronizedRootGroup section */
100+
97101
/* Begin PBXFrameworksBuildPhase section */
98102
276DB5B829B144C900E5C615 /* Frameworks */ = {
99103
isa = PBXFrameworksBuildPhase;
@@ -137,6 +141,22 @@
137141
/* End PBXFrameworksBuildPhase section */
138142

139143
/* Begin PBXGroup section */
144+
09B9B09B2DB72E40005B6CD5 /* Path */ = {
145+
isa = PBXGroup;
146+
children = (
147+
09B9B09A2DB72E40005B6CD5 /* GroupContentView.swift */,
148+
);
149+
path = Path;
150+
sourceTree = "<group>";
151+
};
152+
09B9B09C2DB72E40005B6CD5 /* DeepGroup */ = {
153+
isa = PBXGroup;
154+
children = (
155+
09B9B09B2DB72E40005B6CD5 /* Path */,
156+
);
157+
path = DeepGroup;
158+
sourceTree = "<group>";
159+
};
140160
276DB5B229B144C900E5C615 = {
141161
isa = PBXGroup;
142162
children = (
@@ -167,7 +187,8 @@
167187
isa = PBXGroup;
168188
children = (
169189
276DB5BE29B144C900E5C615 /* ExampleProjectApp.swift */,
170-
FDE923FE2A5C5AC300D61FD3 /* Deep */,
190+
095EE0952DB8E35400EACE2E /* DeepFolder */,
191+
09B9B09C2DB72E40005B6CD5 /* DeepGroup */,
171192
276DB5C229B144C900E5C615 /* Assets.xcassets */,
172193
276DB5C429B144C900E5C615 /* Preview Content */,
173194
B24BBDBC2CAD7228005E6DAC /* Example.xib */,
@@ -226,22 +247,6 @@
226247
name = Frameworks;
227248
sourceTree = "<group>";
228249
};
229-
FDE923FE2A5C5AC300D61FD3 /* Deep */ = {
230-
isa = PBXGroup;
231-
children = (
232-
FDE923FF2A5C5AC300D61FD3 /* Path */,
233-
);
234-
path = Deep;
235-
sourceTree = "<group>";
236-
};
237-
FDE923FF2A5C5AC300D61FD3 /* Path */ = {
238-
isa = PBXGroup;
239-
children = (
240-
FDE924002A5C5AC300D61FD3 /* ContentView.swift */,
241-
);
242-
path = Path;
243-
sourceTree = "<group>";
244-
};
245250
/* End PBXGroup section */
246251

247252
/* Begin PBXHeadersBuildPhase section */
@@ -270,6 +275,9 @@
270275
dependencies = (
271276
27F467F929B1457600A93E94 /* PBXTargetDependency */,
272277
);
278+
fileSystemSynchronizedGroups = (
279+
095EE0952DB8E35400EACE2E /* DeepFolder */,
280+
);
273281
name = ExampleProject;
274282
packageProductDependencies = (
275283
27F4680B29B1482E00A93E94 /* ExamplePackage */,
@@ -450,7 +458,7 @@
450458
isa = PBXSourcesBuildPhase;
451459
buildActionMask = 2147483647;
452460
files = (
453-
FDE924012A5C5AC300D61FD3 /* ContentView.swift in Sources */,
461+
09B9B09D2DB72E40005B6CD5 /* GroupContentView.swift in Sources */,
454462
276DB5BF29B144C900E5C615 /* ExampleProjectApp.swift in Sources */,
455463
);
456464
runOnlyForDeploymentPostprocessing = 0;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import ExampleLibrary
2+
import ExamplePackage
3+
import ExmapleTargetLibrary
4+
import SwiftUI
5+
6+
struct FolderContentView: View {
7+
var body: some View {
8+
VStack {
9+
Image(systemName: "globe")
10+
.imageScale(.large)
11+
.foregroundColor(.accentColor)
12+
Text(ExampleLibrary.exampleText())
13+
Text(ExampleTargetLibrary.exampleTargetText())
14+
Text(ExamplePackage.exampleText())
15+
}
16+
.padding()
17+
}
18+
}
19+
20+
struct FolderContentView_Previews: PreviewProvider {
21+
static var previews: some View {
22+
FolderContentView()
23+
}
24+
}

Tests/SelectiveTestingTests/ExampleProject/ExampleProject/Deep/Path/ContentView.swift renamed to Tests/SelectiveTestingTests/ExampleProject/ExampleProject/DeepGroup/Path/GroupContentView.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// ContentView.swift
2+
// GroupContentView.swift
33
// ExampleProject
44
//
55
// Created by Mike on 02.03.23.
@@ -10,7 +10,7 @@ import ExamplePackage
1010
import ExmapleTargetLibrary
1111
import SwiftUI
1212

13-
struct ContentView: View {
13+
struct GroupContentView: View {
1414
var body: some View {
1515
VStack {
1616
Image(systemName: "globe")
@@ -24,8 +24,8 @@ struct ContentView: View {
2424
}
2525
}
2626

27-
struct ContentView_Previews: PreviewProvider {
27+
struct GroupContentView_Previews: PreviewProvider {
2828
static var previews: some View {
29-
ContentView()
29+
GroupContentView()
3030
}
3131
}

Tests/SelectiveTestingTests/ExampleProject/ExampleProject/ExampleProjectApp.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import SwiftUI
1111
struct ExampleProjectApp: App {
1212
var body: some Scene {
1313
WindowGroup {
14-
ContentView()
14+
GroupContentView()
1515
}
1616
}
1717
}

Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ final class SelectiveTestingProjectTests: XCTestCase {
4141
]))
4242
}
4343

44-
func testProjectAlone_turbo() async throws {
44+
func testProjectDeepGroupPathChange_turbo() async throws {
4545
// given
4646
let tool = try testTool.createSUT(config: nil,
4747
basePath: "ExampleProject.xcodeproj",
4848
turbo: true)
4949
// when
50-
try testTool.changeFile(at: testTool.projectPath + "ExampleProject/Deep/Path/ContentView.swift")
50+
try testTool.changeFile(at: testTool.projectPath + "ExampleProject/DeepGroup/Path/GroupContentView.swift")
5151

5252
// then
5353
let result = try await tool.run()
@@ -56,12 +56,43 @@ final class SelectiveTestingProjectTests: XCTestCase {
5656
]))
5757
}
5858

59-
func testProjectDeepPathChange() async throws {
59+
func testProjectDeepGroupPathChange() async throws {
6060
// given
6161
let tool = try testTool.createSUT(config: nil,
6262
basePath: "ExampleProject.xcodeproj")
6363
// when
64-
try testTool.changeFile(at: testTool.projectPath + "ExampleProject/Deep/Path/ContentView.swift")
64+
try testTool.changeFile(at: testTool.projectPath + "ExampleProject/DeepGroup/Path/GroupContentView.swift")
65+
66+
// then
67+
let result = try await tool.run()
68+
XCTAssertEqual(result, Set([
69+
testTool.mainProjectMainTarget,
70+
testTool.mainProjectTests,
71+
testTool.mainProjectUITests,
72+
]))
73+
}
74+
75+
func testProjectDeepFolderPathChange_turbo() async throws {
76+
// given
77+
let tool = try testTool.createSUT(config: nil,
78+
basePath: "ExampleProject.xcodeproj",
79+
turbo: true)
80+
// when
81+
try testTool.changeFile(at: testTool.projectPath + "ExampleProject/DeepFolder/Path/FolderContentView.swift")
82+
83+
// then
84+
let result = try await tool.run()
85+
XCTAssertEqual(result, Set([
86+
testTool.mainProjectMainTarget
87+
]))
88+
}
89+
90+
func testProjectDeepFolderPathChange() async throws {
91+
// given
92+
let tool = try testTool.createSUT(config: nil,
93+
basePath: "ExampleProject.xcodeproj")
94+
// when
95+
try testTool.changeFile(at: testTool.projectPath + "ExampleProject/DeepFolder/Path/FolderContentView.swift")
6596

6697
// then
6798
let result = try await tool.run()

0 commit comments

Comments
 (0)