From 99ca87adcd7ac6f99a613874942a11acb97ece1b Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 14 May 2021 12:12:33 -0700 Subject: [PATCH 01/14] Initial support for Swift Package Manager --- README.md | 1 + docs/sources/swift.md | 4 + lib/licensed/sources.rb | 1 + lib/licensed/sources/swift.rb | 79 +++++++++++++++++++ script/source-setup/swift | 9 +++ test/fixtures/command/swift.yml | 5 ++ test/fixtures/swift/Package.resolved | 16 ++++ test/fixtures/swift/Package.swift | 28 +++++++ .../swift/Sources/Fixtures/Fixture.swift | 0 test/sources/swift_test.rb | 46 +++++++++++ 10 files changed, 189 insertions(+) create mode 100644 docs/sources/swift.md create mode 100644 lib/licensed/sources/swift.rb create mode 100755 script/source-setup/swift create mode 100644 test/fixtures/command/swift.yml create mode 100644 test/fixtures/swift/Package.resolved create mode 100644 test/fixtures/swift/Package.swift create mode 100644 test/fixtures/swift/Sources/Fixtures/Fixture.swift create mode 100644 test/sources/swift_test.rb diff --git a/README.md b/README.md index 5747ba45..8a19722c 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ Dependencies will be automatically detected for all of the following sources by 1. [NuGet](./docs/sources/nuget.md) 1. [Pip](./docs/sources/pip.md) 1. [Pipenv](./docs/sources/pipenv.md) +1. [Swift](./docs/sources/swift.md) 1. [Yarn](./docs/sources/yarn.md) You can disable any of them in the configuration file: diff --git a/docs/sources/swift.md b/docs/sources/swift.md new file mode 100644 index 00000000..5d8b5fef --- /dev/null +++ b/docs/sources/swift.md @@ -0,0 +1,4 @@ +# Swift + +The Swift source uses `swift package` subcommands +to enumerate dependencies and properties. diff --git a/lib/licensed/sources.rb b/lib/licensed/sources.rb index 0b69033c..e19989c4 100644 --- a/lib/licensed/sources.rb +++ b/lib/licensed/sources.rb @@ -14,6 +14,7 @@ module Sources require "licensed/sources/nuget" require "licensed/sources/pip" require "licensed/sources/pipenv" + require "licensed/sources/swift" require "licensed/sources/gradle" require "licensed/sources/mix" require "licensed/sources/yarn" diff --git a/lib/licensed/sources/swift.rb b/lib/licensed/sources/swift.rb new file mode 100644 index 00000000..03e3e25c --- /dev/null +++ b/lib/licensed/sources/swift.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true +require "json" +require "pathname" +require "licensed/sources/helpers/content_versioning" + +module Licensed + module Sources + class Swift < Source + include Licensed::Sources::ContentVersioning + + class Dependency < Licensed::Dependency + attr_reader :url + + def initialize(name:, url:, version:, path:, search_root: nil, errors: [], metadata: {}) + @url = url + super name: name, version: version, path: path, errors: errors, metadata: metadata, search_root: search_root + end + end + + def enabled? + Licensed::Shell.tool_available?("swift") && swift_package? + end + + def enumerate_dependencies + Hash[declarations.map { |d| [d.url, d] }] + .merge(Hash[pins.map { |d| [d.url, d] }]) + .values + end + + private + + def declarations + return @declarations if defined?(@declarations) + + @declarations = begin + json = JSON.parse(dump_package_command) + json["dependencies"].map do |dependency| + Dependency.new( + name: dependency["name"], + url: dependency["url"], + path: "/Package.swift", + version: dependency.dig("requirement", "exact") || + dependency.dig("requirement", "range")&.first&.fetch("lowerBound") || + dependency.dig("requirement", "range")&.first&.fetch("upperBound") + ) + end + end || [] + end + + def pins + return @pins if defined?(@pins) + + @pins = begin + file = "Package.resolved" + return unless File.exist?(file) + + json = JSON.parse(File.read(file)) + json.dig("object", "pins").map do |pin| + Dependency.new( + name: pin["package"], + url: pin["repositoryURL"], + path: "/Package.resolved", + version: pin.dig("state", "version") + ) + end + end || [] + end + + def dump_package_command + args = %w(--skip-update) + Licensed::Shell.execute("swift", "package", "dump-package", *args) + end + + def swift_package? + Licensed::Shell.success?("swift", "package", "describe") + end + end + end +end diff --git a/script/source-setup/swift b/script/source-setup/swift new file mode 100755 index 00000000..25bcde8e --- /dev/null +++ b/script/source-setup/swift @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +if [ -z "$(which swift)" ]; then + echo "A local swift installation is required for swift development." >&2 + exit 127 +fi + +swift --version diff --git a/test/fixtures/command/swift.yml b/test/fixtures/command/swift.yml new file mode 100644 index 00000000..01f9ad02 --- /dev/null +++ b/test/fixtures/command/swift.yml @@ -0,0 +1,5 @@ +expected_dependency: LinkedList +source_path: test/fixtures/swift +cache_path: test/fixtures/swift/.licenses +sources: + swift: true diff --git a/test/fixtures/swift/Package.resolved b/test/fixtures/swift/Package.resolved new file mode 100644 index 00000000..3102e65b --- /dev/null +++ b/test/fixtures/swift/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "LinkedList", + "repositoryURL": "https://github.com/mona/LinkedList.git", + "state": { + "branch": null, + "revision": "cfdacae39417d7a987f63a0ea5335a80b16d4659", + "version": "1.2.1" + } + } + ] + }, + "version": 1 +} diff --git a/test/fixtures/swift/Package.swift b/test/fixtures/swift/Package.swift new file mode 100644 index 00000000..3e47fee9 --- /dev/null +++ b/test/fixtures/swift/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Fixtures", + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "Fixtures", + targets: ["Fixtures"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(url: "https://github.com/mona/LinkedList.git", from: "1.2.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "Fixtures", + dependencies: []), + .testTarget( + name: "FixturesTests", + dependencies: ["Fixtures"]), + ] +) diff --git a/test/fixtures/swift/Sources/Fixtures/Fixture.swift b/test/fixtures/swift/Sources/Fixtures/Fixture.swift new file mode 100644 index 00000000..e69de29b diff --git a/test/sources/swift_test.rb b/test/sources/swift_test.rb new file mode 100644 index 00000000..257b8da9 --- /dev/null +++ b/test/sources/swift_test.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true +require "test_helper" +require "tmpdir" + +if Licensed::Shell.tool_available?("swift") + describe Licensed::Sources::Swift do + let(:fixtures) { File.expand_path("../../fixtures/swift", __FILE__) } + let(:config) { Licensed::AppConfiguration.new({ "source_path" => Dir.pwd }) } + let(:source) { Licensed::Sources::Swift.new(config) } + + describe "enabled?" do + it "is true if Swift package exists" do + Dir.chdir(fixtures) do + assert source.enabled? + end + end + + it "is false if Swift package doesn't exist" do + Dir.chdir(Dir.tmpdir) do + refute source.enabled? + end + end + end + + describe "enumerate_dependencies" do + it "does not include the source project" do + Dir.chdir(fixtures) do + config["name"] = "Fixtures" + refute source.enumerate_dependencies.find { |d| d.name == "Fixtures" } + end + end + + it "finds dependencies from path sources" do + Dir.chdir(fixtures) do + dep = source.enumerate_dependencies.find { |d| d.name == "LinkedList" } + assert dep + assert_equal "1.2.1", dep.version + assert_equal "https://github.com/mona/LinkedList.git", dep.url + + dep = source.enumerate_dependencies.find { |d| d.name == "Invalid" } + refute dep + end + end + end + end +end From 227b655197401a8204ac6b2868adac36e5cc99ec Mon Sep 17 00:00:00 2001 From: Mattt Date: Wed, 19 May 2021 05:36:32 -0700 Subject: [PATCH 02/14] Add swift job to test workflow --- .github/workflows/test.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 66d79907..093dc037 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -362,6 +362,30 @@ jobs: - name: Run tests run: script/test pipenv + swift: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Swift + uses: fwal/setup-swift@v1 + with: + swift-version: "5.4" + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.6 + - run: bundle lock + - uses: actions/cache@v1 + with: + path: vendor/gems + key: ${{ runner.os }}-gem-2.6.x-${{ hashFiles('**/Gemfile.lock') }} + - name: Bootstrap + run: script/bootstrap + - name: Set up fixtures + run: script/source-setup/swift + - name: Run tests + run: script/test swift + yarn: runs-on: ubuntu-latest strategy: From 62dd82b54b39790f9f62bf613f3d21b237af83da Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 21 May 2021 12:01:17 -0700 Subject: [PATCH 03/14] Update source-setup command for Swift --- script/source-setup/swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/script/source-setup/swift b/script/source-setup/swift index 25bcde8e..0babac39 100755 --- a/script/source-setup/swift +++ b/script/source-setup/swift @@ -7,3 +7,13 @@ if [ -z "$(which swift)" ]; then fi swift --version + +if [ "$1" == "-f" ]; then + find . -not -regex "\.*" \ + -and -not -path "*/Package.swift" \ + -and -not -path "*/Sources*" \ + -and -not -path "*/Tests*" \ + -print0 | xargs -0 rm -rf +fi + +swift package resolve From 3db2889fee1616888924e7fe402408c48cfc2fb8 Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 21 May 2021 12:01:35 -0700 Subject: [PATCH 04/14] Update test fixtures for Swift --- test/fixtures/command/swift.yml | 2 +- test/fixtures/swift/Package.resolved | 26 ++++++++++++++++--- test/fixtures/swift/Package.swift | 9 ++++--- .../swift/Sources/Fixtures/Fixture.swift | 3 +++ .../Tests/FixturesTests/FixturesTests.swift | 8 ++++++ 5 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 test/fixtures/swift/Tests/FixturesTests/FixturesTests.swift diff --git a/test/fixtures/command/swift.yml b/test/fixtures/command/swift.yml index 01f9ad02..55615783 100644 --- a/test/fixtures/command/swift.yml +++ b/test/fixtures/command/swift.yml @@ -1,4 +1,4 @@ -expected_dependency: LinkedList +expected_dependency: DeckOfPlayingCards source_path: test/fixtures/swift cache_path: test/fixtures/swift/.licenses sources: diff --git a/test/fixtures/swift/Package.resolved b/test/fixtures/swift/Package.resolved index 3102e65b..0ae8167d 100644 --- a/test/fixtures/swift/Package.resolved +++ b/test/fixtures/swift/Package.resolved @@ -2,12 +2,30 @@ "object": { "pins": [ { - "package": "LinkedList", - "repositoryURL": "https://github.com/mona/LinkedList.git", + "package": "DeckOfPlayingCards", + "repositoryURL": "https://github.com/apple/example-package-deckofplayingcards.git", "state": { "branch": null, - "revision": "cfdacae39417d7a987f63a0ea5335a80b16d4659", - "version": "1.2.1" + "revision": "2c0e5ac3e10216151fc78ac1ec6bd9c2c0111a3a", + "version": "3.0.4" + } + }, + { + "package": "FisherYates", + "repositoryURL": "https://github.com/apple/example-package-fisheryates.git", + "state": { + "branch": null, + "revision": "e729f197bbc3831b9a3005fa71ad6f38c1e7e17e", + "version": "2.0.6" + } + }, + { + "package": "PlayingCard", + "repositoryURL": "https://github.com/apple/example-package-playingcard.git", + "state": { + "branch": null, + "revision": "39ddabb01e8102ab548a8c6bb3eb20b15f3b4fbc", + "version": "3.0.5" } } ] diff --git a/test/fixtures/swift/Package.swift b/test/fixtures/swift/Package.swift index 3e47fee9..75c60cfe 100644 --- a/test/fixtures/swift/Package.swift +++ b/test/fixtures/swift/Package.swift @@ -12,15 +12,18 @@ let package = Package( targets: ["Fixtures"]), ], dependencies: [ - // Dependencies declare other packages that this package depends on. - .package(url: "https://github.com/mona/LinkedList.git", from: "1.2.0"), + .package(name: "DeckOfPlayingCards", + url: "https://github.com/apple/example-package-deckofplayingcards.git", + from: "3.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Fixtures", - dependencies: []), + dependencies: [ + .product(name: "DeckOfPlayingCards", package: "DeckOfPlayingCards") + ]), .testTarget( name: "FixturesTests", dependencies: ["Fixtures"]), diff --git a/test/fixtures/swift/Sources/Fixtures/Fixture.swift b/test/fixtures/swift/Sources/Fixtures/Fixture.swift index e69de29b..6aee6b33 100644 --- a/test/fixtures/swift/Sources/Fixtures/Fixture.swift +++ b/test/fixtures/swift/Sources/Fixtures/Fixture.swift @@ -0,0 +1,3 @@ +public struct Fixture { + public init() {} +} diff --git a/test/fixtures/swift/Tests/FixturesTests/FixturesTests.swift b/test/fixtures/swift/Tests/FixturesTests/FixturesTests.swift new file mode 100644 index 00000000..cfd51a14 --- /dev/null +++ b/test/fixtures/swift/Tests/FixturesTests/FixturesTests.swift @@ -0,0 +1,8 @@ +import XCTest +import Fixtures + +class FixturesTests: XCTestCase { + func testFixtures() { + XCTAssertNotNil(Fixture()) + } +} From e3192e5ac28b3af9323a507221e081a3c9e4a2e5 Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 21 May 2021 12:02:30 -0700 Subject: [PATCH 05/14] Update Swift implementation --- lib/licensed/sources/swift.rb | 68 +++++++++++------------------------ test/sources/swift_test.rb | 13 +++++-- 2 files changed, 30 insertions(+), 51 deletions(-) diff --git a/lib/licensed/sources/swift.rb b/lib/licensed/sources/swift.rb index 03e3e25c..454483a8 100644 --- a/lib/licensed/sources/swift.rb +++ b/lib/licensed/sources/swift.rb @@ -1,74 +1,46 @@ # frozen_string_literal: true require "json" require "pathname" +require "uri" + require "licensed/sources/helpers/content_versioning" module Licensed module Sources class Swift < Source - include Licensed::Sources::ContentVersioning - - class Dependency < Licensed::Dependency - attr_reader :url - - def initialize(name:, url:, version:, path:, search_root: nil, errors: [], metadata: {}) - @url = url - super name: name, version: version, path: path, errors: errors, metadata: metadata, search_root: search_root - end - end - def enabled? - Licensed::Shell.tool_available?("swift") && swift_package? + return unless Licensed::Shell.tool_available?("swift") && swift_package? + File.exist?(package_resolved_file_path) end def enumerate_dependencies - Hash[declarations.map { |d| [d.url, d] }] - .merge(Hash[pins.map { |d| [d.url, d] }]) - .values + pins.map { |pin| + Dependency.new( + name: pin["package"], + path: dependency_path_for_url(pin["repositoryURL"]), + version: pin.dig("state", "version") + ) + } end private - def declarations - return @declarations if defined?(@declarations) - - @declarations = begin - json = JSON.parse(dump_package_command) - json["dependencies"].map do |dependency| - Dependency.new( - name: dependency["name"], - url: dependency["url"], - path: "/Package.swift", - version: dependency.dig("requirement", "exact") || - dependency.dig("requirement", "range")&.first&.fetch("lowerBound") || - dependency.dig("requirement", "range")&.first&.fetch("upperBound") - ) - end - end || [] - end - def pins return @pins if defined?(@pins) @pins = begin - file = "Package.resolved" - return unless File.exist?(file) + json = JSON.parse(File.read(package_resolved_file_path)) + json.dig("object", "pins") + end + end - json = JSON.parse(File.read(file)) - json.dig("object", "pins").map do |pin| - Dependency.new( - name: pin["package"], - url: pin["repositoryURL"], - path: "/Package.resolved", - version: pin.dig("state", "version") - ) - end - end || [] + def dependency_path_for_url(url) + last_path_component = URI(url).path.split('/').last.sub(/\.git$/, '') + File.join(config.pwd, ".build", "checkouts", last_path_component) end - def dump_package_command - args = %w(--skip-update) - Licensed::Shell.execute("swift", "package", "dump-package", *args) + def package_resolved_file_path + File.join(config.pwd, "Package.resolved") end def swift_package? diff --git a/test/sources/swift_test.rb b/test/sources/swift_test.rb index 257b8da9..19d79d32 100644 --- a/test/sources/swift_test.rb +++ b/test/sources/swift_test.rb @@ -32,10 +32,17 @@ it "finds dependencies from path sources" do Dir.chdir(fixtures) do - dep = source.enumerate_dependencies.find { |d| d.name == "LinkedList" } + dep = source.enumerate_dependencies.find { |d| d.name == "DeckOfPlayingCards" } assert dep - assert_equal "1.2.1", dep.version - assert_equal "https://github.com/mona/LinkedList.git", dep.url + assert_equal "3.0.4", dep.version + + dep = source.enumerate_dependencies.find { |d| d.name == "FisherYates" } + assert dep + assert_equal "2.0.6", dep.version + + dep = source.enumerate_dependencies.find { |d| d.name == "PlayingCard" } + assert dep + assert_equal "3.0.5", dep.version dep = source.enumerate_dependencies.find { |d| d.name == "Invalid" } refute dep From daf03e15297a4b629786bd0f3f02ed16efb1ae74 Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 21 May 2021 12:08:12 -0700 Subject: [PATCH 06/14] Handle JSON parsing errors --- lib/licensed/sources/swift.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/licensed/sources/swift.rb b/lib/licensed/sources/swift.rb index 454483a8..b550b58d 100644 --- a/lib/licensed/sources/swift.rb +++ b/lib/licensed/sources/swift.rb @@ -31,6 +31,9 @@ def pins @pins = begin json = JSON.parse(File.read(package_resolved_file_path)) json.dig("object", "pins") + rescue JSON::ParserError => e + message = "Licensed was unable to parse the Package.resolved file'. JSON Error: #{e.message}" + raise Licensed::Sources::Source::Error, message end end From ce27e853c05c9850fe7bdec93fd94f909c717c55 Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 21 May 2021 12:15:56 -0700 Subject: [PATCH 07/14] Remove unnecessary setup-swift step --- .github/workflows/test.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 093dc037..4a172171 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -366,10 +366,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Setup Swift - uses: fwal/setup-swift@v1 - with: - swift-version: "5.4" - name: Set up Ruby uses: ruby/setup-ruby@v1 with: From abc7b909445b802e96de5359637adfae32842d9f Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 21 May 2021 12:16:11 -0700 Subject: [PATCH 08/14] Fix source-setup script for Swift --- script/source-setup/swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/script/source-setup/swift b/script/source-setup/swift index 0babac39..21ae35b4 100755 --- a/script/source-setup/swift +++ b/script/source-setup/swift @@ -8,6 +8,9 @@ fi swift --version +BASE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd $BASE_PATH/test/fixtures/swift + if [ "$1" == "-f" ]; then find . -not -regex "\.*" \ -and -not -path "*/Package.swift" \ From 5690eca8395edd6aad0b0215113b393967ee70b0 Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 21 May 2021 12:18:31 -0700 Subject: [PATCH 09/14] Add swift-setup step with matrix of values --- .github/workflows/test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4a172171..e4d94e7b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -364,8 +364,15 @@ jobs: swift: runs-on: ubuntu-latest + strategy: + matrix: + swift: [ "5.4", "5.3" ] steps: - uses: actions/checkout@v2 + - name: Setup Swift + uses: fwal/setup-swift@v1 + with: + swift-version: ${{ matrix.swift }} - name: Set up Ruby uses: ruby/setup-ruby@v1 with: From 5b44c608e41610a0bdf41f6bc7e72c2a8e7b6b8d Mon Sep 17 00:00:00 2001 From: Mattt Date: Fri, 21 May 2021 12:31:49 -0700 Subject: [PATCH 10/14] Fix Rubocop violations --- lib/licensed/sources/swift.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/licensed/sources/swift.rb b/lib/licensed/sources/swift.rb index b550b58d..45aa3db4 100644 --- a/lib/licensed/sources/swift.rb +++ b/lib/licensed/sources/swift.rb @@ -32,13 +32,13 @@ def pins json = JSON.parse(File.read(package_resolved_file_path)) json.dig("object", "pins") rescue JSON::ParserError => e - message = "Licensed was unable to parse the Package.resolved file'. JSON Error: #{e.message}" + message = "Licensed was unable to parse the Package.resolved file. JSON Error: #{e.message}" raise Licensed::Sources::Source::Error, message end end def dependency_path_for_url(url) - last_path_component = URI(url).path.split('/').last.sub(/\.git$/, '') + last_path_component = URI(url).path.split("/").last.sub(/\.git$/, "") File.join(config.pwd, ".build", "checkouts", last_path_component) end From 4072e1abb6ef97c682fce232cdc27369a1c9226b Mon Sep 17 00:00:00 2001 From: Mattt Date: Tue, 25 May 2021 10:38:49 -0700 Subject: [PATCH 11/14] Handle errors when constructing dependencies --- lib/licensed/sources/swift.rb | 21 ++++++++++++++++----- test/sources/swift_test.rb | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/lib/licensed/sources/swift.rb b/lib/licensed/sources/swift.rb index 45aa3db4..4f868a1b 100644 --- a/lib/licensed/sources/swift.rb +++ b/lib/licensed/sources/swift.rb @@ -15,10 +15,21 @@ def enabled? def enumerate_dependencies pins.map { |pin| + errors = [] + + begin + name = pin["package"] + version = pin.dig("state", "version") + path = dependency_path_for_url(pin["repositoryURL"]) + rescue => e + errors << e + end + Dependency.new( - name: pin["package"], - path: dependency_path_for_url(pin["repositoryURL"]), - version: pin.dig("state", "version") + name: name, + path: path, + version: version, + errors: errors ) } end @@ -31,8 +42,8 @@ def pins @pins = begin json = JSON.parse(File.read(package_resolved_file_path)) json.dig("object", "pins") - rescue JSON::ParserError => e - message = "Licensed was unable to parse the Package.resolved file. JSON Error: #{e.message}" + rescue => e + message = "Licensed was unable to read the Package.resolved file. Error: #{e.message}" raise Licensed::Sources::Source::Error, message end end diff --git a/test/sources/swift_test.rb b/test/sources/swift_test.rb index 19d79d32..dc4b2e16 100644 --- a/test/sources/swift_test.rb +++ b/test/sources/swift_test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "test_helper" require "tmpdir" +require "pp" if Licensed::Shell.tool_available?("swift") describe Licensed::Sources::Swift do @@ -48,6 +49,37 @@ refute dep end end + + it "handles invalid repositoryURL field" do + source.stubs(:pins).returns( + JSON.parse <<-JSON + [{ + "package": "Invalid", + "repositoryURL": "Invalid", + "state": { + "version": "1.0.0" + } + }] + JSON + ) + + dep = source.enumerate_dependencies.find { |d| d.name == "Invalid" } + assert dep + assert dep.errors + end + + it "handles invalid Package.resolved file" do + Dir.mktmpdir do |dir| + FileUtils.cp_r(fixtures, dir) + File.write(File.join(dir, "Package.resolved"), %("Invalid")) + + Dir.chdir(dir) do + assert_raises ::Licensed::Sources::Source::Error do + source.enumerate_dependencies + end + end + end + end end end end From 79a3a9e82df5d380bf41a6a2ad0acc734005acbc Mon Sep 17 00:00:00 2001 From: Mattt Date: Tue, 25 May 2021 11:04:38 -0700 Subject: [PATCH 12/14] Trim trailing whitespace --- test/sources/swift_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sources/swift_test.rb b/test/sources/swift_test.rb index dc4b2e16..b02b88e6 100644 --- a/test/sources/swift_test.rb +++ b/test/sources/swift_test.rb @@ -67,7 +67,7 @@ assert dep assert dep.errors end - + it "handles invalid Package.resolved file" do Dir.mktmpdir do |dir| FileUtils.cp_r(fixtures, dir) From 083b68045a6586f3eb5ae28373ad688110874830 Mon Sep 17 00:00:00 2001 From: Mattt Date: Wed, 26 May 2021 06:22:30 -0700 Subject: [PATCH 13/14] Update lib/licensed/sources/swift.rb Co-authored-by: Jon Ruskin --- lib/licensed/sources/swift.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/licensed/sources/swift.rb b/lib/licensed/sources/swift.rb index 4f868a1b..d91d6865 100644 --- a/lib/licensed/sources/swift.rb +++ b/lib/licensed/sources/swift.rb @@ -3,8 +3,6 @@ require "pathname" require "uri" -require "licensed/sources/helpers/content_versioning" - module Licensed module Sources class Swift < Source From a1e43363310c35bb6327afd46224cc18533b0fec Mon Sep 17 00:00:00 2001 From: Mattt Date: Wed, 26 May 2021 06:24:20 -0700 Subject: [PATCH 14/14] Incorporate feedback from review --- lib/licensed/sources/swift.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/licensed/sources/swift.rb b/lib/licensed/sources/swift.rb index d91d6865..5ffc7f0f 100644 --- a/lib/licensed/sources/swift.rb +++ b/lib/licensed/sources/swift.rb @@ -13,11 +13,12 @@ def enabled? def enumerate_dependencies pins.map { |pin| + name = pin["package"] + version = pin.dig("state", "version") + path = nil errors = [] begin - name = pin["package"] - version = pin.dig("state", "version") path = dependency_path_for_url(pin["repositoryURL"]) rescue => e errors << e