Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/SwiftDependencyUpdaterLibrary/Dependency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct Dependency {
if packageDescription.dependencies.isEmpty {
return []
}
let resolvedPackage = try ResolvedPackage.loadResolvedPackage(from: folder)
let resolvedPackage = try ResolvedPackage.resolveAndLoadResolvedPackage(from: folder)
let swiftPackageUpdates = try SwiftPackageUpdate.checkUpdates(in: folder)
return try mergeDependencies(packageDescription: packageDescription, resolvedPackage: resolvedPackage, swiftPackageUpdates: swiftPackageUpdates)
}
Expand Down
45 changes: 42 additions & 3 deletions Sources/SwiftDependencyUpdaterLibrary/PackageDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,27 @@ private struct PackageDependencyV55: PackageDependency {
let url: URL
}

private struct PackageDependencyV56: PackageDependency {

enum CodingKeys: String, CodingKey {
case name = "identity"
case requirement
case location
}

let name: String
let requirement: DependencyRequirement
let location: PackageLocation

var url: URL {
location.remote.first!
}
}

private struct PackageLocation: Decodable {
let remote: [URL]
}

enum DependencyRequirement: Decodable, Equatable {

case exact(version: Version)
Expand Down Expand Up @@ -116,21 +137,39 @@ struct PackageDescriptionV55: PackageDescription {

}

struct PackageDescriptionV56: PackageDescription {

enum CodingKeys: String, CodingKey {
case dependencyMap = "dependencies"
}

private let dependencyMap: [[String: [PackageDependencyV56]]]
var dependencies: [PackageDependency] {
dependencyMap.flatMap { $0.values.flatMap { $0 } }
}

}

enum PackageDescriptionFactory {
static func loadPackageDescription(from folder: URL) throws -> PackageDescription {
let json = try readPackageDescription(from: folder)
let data = json.data(using: .utf8)!
let decoder = JSONDecoder()
do {
let packageDescription = try decoder.decode(PackageDescriptionV55.self, from: data)
let packageDescription = try decoder.decode(PackageDescriptionV56.self, from: data)
return packageDescription
} catch {
do {
let packageDescription = try decoder.decode(PackageDescriptionV54.self, from: data)
let packageDescription = try decoder.decode(PackageDescriptionV55.self, from: data)
return packageDescription
} catch {
do {
let packageDescription = try decoder.decode(PackageDescriptionV54.self, from: data)
return packageDescription
} catch {
throw PackageDescriptionError.parsingFailed(String(describing: error), json)
}
}
throw PackageDescriptionError.parsingFailed(String(describing: error), json)
}
}

Expand Down
6 changes: 5 additions & 1 deletion Sources/SwiftDependencyUpdaterLibrary/ResolvedPackage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,17 @@ struct ResolvedPackage: Decodable {

let dependencies: [ResolvedDependency]

static func loadResolvedPackage(from folder: URL) throws -> ResolvedPackage {
static func resolveAndLoadResolvedPackage(from folder: URL) throws -> ResolvedPackage {
do {
try shellOut(to: "swift", arguments: ["package", "resolve", "--package-path", "\"\(folder.path)\"" ])
} catch {
let error = error as! ShellOutError // swiftlint:disable:this force_cast
throw ResolvedPackageError.resolvingFailed(error.message)
}
return try loadResolvedPackage(from: folder)
}

static func loadResolvedPackage(from folder: URL) throws -> ResolvedPackage {
let data = try readResolvedPackageData(from: folder)
let decoder = JSONDecoder()
do {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct SwiftPackageUpdate {

private static func readUpdates(in folder: URL) throws -> String {
do {
let output = try shellOut(to: "swift", arguments: ["package", "update", "--dry-run", "--package-path", "\"\(folder.path)\"" ])
let output = try shellOut(to: "swift", arguments: ["package", "--package-path", "\"\(folder.path)\"", "update", "--dry-run" ])
return output
} catch {
let error = error as! ShellOutError // swiftlint:disable:this force_cast
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,19 @@ extension XCTestCase {
XCTAssertEqual(error, expectedError, file: file, line: line)
}

func assert<T, E: Error & Equatable>(_ expression: @autoclosure () throws -> T, throws expectedErrors: [E], in file: StaticString = #file, line: UInt = #line) {
var caughtError: Error?

XCTAssertThrowsError(try expression(), file: file, line: line) {
caughtError = $0
}

guard let error = caughtError as? E else {
XCTFail("Unexpected error type, got \(type(of: caughtError!)) instead of \(E.self)", file: file, line: line)
return
}

XCTAssert(expectedErrors.contains(error), "Received \(error) instead of expected error", file: file, line: line)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ class PackageDescriptionTest: XCTestCase {

func testEmptyFolder() {
let folder = emptyFolderURL()

assert(
try PackageDescriptionFactory.loadPackageDescription(from: folder),
throws: PackageDescriptionError.loadingFailed("error: root manifest not found")
throws: [
PackageDescriptionError.loadingFailed("error: root manifest not found"),
PackageDescriptionError.loadingFailed("error: Could not find Package.swift in this directory or any of its parent directories.")
]
)
}

Expand All @@ -26,8 +30,12 @@ class PackageDescriptionTest: XCTestCase {
XCTFail("Unexpected error, got \(type(of: caughtError!)) \(caughtError!)) instead of PackageDescriptionError.loadingFailed")
return
}
let errors = [
"Missing or empty JSON output from manifest compilation",
"\(folder.path): error: malformed"
]

XCTAssert(description.contains("\(folder.path): error: malformed"))
XCTAssert(errors.contains { description.contains($0) }, "Received \(description) instead of expected error")
}

func testParsing() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,64 @@ import XCTest

class ResolvedPackageTests: XCTestCase {

func testEmptyFolderResolve() {
let folder = emptyFolderURL()

assert(
try ResolvedPackage.resolveAndLoadResolvedPackage(from: folder),
throws: [
ResolvedPackageError.resolvingFailed("error: root manifest not found"),
ResolvedPackageError.resolvingFailed("error: Could not find Package.swift in this directory or any of its parent directories.")
]
)
}

func testEmptyFolder() {
let folder = emptyFolderURL()

assert(
try ResolvedPackage.loadResolvedPackage(from: folder),
throws: ResolvedPackageError.resolvingFailed("error: root manifest not found")
throws: [
ResolvedPackageError.readingFailed("The file “Package.resolved” couldn’t be opened because there is no such file."),
ResolvedPackageError.readingFailed("The operation could not be completed. No such file or directory")
]
)
}

func testInvalidFileResolve() {
let folder = emptyFolderURL()
let resolvedFile = temporaryFileURL(in: folder, name: "Package.resolved")
createFile(at: resolvedFile, content: "\n")
let packageFile = temporaryFileURL(in: folder, name: "Package.swift")
createFile(at: packageFile, content: TestUtils.emptyPackageSwiftFileContent)

XCTAssertThrowsError(try ResolvedPackage.resolveAndLoadResolvedPackage(from: folder)) {
guard let error = $0 as? ResolvedPackageError else {
XCTFail("Unexpected error type, got \(type(of: $0)) instead of \(ResolvedPackageError.self)")
return
}
if case let .resolvingFailed(errorMessage) = error {
XCTAssert(errorMessage.contains("error: Package.resolved file is corrupted or malformed; fix or delete the file to continue"),
"Received error message \(errorMessage) does not contain expected error")
} else {
XCTFail("Received errors is not of type resolvingFailed: \(error)")
}
}
}

func testInvalidFile() {
let folder = emptyFolderURL()
let resolvedFile = temporaryFileURL(in: folder, name: "Package.resolved")
createFile(at: resolvedFile, content: "\n")
let packageFile = temporaryFileURL(in: folder, name: "Package.swift")
createFile(at: packageFile, content: TestUtils.emptyPackageSwiftFileContent)

assert(
try ResolvedPackage.loadResolvedPackage(from: folder),
throws: ResolvedPackageError.resolvingFailed("error: Package.resolved file is corrupted or malformed; fix or delete the file to continue: malformed")
throws: [
ResolvedPackageError.parsingFailed("The data couldn’t be read because it isn’t in the correct format.", "\n"),
ResolvedPackageError.parsingFailed("The operation could not be completed. The data isn’t in the correct format.", "\n")
]
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ class GitHubCommandTests: XCTestCase {
let result = outputFromExecutionWith(arguments: ["github", url.path])
XCTAssertEqual(result.exitCode, 1)
XCTAssertEqual(result.errorOutput, "")
XCTAssertEqual(result.output, "Could not get package data, swift package dump-package failed: error: root manifest not found")
let errors = [
"Could not get package data, swift package dump-package failed: error: Could not find Package.swift in this directory or any of its parent directories.",
"Could not get package data, swift package dump-package failed: error: root manifest not found"
]
XCTAssert(errors.contains(result.output), "Received \(result.output) instead of expected error")
}

func testInvalidPackage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ class ListCommandTests: XCTestCase {
let result = outputFromExecutionWith(arguments: ["list", url.path])
XCTAssertEqual(result.exitCode, 1)
XCTAssertEqual(result.errorOutput, "")
XCTAssertEqual(result.output, "Could not get package data, swift package dump-package failed: error: root manifest not found")
let errors = [
"Could not get package data, swift package dump-package failed: error: Could not find Package.swift in this directory or any of its parent directories.",
"Could not get package data, swift package dump-package failed: error: root manifest not found"
]
XCTAssert(errors.contains(result.output), "Received \(result.output) instead of expected error")
}

func testInvalidPackage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ class UpdateCommandTests: XCTestCase {
let result = outputFromExecutionWith(arguments: ["update", url.path])
XCTAssertEqual(result.exitCode, 1)
XCTAssertEqual(result.errorOutput, "")
XCTAssertEqual(result.output, "Could not get package data, swift package dump-package failed: error: root manifest not found")
let errors = [
"Could not get package data, swift package dump-package failed: error: root manifest not found",
"Could not get package data, swift package dump-package failed: error: Could not find Package.swift in this directory or any of its parent directories."
]
XCTAssert(errors.contains(result.output), "Received \(result.output) instead of expected error")
}

func testInvalidPackage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ class SwiftPackageUpdateTests: XCTestCase {
let folder = emptyFolderURL()
assert(
try SwiftPackageUpdate.checkUpdates(in: folder),
throws: SwiftPackageUpdateError.loadingFailed("error: root manifest not found")
throws: [
SwiftPackageUpdateError.loadingFailed("error: root manifest not found"),
SwiftPackageUpdateError.loadingFailed("error: Could not find Package.swift in this directory or any of its parent directories.")
]
)
}

Expand Down