Skip to content

Commit 35f7e52

Browse files
Ckitakishiclaudeyonaskolb
authored
Fix missing dstPath in Copy Bundle Resources phases (#1654)
* Write an empty destination path for the bundle copy phase The generated "Copy Bundle Resources" phase omitted `dstPath`, and converting such a project to the Xcode 27.2 JSON format fails with "A copy build phase is missing a required value for destination path". Xcode-written projects carry the key with an empty path when no subpath is needed, and every other phase XcodeGen generates already does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Add changelog entry for #1654 --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Yonas Kolb <yonaskolb@users.noreply.github.com>
1 parent aae8777 commit 35f7e52

4 files changed

Lines changed: 7 additions & 2 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- Fix `syncedFolder` source paths being relative to the spec directory instead of the project directory when they differ, which caused Xcode to treat the synced folder as empty #1636 @Ckitakishi
1515
- Fix nested target attributes (e.g. `attributes.SystemCapabilities`) being serialized as a stringified Swift `Dictionary` description instead of a proper nested plist dictionary, which also caused non-deterministic key ordering in generated `project.pbxproj` files across runs #1639 @imadaan @sergeyospanov
1616
- Fix `.DS_Store` and `.orig` files causing projects to be regenerated when using `--use-cache` #1622 @kimjune01
17+
- Fix generated "Copy Bundle Resources" phases missing `dstPath`, which caused Xcode 27.2 project conversion to fail #1654 @Ckitakishi
1718

1819
### Internal
1920
- Use a dedicated local package in the SPM fixture so generated fixtures don't depend on the checkout directory name, such as when running tests from a git worktree @yonaskolb

‎Sources/XcodeGenKit/PBXProjGenerator.swift‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,8 @@ public class PBXProjGenerator {
12211221

12221222
if !copyBundlesReferences.isEmpty {
12231223
let copyBundlesPhase = addObject(PBXCopyFilesBuildPhase(
1224+
// Xcode expects the key to be present, even when the path is empty.
1225+
dstPath: "",
12241226
dstSubfolderSpec: .resources,
12251227
name: "Copy Bundle Resources",
12261228
files: copyBundlesReferences

‎Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@
616616
E8BC0F358D693454E5027ECC /* Copy Bundle Resources */ = {
617617
isa = PBXCopyFilesBuildPhase;
618618
buildActionMask = 2147483647;
619+
dstPath = "";
619620
dstSubfolderSpec = 7;
620621
files = (
621622
3BBCA6F76E5F212E9C55FB78 /* BundleX.bundle in Copy Bundle Resources */,

‎Tests/XcodeGenKitTests/ProjectGeneratorTests.swift‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,7 @@ class ProjectGeneratorTests: XCTestCase {
998998
let copyBundles = (copyBundlesPhase?.files ?? [])
999999
.compactMap { $0.file?.nameOrPath }
10001000
try expect(Set(copyBundles)) == expectedBundlesFiles
1001+
try expect(copyBundlesPhase?.dstPath) == ""
10011002
}
10021003
try expect(copyFilesPhases.count) == expectedCopyFilesPhasesCount
10031004
}
@@ -3724,7 +3725,7 @@ class ProjectGeneratorTests: XCTestCase {
37243725

37253726
// then
37263727
/// XcodeGen ignores embed: false for bundles
3727-
try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.bundle", "bundleB.bundle"], toSubFolder: .resources)
3728+
try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.bundle", "bundleB.bundle"], toSubFolder: .resources, dstPath: "")
37283729
}
37293730

37303731
$0.it("ignores custom copy phase spec") {
@@ -3740,7 +3741,7 @@ class ProjectGeneratorTests: XCTestCase {
37403741

37413742
// then
37423743
/// XcodeGen ignores embed: false for bundles
3743-
try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.bundle", "bundleB.bundle"], toSubFolder: .resources)
3744+
try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.bundle", "bundleB.bundle"], toSubFolder: .resources, dstPath: "")
37443745
}
37453746
}
37463747
}

0 commit comments

Comments
 (0)