danger-spm_version_updates 0.0.1

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.
data/Guardfile ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A guardfile for making Danger Plugins
4
+ # For more info see https://github.com/guard/guard#readme
5
+
6
+ # To run, use `bundle exec guard`.
7
+
8
+ guard :rspec, cmd: "bundle exec rspec" do
9
+ require "guard/rspec/dsl"
10
+ dsl = Guard::RSpec::Dsl.new(self)
11
+
12
+ # RSpec files
13
+ rspec = dsl.rspec
14
+ watch(rspec.spec_helper) { rspec.spec_dir }
15
+ watch(rspec.spec_support) { rspec.spec_dir }
16
+ watch(rspec.spec_files)
17
+
18
+ # Ruby files
19
+ ruby = dsl.ruby
20
+ dsl.watch_spec_files_for(ruby.lib_files)
21
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2023 Harold Martin <harold.martin@gmail.com>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # danger-spm_version_updates
2
+
3
+ [![CI](https://github.com/hbmartin/danger-spm_version_updates/actions/workflows/lint_and_test.yml/badge.svg)](https://github.com/hbmartin/danger-spm_version_updates/actions/workflows/lint_and_test.yml)
4
+ [![CodeFactor](https://www.codefactor.io/repository/github/hbmartin/danger-spm_version_updates/badge/main)](https://www.codefactor.io/repository/github/hbmartin/danger-spm_version_updates/overview/main)
5
+ [![Gem Version](https://badge.fury.io/rb/danger-spm_version_updates.svg)](https://badge.fury.io/rb/danger-spm_version_updates)
6
+
7
+
8
+ A [Danger](https://danger.systems/ruby/) plugin to detect if there are any updates to your Swift Package Manager dependencies.
9
+
10
+ It is lightweight and does not require swift to be installed on the CI where it is run.
11
+
12
+
13
+ ## Installation
14
+
15
+ $ gem install danger-spm_version_updates
16
+
17
+ or add the following to your Gemfile:
18
+
19
+
20
+ ```ruby
21
+ gem "danger-spm_version_updates"
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ Just add this to your Dangerfile! Note that it is required to configure the path to your Xcode project.
27
+
28
+ ```ruby
29
+ spm_version_updates.xcodeproj_path = ".../Example.xcodeproj"
30
+ spm_version_updates.check_for_updates
31
+ ```
32
+
33
+ You can also configure custom behaviors:
34
+
35
+ ```ruby
36
+ # Whether to check when dependencies are exact versions or commits, default false
37
+ spm_version_updates.check_when_exact = true
38
+
39
+ # Whether to ignore version above the maximum version range, default true
40
+ spm_version_updates.quiet_above_maximum = false
41
+
42
+ # A list of repositories to ignore entirely, must exactly match the URL as configured in the Xcode project
43
+ spm_version_updates.ignore_repositories = ["https://github.com/pointfreeco/swift-snapshot-testing"]
44
+ ```
45
+
46
+ ## Development
47
+
48
+ 1. Clone this repo
49
+ 2. Run `bundle install` to setup dependencies.
50
+ 3. Run `bundle exec rake spec` to run the tests.
51
+ 4. Use `bundle exec guard` to automatically have tests run as you make changes.
52
+ 5. Make your changes.
53
+
54
+
55
+ ## Authors
56
+
57
+ * [Harold Martin](https://www.linkedin.com/in/harold-martin-98526971/) - harold.martin at gmail
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "reek/rake/task"
5
+ require "rspec/core/rake_task"
6
+ require "rubocop/rake_task"
7
+
8
+ RSpec::Core::RakeTask.new(:specs)
9
+
10
+ task default: :specs
11
+
12
+ task :spec do
13
+ Rake::Task["specs"].invoke
14
+ Rake::Task["rubocop"].invoke
15
+ Rake::Task["spec_docs"].invoke
16
+ end
17
+
18
+ desc "Run RuboCop on the lib/specs directory"
19
+ RuboCop::RakeTask.new(:rubocop) { |task|
20
+ task.requires << "rubocop-rspec"
21
+ task.requires << "rubocop-rake"
22
+ task.patterns = ["lib/**/*.rb", "spec/**/*.rb"]
23
+ }
24
+
25
+ desc "Run Reek on the lib/specs directory"
26
+ Reek::Rake::Task.new(:reek) { |task|
27
+ task.source_files = FileList["lib/**/*.rb", "spec/**/*.rb"]
28
+ }
29
+
30
+ desc "Ensure that the plugin passes `danger plugins lint`"
31
+ task :spec_docs do
32
+ sh "bundle exec danger plugins lint"
33
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "spm_version_updates/gem_version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "danger-spm_version_updates"
9
+ spec.version = SpmVersionUpdates::VERSION
10
+ spec.authors = ["Harold Martin"]
11
+ spec.email = ["harold.martin@gmail.com"]
12
+ spec.description = "A Danger plugin to detect if there are any updates to your Swift Package Manager dependencies."
13
+ spec.summary = "A Danger plugin to detect if there are any updates to your Swift Package Manager dependencies."
14
+ spec.homepage = "https://github.com/hbmartin/danger-spm_version_updates"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency("danger-plugin-api", "~> 1.0")
23
+
24
+ # General ruby development
25
+ spec.add_development_dependency("bundler", "~> 2.0")
26
+ spec.add_development_dependency("rake", "~> 13.0")
27
+
28
+ # Testing support
29
+ spec.add_development_dependency("rspec", "~> 3.4")
30
+
31
+ # Linting code and docs
32
+ spec.add_development_dependency("reek")
33
+ spec.add_development_dependency("rubocop")
34
+ spec.add_development_dependency("rubocop-rake")
35
+ spec.add_development_dependency("rubocop-rspec")
36
+ spec.add_development_dependency("yard")
37
+
38
+ # Makes testing easy via `bundle exec guard`
39
+ spec.add_development_dependency("guard", "~> 2.14")
40
+ spec.add_development_dependency("guard-rspec", "~> 4.7")
41
+
42
+ # If you want to work on older builds of ruby
43
+ spec.add_development_dependency("listen", "3.0.7")
44
+
45
+ # This gives you the chance to run a REPL inside your tests
46
+ # via:
47
+ #
48
+ # require 'pry'
49
+ # binding.pry
50
+ #
51
+ # This will stop test execution and let you inspect the results
52
+ spec.add_development_dependency("pry")
53
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spm_version_updates/plugin"
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spm_version_updates/gem_version"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpmVersionUpdates
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "semantic"
4
+ require "xcodeproj"
5
+
6
+ module Danger
7
+ # @example Ensure people are well warned about merging on Mondays
8
+ #
9
+ # my_plugin.warn_on_mondays
10
+ #
11
+ # @see Harold Martin/danger-spm_version_updates
12
+ # @tags swift, spm, swift package manager, xcode, xcodeproj, version, updates
13
+ #
14
+ class DangerSpmVersionUpdates < Plugin
15
+ # The path to the xcodeproj file
16
+ # @return [String]
17
+ attr_accessor :xcodeproj_path
18
+
19
+ # Whether to check when dependencies are exact versions or commits, default false
20
+ # @return [Boolean]
21
+ attr_accessor :check_when_exact
22
+
23
+ # Whether to ignore version above the maximum version range, default true
24
+ # @return [Boolean]
25
+ attr_accessor :quiet_above_maximum
26
+
27
+ # A list of repositories to ignore entirely, must exactly match the URL as configured in the Xcode project
28
+ # @return [Array<String>]
29
+ attr_accessor :ignore_repos
30
+
31
+ def initialize(dangerfile)
32
+ super(dangerfile)
33
+ @check_when_exact = false
34
+ @quiet_above_maximum = false
35
+ @ignore_repos = []
36
+ end
37
+
38
+ # A method that you can call from your Dangerfile
39
+ # @return [Array<String>]
40
+ def check_for_updates
41
+ raise(XcodeprojPathMustBeSet) if xcodeproj_path.nil?
42
+
43
+ project = Xcodeproj::Project.open(xcodeproj_path)
44
+ remote_packages = filter_remote_packages(project)
45
+
46
+ resolved_path = find_packages_resolved
47
+ raise(CouldNotFindResolvedFile) unless File.exist?(resolved_path)
48
+
49
+ resolved_versions = JSON.load_file!(resolved_path)["pins"]
50
+ .to_h { |pin| [pin["location"], pin["state"]["version"] || pin["state"]["revision"]] }
51
+
52
+ remote_packages.each { |repository_url, requirement|
53
+ next if ignore_repos.include?(repository_url)
54
+
55
+ name = repo_name(repository_url)
56
+ resolved_version = resolved_versions[repository_url]
57
+ kind = requirement["kind"]
58
+
59
+ # kind can be major, minor, range, exact, branch, or commit
60
+
61
+ if kind == "branch" && check_when_exact
62
+ last_commit = git_branch_last_commit(repository_url, requirement["branch"])
63
+ warn("Newer commit available for #{name}: #{last_commit}") unless last_commit == resolved_version
64
+ next
65
+ end
66
+
67
+ available_versions = git_versions(repository_url)
68
+ next if available_versions.first.to_s == resolved_version
69
+
70
+ if kind == "exactVersion" && @check_when_exact
71
+ warn(
72
+ <<-TEXT
73
+ Newer version of #{name}: #{available_versions.first} (but this package is set to exact version #{resolved_version})
74
+ TEXT
75
+ )
76
+ elsif kind == "upToNextMajorVersion"
77
+ warn_for_new_versions(:major, available_versions, name, resolved_version)
78
+ elsif kind == "upToNextMinorVersion"
79
+ warn_for_new_versions(:minor, available_versions, name, resolved_version)
80
+ elsif kind == "range"
81
+ warn_for_new_versions_range(available_versions, name, requirement, resolved_version)
82
+ end
83
+ }
84
+ end
85
+
86
+ def repo_name(repo_url)
87
+ match = repo_url.match(%r{([\w-]+/[\w-]+)(.git)?$})
88
+
89
+ if match
90
+ match[1] || match[0]
91
+ else
92
+ repo_url
93
+ end
94
+ end
95
+
96
+ def filter_remote_packages(project)
97
+ project.objects.select { |obj|
98
+ obj.kind_of?(Xcodeproj::Project::Object::XCRemoteSwiftPackageReference) &&
99
+ obj.requirement["kind"] != "commit"
100
+ }
101
+ .to_h { |package| [package.repositoryURL, package.requirement] }
102
+ end
103
+
104
+ def find_packages_resolved
105
+ if Dir.exist?(xcodeproj_path.sub("xcodeproj", "xcworkspace"))
106
+ File.join(xcodeproj_path.sub("xcodeproj", "xcworkspace"), "xcshareddata", "swiftpm", "Package.resolved")
107
+ else
108
+ File.join(xcodeproj_path, "project.xcworkspace", "xcshareddata", "swiftpm", "Package.resolved")
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def warn_for_new_versions_range(available_versions, name, requirement, resolved_version)
115
+ max_version = Semantic::Version.new(requirement["maximumVersion"])
116
+ if available_versions.first < max_version
117
+ warn("Newer version of #{name}: #{available_versions.first}")
118
+ else
119
+ newest_meeting_reqs = available_versions.find { |version|
120
+ version < max_version
121
+ }
122
+ warn("Newer version of #{name}: #{newest_meeting_reqs} ") unless newest_meeting_reqs.to_s == resolved_version
123
+ warn(
124
+ <<-TEXT
125
+ Newest version of #{name}: #{available_versions.first} (but this package is configured up to the next #{max_version} version)
126
+ TEXT
127
+ ) unless quiet_above_maximum
128
+ end
129
+ end
130
+
131
+ def warn_for_new_versions(major_or_minor, available_versions, name, resolved_version_string)
132
+ resolved_version = Semantic::Version.new(resolved_version_string)
133
+ if available_versions.first.send(major_or_minor) == resolved_version.send(major_or_minor)
134
+ warn("Newer version of #{name}: #{available_versions.first}")
135
+ else
136
+ newest_meeting_reqs = available_versions.find { |version|
137
+ version.send(major_or_minor) == resolved_version.send(major_or_minor)
138
+ }
139
+ warn("Newer version of #{name}: #{newest_meeting_reqs}") unless newest_meeting_reqs == resolved_version
140
+ warn(
141
+ <<-TEXT
142
+ Newest version of #{name}: #{available_versions.first} (but this package is configured up to the next #{major_or_minor} version)
143
+ TEXT
144
+ ) unless quiet_above_maximum
145
+ end
146
+ end
147
+
148
+ def git_versions(repo_url)
149
+ `git ls-remote -t #{repo_url}`
150
+ .split("\n")
151
+ .map { |line| line.split("/tags/").last }
152
+ .filter_map { |line|
153
+ begin
154
+ Semantic::Version.new(line)
155
+ rescue ArgumentError
156
+ nil
157
+ end
158
+ }
159
+ .sort
160
+ .reverse
161
+ end
162
+
163
+ def git_branch_last_commit(repo_url, branch_name)
164
+ `git ls-remote -h #{repo_url}`
165
+ .split("\n")
166
+ .find { |line| line.split("\trefs/heads/")[1] == branch_name }
167
+ .split("\trefs/heads/")[0]
168
+ end
169
+ end
170
+
171
+ class XcodeprojPathMustBeSet < StandardError
172
+ end
173
+
174
+ class CouldNotFindResolvedFile < StandardError
175
+ end
176
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ ROOT = Pathname.new(File.expand_path("..", __dir__))
5
+ $:.unshift("#{ROOT}lib".to_s)
6
+ $:.unshift("#{ROOT}spec".to_s)
7
+
8
+ require "bundler/setup"
9
+ require "pry"
10
+
11
+ require "danger"
12
+ require "rspec"
13
+
14
+ if `git remote -v` == ""
15
+ puts "You cannot run tests without setting a local git remote on this repo"
16
+ puts "It's a weird side-effect of Danger's internals."
17
+ exit(0)
18
+ end
19
+
20
+ # Use coloured output, it's the best.
21
+ RSpec.configure do |config|
22
+ config.filter_gems_from_backtrace("bundler")
23
+ config.color = true
24
+ config.tty = true
25
+ end
26
+
27
+ require "danger_plugin"
28
+
29
+ # These functions are a subset of https://github.com/danger/danger/blob/master/spec/spec_helper.rb
30
+ # If you are expanding these files, see if it's already been done ^.
31
+
32
+ # A silent version of the user interface,
33
+ # it comes with an extra function `.string` which will
34
+ # strip all ANSI colours from the string.
35
+
36
+ # rubocop:disable Lint/NestedMethodDefinition
37
+ def testing_ui
38
+ @output = StringIO.new
39
+ def @output.winsize
40
+ [20, 9999]
41
+ end
42
+
43
+ cork = Cork::Board.new(out: @output)
44
+ def cork.string
45
+ out.string.gsub(/\e\[([;\d]+)?m/, "")
46
+ end
47
+ cork
48
+ end
49
+ # rubocop:enable Lint/NestedMethodDefinition
50
+
51
+ # Example environment (ENV) that would come from
52
+ # running a PR on TravisCI
53
+ def testing_env
54
+ {
55
+ "HAS_JOSH_K_SEAL_OF_APPROVAL" => "true",
56
+ "TRAVIS_PULL_REQUEST" => "800",
57
+ "TRAVIS_REPO_SLUG" => "artsy/eigen",
58
+ "TRAVIS_COMMIT_RANGE" => "759adcbd0d8f...13c4dc8bb61d",
59
+ "DANGER_GITHUB_API_TOKEN" => "123sbdq54erfsd3422gdfio"
60
+ }
61
+ end
62
+
63
+ # A stubbed out Dangerfile for use in tests
64
+ def testing_dangerfile
65
+ env = Danger::EnvironmentManager.new(testing_env)
66
+ Danger::Dangerfile.new(env, testing_ui)
67
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("spec_helper", __dir__)
4
+
5
+ module Danger
6
+ describe Danger::DangerSpmVersionUpdates do
7
+ it "is a plugin" do
8
+ expect(described_class.new(nil)).to be_a Danger::Plugin
9
+ end
10
+
11
+ #
12
+ # You should test your custom attributes and methods here
13
+ #
14
+ describe "with Dangerfile" do
15
+ before do
16
+ @dangerfile = testing_dangerfile
17
+ @my_plugin = @dangerfile.spm_version_updates
18
+
19
+ # mock the PR data
20
+ # you can then use this, eg. github.pr_author, later in the spec
21
+ json = File.read("#{File.dirname(__FILE__)}/support/fixtures/github_pr.json") # example json: `curl https://api.github.com/repos/danger/danger-plugin-template/pulls/18 > github_pr.json`
22
+ allow(@my_plugin.github).to receive(:pr_json).and_return(json)
23
+ end
24
+
25
+ it "raises error if xcodeproj_path is not set" do
26
+ expect { @my_plugin.check_for_updates }
27
+ .to raise_error(Danger::XcodeprojPathMustBeSet)
28
+ end
29
+
30
+ it "Reports none without exact version matching" do
31
+ monday_date = Date.parse("2016-07-11")
32
+ allow(Date).to receive(:today).and_return monday_date
33
+
34
+ @my_plugin.xcodeproj_path = "#{File.dirname(__FILE__)}/support/fixtures/Example.xcodeproj"
35
+ @my_plugin.check_for_updates
36
+
37
+ expect(@dangerfile.status_report[:warnings]).to eq([])
38
+ end
39
+
40
+ it "Reports some with exact version matching" do
41
+ # TODO: mock git calls
42
+ # allow(@my_plugin).to receive(:git_versions).and_return false
43
+
44
+ @my_plugin.xcodeproj_path = "#{File.dirname(__FILE__)}/support/fixtures/Example.xcodeproj"
45
+ @my_plugin.check_when_exact = true
46
+ @my_plugin.check_for_updates
47
+
48
+ expect(@dangerfile.status_report[:warnings]).to eq(
49
+ [
50
+ "Newer version of pointfreeco/swift-snapshot-testing: 1.14.2 (but this package is set to exact version 1.13.0)\n",
51
+ "Newer version of kean/Nuke: 12.2.0-beta.2 (but this package is set to exact version 12.1.6)\n",
52
+ "Newer version of pointfreeco/swiftui-navigation: 1.0.3 (but this package is set to exact version 1.0.2)\n",
53
+ "Newer version of getsentry/sentry-cocoa: 8.14.2 (but this package is set to exact version 8.12.0)\n",
54
+ "Newer version of firebase/firebase-ios-sdk: 10.17.0 (but this package is set to exact version 10.15.0)\n",
55
+ ]
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,152 @@
1
+ // !$*UTF8*$!
2
+ {
3
+ archiveVersion = 1;
4
+ classes = {
5
+ };
6
+ objectVersion = 54;
7
+ objects = {
8
+ /* Begin PBXGroup section */
9
+ F1465EF423AA94BF0055F7C3 = {
10
+ isa = PBXGroup;
11
+ children = (
12
+ F1465EFF23AA94BF0055F7C3 /* Demo */,
13
+ );
14
+ sourceTree = "<group>";
15
+ };
16
+ F1465EFF23AA94BF0055F7C3 /* Demo */ = {
17
+ isa = PBXGroup;
18
+ children = ();
19
+ path = Demo;
20
+ sourceTree = "<group>";
21
+ };
22
+ /* End PBXGroup section */
23
+
24
+ /* Begin PBXProject section */
25
+ F1465EF523AA94BF0055F7C3 /* Project object */ = {
26
+ isa = PBXProject;
27
+ attributes = {
28
+ BuildIndependentTargetsInParallel = YES;
29
+ LastSwiftUpdateCheck = 1420;
30
+ LastUpgradeCheck = 1420;
31
+ TargetAttributes = {
32
+ F1465EFC23AA94BF0055F7C3 = {
33
+ CreatedOnToolsVersion = 11.2.1;
34
+ };
35
+ };
36
+ };
37
+ buildConfigurationList = F1465EF823AA94BF0055F7C3 /* Build configuration list for PBXProject "Demo" */;
38
+ compatibilityVersion = "Xcode 9.3";
39
+ developmentRegion = en;
40
+ hasScannedForEncodings = 0;
41
+ knownRegions = (
42
+ en,
43
+ Base,
44
+ es,
45
+ "zh-Hans",
46
+ fr,
47
+ );
48
+ mainGroup = F1465EF423AA94BF0055F7C3;
49
+ packageReferences = (
50
+ 115E40CB29B6D0EC00887A45 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
51
+ 11BBD37629C1571400F7A968 /* XCRemoteSwiftPackageReference "Nuke" */,
52
+ 11B8EE072A01A5AA00201115 /* XCRemoteSwiftPackageReference "maplibre-gl-native-distribution" */,
53
+ 116B05982A66192400EB92A4 /* XCRemoteSwiftPackageReference "swiftui-navigation" */,
54
+ F21242692A88338C005407A6 /* XCRemoteSwiftPackageReference "sentry-cocoa" */,
55
+ 1179CA742AAF97DB006EF58C /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
56
+ 112F9EF52ABD298C003D2CE6 /* XCRemoteSwiftPackageReference "LookingGlassUI" */,
57
+ CA7732012ADDBF49009F6B1B /* XCRemoteSwiftPackageReference "PhoneNumberKit" */,
58
+ F2C780582AEDB44700588969 /* XCRemoteSwiftPackageReference "analytics-swift" */,
59
+ );
60
+ productRefGroup = F1465EFE23AA94BF0055F7C3 /* Products */;
61
+ projectDirPath = "";
62
+ projectRoot = "";
63
+ targets = ();
64
+ };
65
+ /* End PBXProject section */
66
+
67
+ /* Begin XCConfigurationList section */
68
+ F1465EF823AA94BF0055F7C3 /* Build configuration list for PBXNativeTarget "Demo" */ = {
69
+ isa = XCConfigurationList;
70
+ buildConfigurations = ();
71
+ defaultConfigurationIsVisible = 0;
72
+ defaultConfigurationName = Release;
73
+ };
74
+ /* End XCConfigurationList section */
75
+
76
+ /* Begin XCRemoteSwiftPackageReference section */
77
+ 112F9EF52ABD298C003D2CE6 /* XCRemoteSwiftPackageReference "LookingGlassUI" */ = {
78
+ isa = XCRemoteSwiftPackageReference;
79
+ repositoryURL = "https://github.com/ryanlintott/LookingGlassUI";
80
+ requirement = {
81
+ kind = upToNextMajorVersion;
82
+ minimumVersion = 0.3.1;
83
+ };
84
+ };
85
+ 115E40CB29B6D0EC00887A45 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = {
86
+ isa = XCRemoteSwiftPackageReference;
87
+ repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing";
88
+ requirement = {
89
+ kind = exactVersion;
90
+ version = 1.13.0;
91
+ };
92
+ };
93
+ 116B05982A66192400EB92A4 /* XCRemoteSwiftPackageReference "swiftui-navigation" */ = {
94
+ isa = XCRemoteSwiftPackageReference;
95
+ repositoryURL = "https://github.com/pointfreeco/swiftui-navigation";
96
+ requirement = {
97
+ kind = exactVersion;
98
+ version = 1.0.2;
99
+ };
100
+ };
101
+ 1179CA742AAF97DB006EF58C /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
102
+ isa = XCRemoteSwiftPackageReference;
103
+ repositoryURL = "https://github.com/firebase/firebase-ios-sdk";
104
+ requirement = {
105
+ kind = exactVersion;
106
+ version = 10.15.0;
107
+ };
108
+ };
109
+ 11B8EE072A01A5AA00201115 /* XCRemoteSwiftPackageReference "maplibre-gl-native-distribution" */ = {
110
+ isa = XCRemoteSwiftPackageReference;
111
+ repositoryURL = "https://github.com/maplibre/maplibre-gl-native-distribution";
112
+ requirement = {
113
+ kind = exactVersion;
114
+ version = 5.13.0;
115
+ };
116
+ };
117
+ 11BBD37629C1571400F7A968 /* XCRemoteSwiftPackageReference "Nuke" */ = {
118
+ isa = XCRemoteSwiftPackageReference;
119
+ repositoryURL = "https://github.com/kean/Nuke";
120
+ requirement = {
121
+ kind = exactVersion;
122
+ version = 12.1.6;
123
+ };
124
+ };
125
+ CA7732012ADDBF49009F6B1B /* XCRemoteSwiftPackageReference "PhoneNumberKit" */ = {
126
+ isa = XCRemoteSwiftPackageReference;
127
+ repositoryURL = "https://github.com/marmelroy/PhoneNumberKit.git";
128
+ requirement = {
129
+ kind = upToNextMajorVersion;
130
+ minimumVersion = 3.7.4;
131
+ };
132
+ };
133
+ F21242692A88338C005407A6 /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = {
134
+ isa = XCRemoteSwiftPackageReference;
135
+ repositoryURL = "https://github.com/getsentry/sentry-cocoa.git";
136
+ requirement = {
137
+ kind = exactVersion;
138
+ version = 8.12.0;
139
+ };
140
+ };
141
+ F2C780582AEDB44700588969 /* XCRemoteSwiftPackageReference "analytics-swift" */ = {
142
+ isa = XCRemoteSwiftPackageReference;
143
+ repositoryURL = "git@github.com:hbmartin/analytics-swift.git";
144
+ requirement = {
145
+ branch = main;
146
+ kind = branch;
147
+ };
148
+ };
149
+ /* End XCRemoteSwiftPackageReference section */
150
+ };
151
+ rootObject = F1465EF523AA94BF0055F7C3 /* Project object */;
152
+ }