diff --git a/Sources/App/Controllers/API/API+PackageController+GetRoute.swift b/Sources/App/Controllers/API/API+PackageController+GetRoute.swift index d64d83ba4..c4028f572 100644 --- a/Sources/App/Controllers/API/API+PackageController+GetRoute.swift +++ b/Sources/App/Controllers/API/API+PackageController+GetRoute.swift @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Dependencies import DependencyResolution import Fluent import Vapor @@ -101,7 +102,8 @@ extension API.PackageController.GetRoute { } static func customCollections(on database: Database, package: Package) async -> [CustomCollection.Details] { - guard Current.environment() == .development else { return [] } + @Dependency(\.environment) var environment + guard environment.current() == .development else { return [] } do { try await package.$customCollections.load(on: database) return package.customCollections.map(\.details) diff --git a/Sources/App/Core/AppEnvironment.swift b/Sources/App/Core/AppEnvironment.swift index 5bf80cc83..1ce20cf0c 100644 --- a/Sources/App/Core/AppEnvironment.swift +++ b/Sources/App/Core/AppEnvironment.swift @@ -39,7 +39,6 @@ struct AppEnvironment: Sendable { var collectionSigningPrivateKey: @Sendable () -> Data? var currentReferenceCache: @Sendable () -> CurrentReferenceCache? var dbId: @Sendable () -> String? - var environment: @Sendable () -> Environment var fetchDocumentation: @Sendable (_ client: Client, _ url: URI) async throws -> ClientResponse var fetchHTTPStatusCode: @Sendable (_ url: String) async throws -> HTTPStatus var fetchLicense: @Sendable (_ client: Client, _ owner: String, _ repository: String) async -> Github.License? @@ -155,7 +154,6 @@ extension AppEnvironment { }, currentReferenceCache: { .live }, dbId: { Environment.get("DATABASE_ID") }, - environment: { (try? Environment.detect()) ?? .development }, fetchDocumentation: { client, url in try await client.get(url) }, fetchHTTPStatusCode: { url in try await Networking.fetchHTTPStatusCode(url) }, fetchLicense: { client, owner, repo in await Github.fetchLicense(client:client, owner: owner, repository: repo) }, diff --git a/Sources/App/Core/Dependencies/EnvironmentClient.swift b/Sources/App/Core/Dependencies/EnvironmentClient.swift index 314a555ba..e16e26609 100644 --- a/Sources/App/Core/Dependencies/EnvironmentClient.swift +++ b/Sources/App/Core/Dependencies/EnvironmentClient.swift @@ -22,6 +22,12 @@ struct EnvironmentClient { // See https://swiftpackageindex.com/pointfreeco/swift-dependencies/main/documentation/dependenciesmacros/dependencyclient()#Restrictions // regarding the use of XCTFail here. var allowBuildTriggers: @Sendable () -> Bool = { XCTFail(#function); return true } + // We're not defaulting current to XCTFail, because its use is too pervasive and would require the vast + // majority of tests to be wrapped with `withDependencies`. + // We can do so at a later time once more tests are transitioned over for other dependencies. This is + // the exact same default behaviour we have with the Current dependency injection: it defaults to + // .development and does not raise an error when not injected. + var current: @Sendable () -> Environment = { .development } } @@ -30,7 +36,8 @@ extension EnvironmentClient: DependencyKey { .init( allowBuildTriggers: { Environment.get("ALLOW_BUILD_TRIGGERS").flatMap(\.asBool) ?? Constants.defaultAllowBuildTriggering - } + }, + current: { (try? Environment.detect()) ?? .development } ) } } diff --git a/Sources/App/Views/Blog/BlogActions+Model.swift b/Sources/App/Views/Blog/BlogActions+Model.swift index 7bb0fb3bd..7d33c064c 100644 --- a/Sources/App/Views/Blog/BlogActions+Model.swift +++ b/Sources/App/Views/Blog/BlogActions+Model.swift @@ -13,9 +13,12 @@ // limitations under the License. import Foundation + +import Dependencies +import Ink import Plot import Yams -import Ink + enum BlogActions { @@ -38,7 +41,8 @@ enum BlogActions { init() throws { let allSummaries = try Self.allSummaries() - summaries = if Current.environment() == .production { + @Dependency(\.environment) var environment + summaries = if environment.current() == .production { // Only "published" posts show in production. allSummaries.filter { $0.published } } else { @@ -67,7 +71,7 @@ enum BlogActions { return try YAMLDecoder().decode([PostSummary].self, from: String(decoding: data, as: UTF8.self)) .reversed() } - + } } diff --git a/Sources/App/Views/DocumentationPageProcessor.swift b/Sources/App/Views/DocumentationPageProcessor.swift index d0b161e15..293d9263f 100644 --- a/Sources/App/Views/DocumentationPageProcessor.swift +++ b/Sources/App/Views/DocumentationPageProcessor.swift @@ -15,6 +15,8 @@ import Vapor import SwiftSoup import Plot +import Dependencies + struct DocumentationPageProcessor { let document: SwiftSoup.Document @@ -104,7 +106,8 @@ struct DocumentationPageProcessor { } var metaNoIndex: String? { - guard Current.environment() != .production else { return nil } + @Dependency(\.environment) var environment + guard environment.current() != .production else { return nil } return Plot.Node.meta( .name("robots"), .content("noindex") @@ -129,7 +132,8 @@ struct DocumentationPageProcessor { } var analyticsScript: String? { - guard Current.environment() == .production else { return nil } + @Dependency(\.environment) var environment + guard environment.current() == .production else { return nil } return PublicPage.analyticsScriptTags } @@ -194,10 +198,11 @@ struct DocumentationPageProcessor { ])) } + @Dependency(\.environment) var environment return Plot.Node.group( .header( .class("spi"), - .if(Current.environment() == .development, stagingBanner()), + .if(environment.current() == .development, stagingBanner()), .div( .class("inner breadcrumbs"), .nav( @@ -240,6 +245,7 @@ struct DocumentationPageProcessor { } var footer: String { + @Dependency(\.environment) var environment return Plot.Node.footer( .class("spi"), .div( @@ -288,7 +294,7 @@ struct DocumentationPageProcessor { .text(".") ) ), - .if(Current.environment() == .development, stagingBanner()) + .if(environment.current() == .development, stagingBanner()) ).render() } diff --git a/Sources/App/Views/PublicPage.swift b/Sources/App/Views/PublicPage.swift index 06f209b16..4e6b49ccb 100644 --- a/Sources/App/Views/PublicPage.swift +++ b/Sources/App/Views/PublicPage.swift @@ -13,8 +13,11 @@ // limitations under the License. import Foundation -import Vapor + +import Dependencies import Plot +import Vapor + class PublicPage { @@ -91,7 +94,8 @@ class PublicPage { /// For non-production environments, this will *always* return true. /// - Returns: Either nothing, or a element telling search engines not to index this content. final func metaNoIndex() -> Node { - if Current.environment() == .production && allowIndexing() { + @Dependency(\.environment) var environment + if environment.current() == .production && allowIndexing() { return .empty } else { return .meta( @@ -167,7 +171,8 @@ class PublicPage { /// The Plausible analytics code to be inserted into the element. /// - Returns: A