Skip to content

Commit 12fe4ab

Browse files
Allow updates for sub-dependencies in XCode SwiftPM projects (#14619)
* allow updates for sub-dependencies in xcode swiftpm projects * refactor function to check if requirement comes from package.resolved * reuse function from XCodeFileHelpers class
1 parent 75393ad commit 12fe4ab

2 files changed

Lines changed: 38 additions & 1 deletion

File tree

swift/lib/dependabot/swift/update_checker/xcode_version_resolver.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
require "dependabot/swift/update_checker"
77
require "dependabot/swift/requirement"
88
require "dependabot/swift/version"
9+
require "dependabot/swift/xcode_file_helpers"
910
require "dependabot/update_checkers/version_filters"
1011

1112
module Dependabot
@@ -145,12 +146,32 @@ def version_meets_requirements?(version)
145146
# Only versionRange has an explicit upper bound that should be respected.
146147
return true if %w(exactVersion upToNextMajorVersion upToNextMinorVersion).include?(kind)
147148

149+
# For sub-dependencies that are not declared directly in project.pbxproj
150+
# (e.g., transitive dependencies of local packages), kind will be nil and
151+
# the requirement comes from Package.resolved as an equality pin.
152+
# In this case, we allow updates since the actual constraint lives in
153+
# the local package's Package.swift, which we don't have access to.
154+
# This may produce a pin that is not resolvable for the full package graph.
155+
# In Xcode mode we intentionally defer that validation to downstream
156+
# SwiftPM/Xcode resolution.
157+
return true if kind.nil? && package_resolved_requirement?
158+
148159
requirement = dependency_requirement
149160
return true unless requirement
150161

151162
requirement.satisfied_by?(version)
152163
end
153164

165+
# Returns true if the dependency's requirement originates from an
166+
# Xcode-managed Package.resolved file (rather than project.pbxproj).
167+
sig { returns(T::Boolean) }
168+
def package_resolved_requirement?
169+
dependency.requirements.any? do |req|
170+
file = req[:file]
171+
file.is_a?(String) && XcodeFileHelpers.xcode_resolved_path?(file)
172+
end
173+
end
174+
154175
sig do
155176
params(
156177
tags: T::Array[T::Hash[Symbol, T.untyped]]

swift/spec/dependabot/swift/update_checker/xcode_version_resolver_spec.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@
164164
end
165165
end
166166

167-
context "with nil requirement kind" do
167+
context "with nil requirement kind from pbxproj" do
168168
let(:requirements) do
169169
[{
170170
file: "MyApp.xcodeproj/project.pbxproj",
@@ -179,6 +179,22 @@
179179
expect(resolver.send(:version_meets_requirements?, version)).to be false
180180
end
181181
end
182+
183+
context "with nil requirement kind from Package.resolved (sub-dependency)" do
184+
let(:requirements) do
185+
[{
186+
file: "MyApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved",
187+
requirement: "= 7.0.0",
188+
groups: ["dependencies"],
189+
source: { type: "git", url: "https://github.com/Quick/Quick.git", ref: "7.0.0", branch: nil },
190+
metadata: { identity: "quick" }
191+
}]
192+
end
193+
194+
it "allows updates since actual constraint is in local package's Package.swift" do
195+
expect(resolver.send(:version_meets_requirements?, version)).to be true
196+
end
197+
end
182198
end
183199

184200
describe "#version_pinned?" do

0 commit comments

Comments
 (0)