dependabot-swift 0.222.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/dependabot/swift/file_fetcher.rb +50 -0
- data/lib/dependabot/swift/file_parser/dependency_parser.rb +72 -0
- data/lib/dependabot/swift/file_parser/manifest_parser.rb +47 -0
- data/lib/dependabot/swift/file_parser.rb +60 -0
- data/lib/dependabot/swift/file_updater/lockfile_updater.rb +38 -0
- data/lib/dependabot/swift/file_updater/manifest_updater.rb +37 -0
- data/lib/dependabot/swift/file_updater/requirement_replacer.rb +28 -0
- data/lib/dependabot/swift/file_updater.rb +78 -0
- data/lib/dependabot/swift/metadata_finder.rb +38 -0
- data/lib/dependabot/swift/native_requirement.rb +159 -0
- data/lib/dependabot/swift/requirement.rb +29 -0
- data/lib/dependabot/swift/update_checker/requirements_updater.rb +31 -0
- data/lib/dependabot/swift/update_checker/version_resolver.rb +54 -0
- data/lib/dependabot/swift/update_checker.rb +107 -0
- data/lib/dependabot/swift/version.rb +11 -0
- data/lib/dependabot/swift.rb +22 -0
- metadata +230 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4aef4a94ae75bf75d90152d46b40c74149b9b6724392bcd7aed6ab75843dc359
|
4
|
+
data.tar.gz: b1423ec2d83751d7f0fca41a5e24b0d7c952015ca355042ab5a585f02b321895
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2451f0816f18243f61732cd2cb751953ba5b7cb8e55727901c33a81ae9f574282ee58f098df107b7b550e1dfa98b37475b50e1e0e323ae0b3dc9c7a5ec04002c
|
7
|
+
data.tar.gz: 7a8dc186c3490327e53c721c01a2424c34a18350bc00d92367866e667980e851379ac2a9f3efb74d892f8bcdb238260fc67843054805c69d62de3228c75f0b0b
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_fetchers"
|
4
|
+
require "dependabot/file_fetchers/base"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Swift
|
8
|
+
class FileFetcher < Dependabot::FileFetchers::Base
|
9
|
+
def self.required_files_in?(filenames)
|
10
|
+
filenames.include?("Package.swift")
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.required_files_message
|
14
|
+
"Repo must contain a Package.swift configuration file."
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def fetch_files
|
20
|
+
check_required_files_present
|
21
|
+
|
22
|
+
fetched_files = []
|
23
|
+
fetched_files << package_manifest
|
24
|
+
fetched_files << package_resolved if package_resolved
|
25
|
+
fetched_files
|
26
|
+
end
|
27
|
+
|
28
|
+
def package_manifest
|
29
|
+
@package_manifest ||= fetch_file_from_host("Package.swift")
|
30
|
+
end
|
31
|
+
|
32
|
+
def package_resolved
|
33
|
+
return @package_resolved if defined?(@package_resolved)
|
34
|
+
|
35
|
+
@package_resolved = fetch_file_if_present("Package.resolved")
|
36
|
+
end
|
37
|
+
|
38
|
+
def check_required_files_present
|
39
|
+
return if package_manifest
|
40
|
+
|
41
|
+
path = Pathname.new(File.join(directory, "Package.swift")).
|
42
|
+
cleanpath.to_path
|
43
|
+
raise Dependabot::DependencyFileNotFound, path
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Dependabot::FileFetchers.
|
50
|
+
register("swift", Dependabot::Swift::FileFetcher)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_parsers/base"
|
4
|
+
require "dependabot/shared_helpers"
|
5
|
+
require "dependabot/dependency"
|
6
|
+
require "json"
|
7
|
+
|
8
|
+
module Dependabot
|
9
|
+
module Swift
|
10
|
+
class FileParser < Dependabot::FileParsers::Base
|
11
|
+
class DependencyParser
|
12
|
+
def initialize(dependency_files:, repo_contents_path:, credentials:)
|
13
|
+
@dependency_files = dependency_files
|
14
|
+
@repo_contents_path = repo_contents_path
|
15
|
+
@credentials = credentials
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse
|
19
|
+
SharedHelpers.in_a_temporary_repo_directory(dependency_files.first.directory, repo_contents_path) do
|
20
|
+
write_temporary_dependency_files
|
21
|
+
|
22
|
+
SharedHelpers.with_git_configured(credentials: credentials) do
|
23
|
+
subdependencies(formatted_deps)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def write_temporary_dependency_files
|
31
|
+
dependency_files.each do |file|
|
32
|
+
File.write(file.name, file.content)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def formatted_deps
|
37
|
+
deps = SharedHelpers.run_shell_command(
|
38
|
+
"swift package show-dependencies --format json",
|
39
|
+
stderr_to_stdout: false
|
40
|
+
)
|
41
|
+
|
42
|
+
JSON.parse(deps)
|
43
|
+
end
|
44
|
+
|
45
|
+
def subdependencies(data, level: 0)
|
46
|
+
data["dependencies"].flat_map { |root| all_dependencies(root, level: level) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def all_dependencies(data, level: 0)
|
50
|
+
name = data["identity"]
|
51
|
+
url = data["url"]
|
52
|
+
version = data["version"]
|
53
|
+
|
54
|
+
source = { type: "git", url: url, ref: version, branch: nil }
|
55
|
+
args = { name: name, version: version, package_manager: "swift", requirements: [] }
|
56
|
+
|
57
|
+
if level.zero?
|
58
|
+
args[:requirements] << { requirement: nil, groups: ["dependencies"], file: nil, source: source }
|
59
|
+
else
|
60
|
+
args[:subdependency_metadata] = [{ source: source }]
|
61
|
+
end
|
62
|
+
|
63
|
+
dep = Dependency.new(**args) if data["version"] != "unspecified"
|
64
|
+
|
65
|
+
[dep, *subdependencies(data, level: level + 1)].compact
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_reader :dependency_files, :repo_contents_path, :credentials
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_parsers/base"
|
4
|
+
require "dependabot/swift/native_requirement"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Swift
|
8
|
+
class FileParser < Dependabot::FileParsers::Base
|
9
|
+
class ManifestParser
|
10
|
+
DEPENDENCY = /(?<declaration>\.package\(\s*(?:name: "[^"]+",\s*)?url: "(?<url>[^"]+)",\s*(?<requirement>.*)\))/
|
11
|
+
|
12
|
+
def initialize(manifest, source:)
|
13
|
+
@manifest = manifest
|
14
|
+
@source = source
|
15
|
+
end
|
16
|
+
|
17
|
+
def requirements
|
18
|
+
found = manifest.content.scan(DEPENDENCY).find do |_declaration, url, requirement|
|
19
|
+
# TODO: Support pinning to specific revisions
|
20
|
+
next if requirement.start_with?("branch:", ".branch(", "revision:", ".revision(")
|
21
|
+
|
22
|
+
url == source[:url]
|
23
|
+
end
|
24
|
+
|
25
|
+
return [] unless found
|
26
|
+
|
27
|
+
declaration = found.first
|
28
|
+
requirement = NativeRequirement.new(found.last)
|
29
|
+
|
30
|
+
[
|
31
|
+
{
|
32
|
+
requirement: requirement.to_s,
|
33
|
+
groups: ["dependencies"],
|
34
|
+
file: manifest.name,
|
35
|
+
source: source,
|
36
|
+
metadata: { declaration_string: declaration, requirement_string: requirement.declaration }
|
37
|
+
}
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :manifest, :source
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/dependency"
|
4
|
+
require "dependabot/file_parsers"
|
5
|
+
require "dependabot/file_parsers/base"
|
6
|
+
require "dependabot/swift/file_parser/dependency_parser"
|
7
|
+
require "dependabot/swift/file_parser/manifest_parser"
|
8
|
+
|
9
|
+
module Dependabot
|
10
|
+
module Swift
|
11
|
+
class FileParser < Dependabot::FileParsers::Base
|
12
|
+
require "dependabot/file_parsers/base/dependency_set"
|
13
|
+
|
14
|
+
def parse
|
15
|
+
dependency_set = DependencySet.new
|
16
|
+
|
17
|
+
dependency_parser.parse.map do |dep|
|
18
|
+
if dep.top_level?
|
19
|
+
source = dep.requirements.first[:source]
|
20
|
+
|
21
|
+
requirements = ManifestParser.new(package_manifest_file, source: source).requirements
|
22
|
+
|
23
|
+
dependency_set << Dependency.new(
|
24
|
+
name: dep.name,
|
25
|
+
version: dep.version,
|
26
|
+
package_manager: dep.package_manager,
|
27
|
+
requirements: requirements
|
28
|
+
)
|
29
|
+
else
|
30
|
+
dependency_set << dep
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
dependency_set.dependencies
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def dependency_parser
|
40
|
+
DependencyParser.new(
|
41
|
+
dependency_files: dependency_files,
|
42
|
+
repo_contents_path: repo_contents_path,
|
43
|
+
credentials: credentials
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def check_required_files
|
48
|
+
raise "No Package.swift!" unless package_manifest_file
|
49
|
+
end
|
50
|
+
|
51
|
+
def package_manifest_file
|
52
|
+
# TODO: Select version-specific manifest
|
53
|
+
@package_manifest_file ||= get_original_file("Package.swift")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Dependabot::FileParsers.
|
60
|
+
register("swift", Dependabot::Swift::FileParser)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_updaters/base"
|
4
|
+
require "dependabot/shared_helpers"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Swift
|
8
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
9
|
+
class LockfileUpdater
|
10
|
+
def initialize(dependencies:, manifest:, repo_contents_path:, credentials:)
|
11
|
+
@dependencies = dependencies
|
12
|
+
@manifest = manifest
|
13
|
+
@repo_contents_path = repo_contents_path
|
14
|
+
@credentials = credentials
|
15
|
+
end
|
16
|
+
|
17
|
+
def updated_lockfile_content
|
18
|
+
SharedHelpers.in_a_temporary_repo_directory(manifest.directory, repo_contents_path) do
|
19
|
+
File.write(manifest.name, manifest.content)
|
20
|
+
|
21
|
+
SharedHelpers.with_git_configured(credentials: credentials) do
|
22
|
+
SharedHelpers.run_shell_command(
|
23
|
+
"swift package update #{dependencies.map(&:name).join(' ')}",
|
24
|
+
fingerprint: "swift package update <dependency_name>"
|
25
|
+
)
|
26
|
+
|
27
|
+
File.read("Package.resolved")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :dependencies, :manifest, :repo_contents_path, :credentials
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_updaters/base"
|
4
|
+
require "dependabot/swift/file_updater/requirement_replacer"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Swift
|
8
|
+
class FileUpdater < FileUpdaters::Base
|
9
|
+
class ManifestUpdater
|
10
|
+
def initialize(content, old_requirements:, new_requirements:)
|
11
|
+
@content = content
|
12
|
+
@old_requirements = old_requirements
|
13
|
+
@new_requirements = new_requirements
|
14
|
+
end
|
15
|
+
|
16
|
+
def updated_manifest_content
|
17
|
+
updated_content = content
|
18
|
+
|
19
|
+
old_requirements.zip(new_requirements).each do |old, new|
|
20
|
+
updated_content = RequirementReplacer.new(
|
21
|
+
content: updated_content,
|
22
|
+
declaration: old[:metadata][:declaration_string],
|
23
|
+
old_requirement: old[:metadata][:requirement_string],
|
24
|
+
new_requirement: new[:metadata][:requirement_string]
|
25
|
+
).updated_content
|
26
|
+
end
|
27
|
+
|
28
|
+
updated_content
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :content, :old_requirements, :new_requirements
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_updaters/base"
|
4
|
+
|
5
|
+
module Dependabot
|
6
|
+
module Swift
|
7
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
8
|
+
class RequirementReplacer
|
9
|
+
def initialize(content:, declaration:, old_requirement:, new_requirement:)
|
10
|
+
@content = content
|
11
|
+
@declaration = declaration
|
12
|
+
@old_requirement = old_requirement
|
13
|
+
@new_requirement = new_requirement
|
14
|
+
end
|
15
|
+
|
16
|
+
def updated_content
|
17
|
+
content.gsub(declaration) do |match|
|
18
|
+
match.to_s.sub(old_requirement, new_requirement)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :content, :declaration, :old_requirement, :new_requirement
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_updaters"
|
4
|
+
require "dependabot/file_updaters/base"
|
5
|
+
require "dependabot/swift/file_updater/lockfile_updater"
|
6
|
+
require "dependabot/swift/file_updater/manifest_updater"
|
7
|
+
|
8
|
+
module Dependabot
|
9
|
+
module Swift
|
10
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
11
|
+
def self.updated_files_regex
|
12
|
+
[
|
13
|
+
/Package(@swift-\d(\.\d){0,2})?\.swift/,
|
14
|
+
/^Package\.resolved$/
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
def updated_dependency_files
|
19
|
+
updated_files = []
|
20
|
+
|
21
|
+
SharedHelpers.in_a_temporary_repo_directory(manifest.directory, repo_contents_path) do
|
22
|
+
updated_manifest = nil
|
23
|
+
|
24
|
+
if file_changed?(manifest)
|
25
|
+
updated_manifest = updated_file(file: manifest, content: updated_manifest_content)
|
26
|
+
updated_files << updated_manifest
|
27
|
+
end
|
28
|
+
|
29
|
+
updated_files << updated_file(file: lockfile, content: updated_lockfile_content(updated_manifest)) if lockfile
|
30
|
+
end
|
31
|
+
|
32
|
+
updated_files
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def dependency
|
38
|
+
# For now we will be updating a single dependency.
|
39
|
+
# TODO: Revisit when/if implementing full unlocks
|
40
|
+
dependencies.first
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_required_files
|
44
|
+
raise "A Package.swift file must be provided!" unless manifest
|
45
|
+
end
|
46
|
+
|
47
|
+
def updated_manifest_content
|
48
|
+
ManifestUpdater.new(
|
49
|
+
manifest.content,
|
50
|
+
old_requirements: dependency.previous_requirements,
|
51
|
+
new_requirements: dependency.requirements
|
52
|
+
).updated_manifest_content
|
53
|
+
end
|
54
|
+
|
55
|
+
def updated_lockfile_content(updated_manifest)
|
56
|
+
LockfileUpdater.new(
|
57
|
+
dependencies: dependencies,
|
58
|
+
manifest: updated_manifest || manifest,
|
59
|
+
repo_contents_path: repo_contents_path,
|
60
|
+
credentials: credentials
|
61
|
+
).updated_lockfile_content
|
62
|
+
end
|
63
|
+
|
64
|
+
def manifest
|
65
|
+
@manifest ||= get_original_file("Package.swift")
|
66
|
+
end
|
67
|
+
|
68
|
+
def lockfile
|
69
|
+
return @lockfile if defined?(@lockfile)
|
70
|
+
|
71
|
+
@lockfile = get_original_file("Package.resolved")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Dependabot::FileUpdaters.
|
78
|
+
register("swift", Dependabot::Swift::FileUpdater)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/metadata_finders"
|
4
|
+
require "dependabot/metadata_finders/base"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Swift
|
8
|
+
class MetadataFinder < Dependabot::MetadataFinders::Base
|
9
|
+
private
|
10
|
+
|
11
|
+
def look_up_source
|
12
|
+
case new_source_type
|
13
|
+
when "git" then find_source_from_git_url
|
14
|
+
when "registry" then find_source_from_registry
|
15
|
+
else raise "Unexpected source type: #{new_source_type}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_source_type
|
20
|
+
dependency.source_type
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_source_from_git_url
|
24
|
+
info = dependency.source_details
|
25
|
+
|
26
|
+
url = info[:url] || info.fetch("url")
|
27
|
+
Source.from_url(url)
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_source_from_registry
|
31
|
+
raise NotImplementedError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Dependabot::MetadataFinders.
|
38
|
+
register("swift", Dependabot::Swift::MetadataFinder)
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/utils"
|
4
|
+
require "dependabot/swift/requirement"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Swift
|
8
|
+
class NativeRequirement
|
9
|
+
attr_reader :declaration
|
10
|
+
|
11
|
+
def self.map_requirements(requirements)
|
12
|
+
requirements.map do |requirement|
|
13
|
+
declaration = new(requirement[:metadata][:requirement_string])
|
14
|
+
|
15
|
+
new_declaration = yield(declaration)
|
16
|
+
new_requirement = new(new_declaration)
|
17
|
+
|
18
|
+
requirement.merge(
|
19
|
+
requirement: new_requirement.to_s,
|
20
|
+
metadata: { requirement_string: new_declaration }
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(declaration)
|
26
|
+
@declaration = declaration
|
27
|
+
|
28
|
+
min, max = parse_declaration(declaration)
|
29
|
+
|
30
|
+
constraint = if min == max
|
31
|
+
["= #{min}"]
|
32
|
+
elsif closed_range?
|
33
|
+
[">= #{min}", "<= #{max}"]
|
34
|
+
else
|
35
|
+
[">= #{min}", "< #{max}"]
|
36
|
+
end
|
37
|
+
|
38
|
+
@min = min
|
39
|
+
@max = max
|
40
|
+
@requirement = Requirement.new(constraint)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
requirement.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_if_needed(version)
|
48
|
+
return declaration if requirement.satisfied_by?(version)
|
49
|
+
|
50
|
+
update(version)
|
51
|
+
end
|
52
|
+
|
53
|
+
def update(version)
|
54
|
+
if single_version_declaration?
|
55
|
+
declaration.sub(min, version.to_s)
|
56
|
+
elsif closed_range?
|
57
|
+
declaration.sub(max, version.to_s)
|
58
|
+
elsif range?
|
59
|
+
declaration.sub(max, bump_major(version.to_s))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def parse_declaration(declaration)
|
66
|
+
if up_to_next_major?
|
67
|
+
min = declaration.gsub(/\Afrom\s*:\s*"(\S+)"\s*\z/, '\1')
|
68
|
+
max = bump_major(min)
|
69
|
+
elsif up_to_next_major_deprecated?
|
70
|
+
min = declaration.gsub(/\A\.upToNextMajor\s*\(\s*from\s*:\s*"(\S+)"\s*\)\z/, '\1')
|
71
|
+
max = bump_major(min)
|
72
|
+
elsif up_to_next_minor_deprecated?
|
73
|
+
min = declaration.gsub(/\A\.upToNextMinor\s*\(\s*from\s*:\s*"(\S+)"\s*\)\z/, '\1')
|
74
|
+
max = bump_minor(min)
|
75
|
+
elsif closed_range?
|
76
|
+
min, max = parse_range("...")
|
77
|
+
elsif range?
|
78
|
+
min, max = parse_range("..<")
|
79
|
+
elsif exact_version?
|
80
|
+
min = declaration.gsub(/\Aexact\s*:\s*"(\S+)"\s*\z/, '\1')
|
81
|
+
max = min
|
82
|
+
elsif exact_version_deprecated?
|
83
|
+
min = declaration.gsub(/\A\.exact\s*\(\s*"(\S+)"\s*\)\z/, '\1')
|
84
|
+
max = min
|
85
|
+
else
|
86
|
+
raise "Unsupported constraint: #{declaration}"
|
87
|
+
end
|
88
|
+
|
89
|
+
[min, max]
|
90
|
+
end
|
91
|
+
|
92
|
+
def parse_range(separator)
|
93
|
+
declaration.split(separator).map { |str| unquote(str) }
|
94
|
+
end
|
95
|
+
|
96
|
+
def single_version_declaration?
|
97
|
+
up_to_next_major? || up_to_next_major_deprecated? || up_to_next_minor? ||
|
98
|
+
exact_version? || exact_version_deprecated?
|
99
|
+
end
|
100
|
+
|
101
|
+
def bump_major(str)
|
102
|
+
transform_version(str) do |s, i|
|
103
|
+
i.zero? ? s.to_i + 1 : 0
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def bump_minor(str)
|
108
|
+
transform_version(str) do |s, i|
|
109
|
+
if i.zero?
|
110
|
+
s
|
111
|
+
else
|
112
|
+
(i == 1 ? s.to_i + 1 : 0)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def transform_version(str, &block)
|
118
|
+
str.split(".").map.with_index(&block).join(".")
|
119
|
+
end
|
120
|
+
|
121
|
+
def up_to_next_major?
|
122
|
+
declaration.start_with?("from")
|
123
|
+
end
|
124
|
+
|
125
|
+
def up_to_next_major_deprecated?
|
126
|
+
declaration.start_with?(".upToNextMajor")
|
127
|
+
end
|
128
|
+
|
129
|
+
def up_to_next_minor_deprecated?
|
130
|
+
declaration.start_with?(".upToNextMinor")
|
131
|
+
end
|
132
|
+
|
133
|
+
def exact_version?
|
134
|
+
declaration.start_with?("exact")
|
135
|
+
end
|
136
|
+
|
137
|
+
def exact_version_deprecated?
|
138
|
+
declaration.start_with?(".exact")
|
139
|
+
end
|
140
|
+
|
141
|
+
def closed_range?
|
142
|
+
declaration.include?("...")
|
143
|
+
end
|
144
|
+
|
145
|
+
def range?
|
146
|
+
declaration.include?("..<")
|
147
|
+
end
|
148
|
+
|
149
|
+
attr_reader :min, :max, :requirement
|
150
|
+
|
151
|
+
def unquote(declaration)
|
152
|
+
declaration[1..-2]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
Dependabot::Utils.
|
159
|
+
register_requirement_class("swift", Dependabot::Swift::Requirement)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/utils"
|
4
|
+
|
5
|
+
module Dependabot
|
6
|
+
module Swift
|
7
|
+
class Requirement < Gem::Requirement
|
8
|
+
# For consistency with other languages, we define a requirements array.
|
9
|
+
# Swift doesn't have an `OR` separator for requirements, so it
|
10
|
+
# always contains a single element.
|
11
|
+
def self.requirements_array(requirement_string)
|
12
|
+
[new(requirement_string)]
|
13
|
+
end
|
14
|
+
|
15
|
+
# Patches Gem::Requirement to make it accept requirement strings like
|
16
|
+
# "~> 4.2.5, >= 4.2.5.1" without first needing to split them.
|
17
|
+
def initialize(*requirements)
|
18
|
+
requirements = requirements.flatten.flat_map do |req_string|
|
19
|
+
req_string.split(",").map(&:strip)
|
20
|
+
end
|
21
|
+
|
22
|
+
super(requirements)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Dependabot::Utils.
|
29
|
+
register_requirement_class("swift", Dependabot::Swift::Requirement)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/update_checkers/base"
|
4
|
+
require "dependabot/swift/native_requirement"
|
5
|
+
require "dependabot/swift/version"
|
6
|
+
|
7
|
+
module Dependabot
|
8
|
+
module Swift
|
9
|
+
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
10
|
+
class RequirementsUpdater
|
11
|
+
def initialize(requirements:, target_version:)
|
12
|
+
@requirements = requirements
|
13
|
+
|
14
|
+
return unless target_version && Version.correct?(target_version)
|
15
|
+
|
16
|
+
@target_version = Version.new(target_version)
|
17
|
+
end
|
18
|
+
|
19
|
+
def updated_requirements
|
20
|
+
NativeRequirement.map_requirements(requirements) do |requirement|
|
21
|
+
requirement.update_if_needed(target_version)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :requirements, :target_version
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/update_checkers/base"
|
4
|
+
require "dependabot/swift/file_parser/dependency_parser"
|
5
|
+
require "dependabot/swift/file_updater/lockfile_updater"
|
6
|
+
|
7
|
+
module Dependabot
|
8
|
+
module Swift
|
9
|
+
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
10
|
+
class VersionResolver
|
11
|
+
def initialize(dependency:, manifest:, repo_contents_path:, credentials:)
|
12
|
+
@dependency = dependency
|
13
|
+
@manifest = manifest
|
14
|
+
@credentials = credentials
|
15
|
+
@repo_contents_path = repo_contents_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def latest_resolvable_version
|
19
|
+
@latest_resolvable_version ||= fetch_latest_resolvable_version
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def fetch_latest_resolvable_version
|
25
|
+
updated_lockfile_content = FileUpdater::LockfileUpdater.new(
|
26
|
+
dependencies: [dependency],
|
27
|
+
manifest: manifest,
|
28
|
+
repo_contents_path: repo_contents_path,
|
29
|
+
credentials: credentials
|
30
|
+
).updated_lockfile_content
|
31
|
+
|
32
|
+
lockfile = DependencyFile.new(
|
33
|
+
name: "Package.resolved",
|
34
|
+
content: updated_lockfile_content
|
35
|
+
)
|
36
|
+
|
37
|
+
dependency_parser(manifest, lockfile).parse.find do |parsed_dep|
|
38
|
+
parsed_dep.name == dependency.name
|
39
|
+
end.version
|
40
|
+
end
|
41
|
+
|
42
|
+
def dependency_parser(manifest, lockfile)
|
43
|
+
FileParser::DependencyParser.new(
|
44
|
+
dependency_files: [manifest, lockfile],
|
45
|
+
repo_contents_path: repo_contents_path,
|
46
|
+
credentials: credentials
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :dependency, :manifest, :repo_contents_path, :credentials
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/update_checkers"
|
4
|
+
require "dependabot/update_checkers/base"
|
5
|
+
require "dependabot/git_commit_checker"
|
6
|
+
require "dependabot/swift/native_requirement"
|
7
|
+
require "dependabot/swift/file_updater/manifest_updater"
|
8
|
+
|
9
|
+
module Dependabot
|
10
|
+
module Swift
|
11
|
+
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
12
|
+
require_relative "update_checker/requirements_updater"
|
13
|
+
require_relative "update_checker/version_resolver"
|
14
|
+
|
15
|
+
def latest_version
|
16
|
+
@latest_version ||= fetch_latest_version
|
17
|
+
end
|
18
|
+
|
19
|
+
def latest_resolvable_version
|
20
|
+
@latest_resolvable_version ||= fetch_latest_resolvable_version
|
21
|
+
end
|
22
|
+
|
23
|
+
def latest_resolvable_version_with_no_unlock
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
def updated_requirements
|
28
|
+
RequirementsUpdater.new(
|
29
|
+
requirements: old_requirements,
|
30
|
+
target_version: preferred_resolvable_version
|
31
|
+
).updated_requirements
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def old_requirements
|
37
|
+
dependency.requirements
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch_latest_version
|
41
|
+
return unless git_commit_checker.pinned_ref_looks_like_version? && latest_version_tag
|
42
|
+
|
43
|
+
latest_version_tag.fetch(:version)
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_latest_resolvable_version
|
47
|
+
Version.new(version_resolver.latest_resolvable_version)
|
48
|
+
end
|
49
|
+
|
50
|
+
def version_resolver
|
51
|
+
VersionResolver.new(
|
52
|
+
dependency: dependency,
|
53
|
+
manifest: prepared_manifest,
|
54
|
+
repo_contents_path: repo_contents_path,
|
55
|
+
credentials: credentials
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def unlocked_requirements
|
60
|
+
NativeRequirement.map_requirements(old_requirements) do |_old_requirement|
|
61
|
+
"\"#{dependency.version}\"...\"#{latest_version}\""
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def prepared_manifest
|
66
|
+
DependencyFile.new(
|
67
|
+
name: manifest.name,
|
68
|
+
content: FileUpdater::ManifestUpdater.new(
|
69
|
+
manifest.content,
|
70
|
+
old_requirements: old_requirements,
|
71
|
+
new_requirements: unlocked_requirements
|
72
|
+
).updated_manifest_content
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def manifest
|
77
|
+
dependency_files.find { |file| file.name == "Package.swift" }
|
78
|
+
end
|
79
|
+
|
80
|
+
def latest_version_resolvable_with_full_unlock?
|
81
|
+
# Full unlock checks aren't implemented for Swift (yet)
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
def updated_dependencies_after_full_unlock
|
86
|
+
raise NotImplementedError
|
87
|
+
end
|
88
|
+
|
89
|
+
def git_commit_checker
|
90
|
+
@git_commit_checker ||= Dependabot::GitCommitChecker.new(
|
91
|
+
dependency: dependency,
|
92
|
+
credentials: credentials,
|
93
|
+
ignored_versions: ignored_versions,
|
94
|
+
raise_on_ignored: raise_on_ignored,
|
95
|
+
consider_version_branches_pinned: true
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def latest_version_tag
|
100
|
+
git_commit_checker.local_tag_for_latest_version
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
Dependabot::UpdateCheckers.
|
107
|
+
register("swift", Dependabot::Swift::UpdateChecker)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# These all need to be required so the various classes can be registered in a
|
4
|
+
# lookup table of package manager names to concrete classes.
|
5
|
+
require "dependabot/swift/file_fetcher"
|
6
|
+
require "dependabot/swift/file_parser"
|
7
|
+
require "dependabot/swift/update_checker"
|
8
|
+
require "dependabot/swift/file_updater"
|
9
|
+
require "dependabot/swift/metadata_finder"
|
10
|
+
require "dependabot/swift/requirement"
|
11
|
+
require "dependabot/swift/version"
|
12
|
+
|
13
|
+
require "dependabot/pull_request_creator/labeler"
|
14
|
+
Dependabot::PullRequestCreator::Labeler.
|
15
|
+
register_label_details("swift", name: "swift_package_manager", colour: "F05138")
|
16
|
+
|
17
|
+
require "dependabot/dependency"
|
18
|
+
Dependabot::Dependency.
|
19
|
+
register_production_check("swift", ->(_) { true })
|
20
|
+
|
21
|
+
require "dependabot/utils"
|
22
|
+
Dependabot::Utils.register_always_clone("swift")
|
metadata
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dependabot-swift
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.222.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dependabot
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-07-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dependabot-common
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.222.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.222.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: debug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.8.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: gpgme
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: parallel_tests
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 4.2.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 4.2.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.12'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.12'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-its
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.3'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.3'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.50.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.50.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-performance
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.17.1
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 1.17.1
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: stackprof
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.2.16
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.2.16
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: vcr
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '6.1'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '6.1'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: webmock
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '3.18'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '3.18'
|
181
|
+
description: Dependabot-Swift provides support for bumping Swift packages via Dependabot.
|
182
|
+
If you want support for multiple package managers, you probably want the meta-gem
|
183
|
+
dependabot-omnibus.
|
184
|
+
email: opensource@github.com
|
185
|
+
executables: []
|
186
|
+
extensions: []
|
187
|
+
extra_rdoc_files: []
|
188
|
+
files:
|
189
|
+
- lib/dependabot/swift.rb
|
190
|
+
- lib/dependabot/swift/file_fetcher.rb
|
191
|
+
- lib/dependabot/swift/file_parser.rb
|
192
|
+
- lib/dependabot/swift/file_parser/dependency_parser.rb
|
193
|
+
- lib/dependabot/swift/file_parser/manifest_parser.rb
|
194
|
+
- lib/dependabot/swift/file_updater.rb
|
195
|
+
- lib/dependabot/swift/file_updater/lockfile_updater.rb
|
196
|
+
- lib/dependabot/swift/file_updater/manifest_updater.rb
|
197
|
+
- lib/dependabot/swift/file_updater/requirement_replacer.rb
|
198
|
+
- lib/dependabot/swift/metadata_finder.rb
|
199
|
+
- lib/dependabot/swift/native_requirement.rb
|
200
|
+
- lib/dependabot/swift/requirement.rb
|
201
|
+
- lib/dependabot/swift/update_checker.rb
|
202
|
+
- lib/dependabot/swift/update_checker/requirements_updater.rb
|
203
|
+
- lib/dependabot/swift/update_checker/version_resolver.rb
|
204
|
+
- lib/dependabot/swift/version.rb
|
205
|
+
homepage: https://github.com/dependabot/dependabot-core
|
206
|
+
licenses:
|
207
|
+
- Nonstandard
|
208
|
+
metadata:
|
209
|
+
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
210
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.222.0
|
211
|
+
post_install_message:
|
212
|
+
rdoc_options: []
|
213
|
+
require_paths:
|
214
|
+
- lib
|
215
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - ">="
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: 3.1.0
|
220
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
|
+
requirements:
|
222
|
+
- - ">="
|
223
|
+
- !ruby/object:Gem::Version
|
224
|
+
version: 3.1.0
|
225
|
+
requirements: []
|
226
|
+
rubygems_version: 3.3.26
|
227
|
+
signing_key:
|
228
|
+
specification_version: 4
|
229
|
+
summary: Provides Dependabot support for Swift
|
230
|
+
test_files: []
|