From 0079820222aefc8c7b055007752b0a5351a49c6d Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Wed, 19 Feb 2025 00:26:17 +0100 Subject: [PATCH 1/4] Fixed the percent encoding for the "pathString" computed property of the URL+Extensions extension in the library target. --- Library/Sources/Internal/Extensions/URL+Extensions.swift | 2 +- .../Cases/Internal/Extensions/URL+ExtensionsTests.swift | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Library/Sources/Internal/Extensions/URL+Extensions.swift b/Library/Sources/Internal/Extensions/URL+Extensions.swift index 01d4ea3..4ab418d 100644 --- a/Library/Sources/Internal/Extensions/URL+Extensions.swift +++ b/Library/Sources/Internal/Extensions/URL+Extensions.swift @@ -16,7 +16,7 @@ extension URL { var pathString: String { if #available(macOS 13.0, *) { - path(percentEncoded: true) + path(percentEncoded: false) } else { path } diff --git a/Test/Sources/Cases/Internal/Extensions/URL+ExtensionsTests.swift b/Test/Sources/Cases/Internal/Extensions/URL+ExtensionsTests.swift index b5525ea..ac809d5 100644 --- a/Test/Sources/Cases/Internal/Extensions/URL+ExtensionsTests.swift +++ b/Test/Sources/Cases/Internal/Extensions/URL+ExtensionsTests.swift @@ -24,8 +24,8 @@ struct URL_ExtensionsTests { // MARK: Computed tests - @Test(arguments: zip([URL.someFile, .dotFile, .tildeFile, .someURL], - [String.someFilePath, .dotPath, .tildePath, .empty])) + @Test(arguments: zip([URL.someFile, .dotFile, .tildeFile, .someEncodedFile, .someURL], + [String.someFilePath, .dotPath, .tildePath, .someEncodedPath, .empty])) func pathString( with url: URL, expects path: String @@ -63,6 +63,7 @@ private extension String { static let dotPath = "." static let empty = "" static let tildePath = "~" + static let someEncodedPath = "/sömê/páth/fîlê" static let someFilePath = "/some/file/path" } @@ -70,6 +71,7 @@ private extension String { private extension URL { static let dotFile = URL(at: .dotPath) + static let someEncodedFile = URL(at: "/sömê/páth/fîlê") static let someFile = URL(at: .someFilePath) static let someURL = URL(string: "https://some.url.path")! static let tildeFile = URL(at: .tildePath) -- 2.47.1 From 7615e707581511955f58c544f65b2f2b31e8adcf Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Wed, 19 Feb 2025 00:41:56 +0100 Subject: [PATCH 2/4] Implemented the OutdatedDependenciesTask task in the library target. --- .../Tasks/OutdatedDependenciesTask.swift | 31 ++++++++++++++ .../Tasks/OutdatedDependenciesTaskTests.swift | 42 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 Library/Sources/Public/Tasks/OutdatedDependenciesTask.swift create mode 100644 Test/Sources/Cases/Public/Tasks/OutdatedDependenciesTaskTests.swift diff --git a/Library/Sources/Public/Tasks/OutdatedDependenciesTask.swift b/Library/Sources/Public/Tasks/OutdatedDependenciesTask.swift new file mode 100644 index 0000000..38a33de --- /dev/null +++ b/Library/Sources/Public/Tasks/OutdatedDependenciesTask.swift @@ -0,0 +1,31 @@ +import Foundation + +public struct OutdatedDependenciesTask { + + // MARK: Properties + + private let terminalService: TerminalServicing + + // MARK: Initialisers + + public init(terminalService: TerminalServicing) { + self.terminalService = terminalService + } + + // MARK: Functions + + public func callAsFunction(at location: URL? = nil) async throws (TerminalServiceError) { + let executableURL = URL(at: "/usr/bin/swift") + + var arguments: [String] = ["package", "update"] + + if let location { + arguments.append(contentsOf: ["--package-path", location.pathString]) + } + + arguments.append("--dry-run") + + try await terminalService.run(executableURL, arguments: arguments) + } + +} diff --git a/Test/Sources/Cases/Public/Tasks/OutdatedDependenciesTaskTests.swift b/Test/Sources/Cases/Public/Tasks/OutdatedDependenciesTaskTests.swift new file mode 100644 index 0000000..b79a211 --- /dev/null +++ b/Test/Sources/Cases/Public/Tasks/OutdatedDependenciesTaskTests.swift @@ -0,0 +1,42 @@ +import Foundation +import Testing + +@testable import ColibriLibrary + +struct OutdatedDependenciesTaskTests { + + @Test(arguments: [nil, URL.someCurrentFolder]) + func task(at location: URL?) async throws { + // GIVEN + let terminalService = TerminalServiceSpy() + let task = OutdatedDependenciesTask(terminalService: terminalService) + + // WHEN + try await task(at: location) + + // THEN + let executableURL = URL(at: "/usr/bin/swift") + let arguments = if let location { + ["package", "update", "--package-path", location.pathString, "--dry-run"] + } else { + ["package", "update", "--dry-run"] + } + + #expect(terminalService.actions.count == 1) + #expect(terminalService.actions[0] == .ran(executableURL, arguments)) + } + + @Test(arguments: [nil, URL.someCurrentFolder], [TerminalServiceError.unexpected, .output(""), .captured("")]) + func task(at location: URL?, throws error: TerminalServiceError) async throws { + // GIVEN + let terminalService = TerminalServiceMock(action: .error(error)) + let task = BuildProjectTask(terminalService: terminalService) + + // WHEN + // THEN + await #expect(throws: error) { + try await task(at: location) + } + } + +} -- 2.47.1 From a52cfb295c74aaacfd4d2c5e6f033eafa9bf947e Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Wed, 19 Feb 2025 00:47:03 +0100 Subject: [PATCH 3/4] Implemented the OutdatedCommand command in the executable target. --- .../Sources/Commands/OutdatedCommand.swift | 29 +++++++++++++++++++ .../Sources/Options/OutdatedOptions.swift | 13 +++++++++ 2 files changed, 42 insertions(+) create mode 100644 Executable/Sources/Commands/OutdatedCommand.swift create mode 100644 Executable/Sources/Options/OutdatedOptions.swift diff --git a/Executable/Sources/Commands/OutdatedCommand.swift b/Executable/Sources/Commands/OutdatedCommand.swift new file mode 100644 index 0000000..686da2b --- /dev/null +++ b/Executable/Sources/Commands/OutdatedCommand.swift @@ -0,0 +1,29 @@ +import ArgumentParser +import ColibriLibrary + +extension Colibri { + struct Outdated: AsyncParsableCommand { + + // MARK: Properties + + static let configuration = CommandConfiguration( + commandName: "outdated-dependencies", + abstract: "Check for outdated package dependencies in a Hummingbird app", + helpNames: .shortAndLong, + aliases: ["outdated"] + ) + + @OptionGroup var options: Options + + // MARK: Functions + + mutating func run() async throws { + let terminalService = TerminalService() + + let outdatedDependencies = OutdatedDependenciesTask(terminalService: terminalService) + + try await outdatedDependencies(at: options.locationURL) + } + + } +} diff --git a/Executable/Sources/Options/OutdatedOptions.swift b/Executable/Sources/Options/OutdatedOptions.swift new file mode 100644 index 0000000..ab501b9 --- /dev/null +++ b/Executable/Sources/Options/OutdatedOptions.swift @@ -0,0 +1,13 @@ +import ArgumentParser +import ColibriLibrary + +extension Colibri.Outdated { + struct Options: ParsableArguments, Locationable { + + // MARK: Properties + + @Option(name: .shortAndLong) + var location: String? + + } +} -- 2.47.1 From bd3963b9f19dfce73455cf4d00f96aef8c1b4ff3 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Wed, 19 Feb 2025 00:48:03 +0100 Subject: [PATCH 4/4] Added the Outdated command to the subcommand lists of the Colibri command in the executable target. --- Executable/Sources/Colibri.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Executable/Sources/Colibri.swift b/Executable/Sources/Colibri.swift index 4359f28..288e88b 100644 --- a/Executable/Sources/Colibri.swift +++ b/Executable/Sources/Colibri.swift @@ -9,7 +9,8 @@ struct Colibri: AsyncParsableCommand { abstract: "The utility to manage your Hummingbird apps", subcommands: [ Build.self, - Create.self + Create.self, + Outdated.self ], defaultSubcommand: Create.self ) -- 2.47.1