Skip to content

Commit 17184b7

Browse files
Merge pull request #3625 from SwiftPackageIndex/issue-3469-dependency-transition-19
Issue 3469 dependency transition 19
2 parents 85173a3 + fc1efa9 commit 17184b7

File tree

9 files changed

+162
-94
lines changed

9 files changed

+162
-94
lines changed

Sources/App/Commands/Ingestion.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ enum Ingestion {
190190

191191
let s3Readme: S3Readme?
192192
do throws(S3Readme.Error) {
193-
s3Readme = try await storeS3Readme(client: client, repository: repo, metadata: metadata, readme: readme)
193+
s3Readme = try await storeS3Readme(repository: repo, metadata: metadata, readme: readme)
194194
} catch {
195195
// We don't want to fail ingestion in case storing the readme fails - warn and continue.
196196
Current.logger().warning("storeS3Readme failed: \(error)")
@@ -239,15 +239,16 @@ enum Ingestion {
239239
}
240240

241241

242-
static func storeS3Readme(client: Client, repository: Repository, metadata: Github.Metadata, readme: Github.Readme?) async throws(S3Readme.Error) -> S3Readme? {
242+
static func storeS3Readme(repository: Repository, metadata: Github.Metadata, readme: Github.Readme?) async throws(S3Readme.Error) -> S3Readme? {
243+
@Dependency(\.s3) var s3
243244
if let upstreamEtag = readme?.etag,
244245
repository.s3Readme?.needsUpdate(upstreamEtag: upstreamEtag) ?? true,
245246
let owner = metadata.repositoryOwner,
246247
let repository = metadata.repositoryName,
247248
let html = readme?.html {
248-
let objectUrl = try await Current.storeS3Readme(owner, repository, html)
249+
let objectUrl = try await s3.storeReadme(owner, repository, html)
249250
if let imagesToCache = readme?.imagesToCache, imagesToCache.isEmpty == false {
250-
try await Current.storeS3ReadmeImages(client, imagesToCache)
251+
try await s3.storeReadmeImages(imagesToCache)
251252
}
252253
return .cached(s3ObjectUrl: objectUrl, githubEtag: upstreamEtag)
253254
} else {

Sources/App/Controllers/PackageController+routes.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ enum PackageController {
306306
}
307307

308308
do {
309-
let readme = try await Current.fetchS3Readme(req.client, owner, repository)
309+
@Dependency(\.s3) var s3
310+
let readme = try await s3.fetchReadme(owner, repository)
310311
guard let branch = pkg.repository?.defaultBranch else {
311312
return PackageReadme.View(model: .cacheLookupFailed(url: readmeHtmlUrl)).document()
312313
}

Sources/App/Core/AppEnvironment.swift

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import FoundationNetworking
2323

2424

2525
struct AppEnvironment: Sendable {
26-
var fetchS3Readme: @Sendable (_ client: Client, _ owner: String, _ repository: String) async throws -> String
2726
var fileManager: FileManager
2827
var getStatusCount: @Sendable (_ client: Client, _ status: Gitlab.Builder.Status) async throws -> Int
2928
var git: Git
@@ -33,11 +32,6 @@ struct AppEnvironment: Sendable {
3332
var logger: @Sendable () -> Logger
3433
var setLogger: @Sendable (Logger) -> Void
3534
var shell: Shell
36-
var storeS3Readme: @Sendable (_ owner: String,
37-
_ repository: String,
38-
_ readme: String) async throws(S3Readme.Error) -> String
39-
var storeS3ReadmeImages: @Sendable (_ client: Client,
40-
_ imagesToCache: [Github.Readme.ImageToCache]) async throws(S3Readme.Error) -> Void
4135
var triggerBuild: @Sendable (_ client: Client,
4236
_ buildId: Build.Id,
4337
_ cloneURL: String,
@@ -53,7 +47,6 @@ extension AppEnvironment {
5347
nonisolated(unsafe) static var logger: Logger!
5448

5549
static let live = AppEnvironment(
56-
fetchS3Readme: { client, owner, repo in try await S3Readme.fetchReadme(client:client, owner: owner, repository: repo) },
5750
fileManager: .live,
5851
getStatusCount: { client, status in
5952
try await Gitlab.Builder.getStatusCount(client: client,
@@ -72,12 +65,6 @@ extension AppEnvironment {
7265
logger: { logger },
7366
setLogger: { logger in Self.logger = logger },
7467
shell: .live,
75-
storeS3Readme: { owner, repo, readme throws(S3Readme.Error) in
76-
try await S3Readme.storeReadme(owner: owner, repository: repo, readme: readme)
77-
},
78-
storeS3ReadmeImages: { client, images throws(S3Readme.Error) in
79-
try await S3Readme.storeReadmeImages(client: client, imagesToCache: images)
80-
},
8168
triggerBuild: { client, buildId, cloneURL, isDocBuild, platform, ref, swiftVersion, versionID in
8269
try await Gitlab.Builder.triggerBuild(client: client,
8370
buildId: buildId,

Sources/App/Core/Dependencies/HTTPClient.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ extension HTTPClient: DependencyKey {
6666
}
6767
)
6868
}
69+
70+
func get(url: String) async throws -> Response { try await get(url: url, headers: .init()) }
6971
}
7072

7173

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import Dependencies
16+
import IssueReporting
17+
18+
19+
// We currently cannot use @DependencyClient here due to
20+
// https://github.com/pointfreeco/swift-dependencies/discussions/324
21+
//@DependencyClient
22+
struct S3Client {
23+
var fetchReadme: @Sendable (_ owner: String, _ repository: String) async throws -> String
24+
var storeReadme: @Sendable (_ owner: String, _ repository: String, _ readme: String) async throws(S3Readme.Error) -> String = { _, _, _ in
25+
reportIssue("storeS3Readme"); return ""
26+
}
27+
var storeReadmeImages: @Sendable (_ imagesToCache: [Github.Readme.ImageToCache]) async throws(S3Readme.Error) -> Void
28+
}
29+
30+
31+
extension S3Client: DependencyKey {
32+
static var liveValue: Self {
33+
.init(
34+
fetchReadme: { owner, repo in
35+
try await S3Readme.fetchReadme(owner: owner, repository: repo)
36+
},
37+
storeReadme: { owner, repo, readme throws(S3Readme.Error) in
38+
try await S3Readme.storeReadme(owner: owner, repository: repo, readme: readme)
39+
},
40+
storeReadmeImages: { images throws(S3Readme.Error) in
41+
try await S3Readme.storeReadmeImages(imagesToCache: images)
42+
}
43+
)
44+
}
45+
}
46+
47+
48+
extension S3Client: TestDependencyKey {
49+
static var testValue: Self {
50+
.init(
51+
fetchReadme: { _, _ in unimplemented(); return "" },
52+
storeReadme: { _, _, _ in unimplemented("storeS3Readme"); return "" },
53+
storeReadmeImages: { _ throws(S3Readme.Error) in unimplemented("storeS3ReadmeImages") }
54+
)
55+
}
56+
}
57+
58+
59+
extension DependencyValues {
60+
var s3: S3Client {
61+
get { self[S3Client.self] }
62+
set { self[S3Client.self] = newValue }
63+
}
64+
}
65+
66+

Sources/App/Core/Extensions/S3Readme+ext.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ extension S3Readme {
2727
case storeImagesFailed
2828
}
2929

30-
static func fetchReadme(client: Client, owner: String, repository: String) async throws(S3Readme.Error) -> String {
30+
static func fetchReadme(owner: String, repository: String) async throws(S3Readme.Error) -> String {
3131
let key = try S3Store.Key.readme(owner: owner, repository: repository)
32-
let response: ClientResponse
32+
@Dependency(\.httpClient) var httpClient
33+
let response: HTTPClient.Response
3334
do {
34-
response = try await client.get(URI(string: key.objectUrl))
35+
response = try await httpClient.get(url: key.objectUrl)
3536
} catch {
3637
throw .requestFailed(key: key, error: error)
3738
}
@@ -56,16 +57,17 @@ extension S3Readme {
5657
return key.objectUrl
5758
}
5859

59-
static func storeReadmeImages(client: Client, imagesToCache: [Github.Readme.ImageToCache]) async throws(S3Readme.Error) {
60+
static func storeReadmeImages(imagesToCache: [Github.Readme.ImageToCache]) async throws(S3Readme.Error) {
6061
@Dependency(\.environment) var environment
62+
@Dependency(\.httpClient) var httpClient
6163
guard let accessKeyId = environment.awsAccessKeyId() else { throw .envVariableNotSet("AWS_ACCESS_KEY_ID") }
6264
guard let secretAccessKey = environment.awsSecretAccessKey() else { throw .envVariableNotSet("AWS_SECRET_ACCESS_KEY")}
6365

6466
let store = S3Store(credentials: .init(keyId: accessKeyId, secret: secretAccessKey))
6567
for imageToCache in imagesToCache {
6668
Current.logger().debug("Copying readme image to \(imageToCache.s3Key.s3Uri) ...")
6769
do {
68-
let response = try await client.get(URI(stringLiteral: imageToCache.originalUrl))
70+
let response = try await httpClient.get(url: imageToCache.originalUrl)
6971
if var body = response.body, let imageData = body.readData(length: body.readableBytes) {
7072
try await store.save(payload: imageData, to: imageToCache.s3Key)
7173
}

Tests/AppTests/IngestionTests.swift

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ class IngestionTests: AppTestCase {
466466

467467
func test_ingest_storeS3Readme() async throws {
468468
let fetchCalls = QueueIsolated(0)
469+
let storeCalls = QueueIsolated(0)
469470
try await withDependencies {
470471
$0.date.now = .now
471472
$0.github.fetchLicense = { @Sendable _, _ in nil }
@@ -484,13 +485,7 @@ class IngestionTests: AppTestCase {
484485
imagesToCache: [])
485486
}
486487
}
487-
} operation: {
488-
// setup
489-
let app = self.app!
490-
let pkg = Package(url: "https://github.com/foo/bar".url, processingStage: .reconciliation)
491-
try await pkg.save(on: app.db)
492-
let storeCalls = QueueIsolated(0)
493-
Current.storeS3Readme = { owner, repo, html in
488+
$0.s3.storeReadme = { owner, repo, html in
494489
storeCalls.increment()
495490
XCTAssertEqual(owner, "foo")
496491
XCTAssertEqual(repo, "bar")
@@ -501,6 +496,11 @@ class IngestionTests: AppTestCase {
501496
}
502497
return "objectUrl"
503498
}
499+
} operation: {
500+
// setup
501+
let app = self.app!
502+
let pkg = Package(url: "https://github.com/foo/bar".url, processingStage: .reconciliation)
503+
try await pkg.save(on: app.db)
504504

505505
do { // first ingestion, no readme has been saved
506506
// MUT
@@ -553,13 +553,7 @@ class IngestionTests: AppTestCase {
553553
let pkg = Package(url: "https://github.com/foo/bar".url,
554554
processingStage: .reconciliation)
555555
try await pkg.save(on: app.db)
556-
Current.storeS3Readme = { _, _, _ in "objectUrl" }
557556
let storeS3ReadmeImagesCalls = QueueIsolated(0)
558-
Current.storeS3ReadmeImages = { _, imagesToCache in
559-
storeS3ReadmeImagesCalls.increment()
560-
561-
XCTAssertEqual(imagesToCache.count, 2)
562-
}
563557

564558
try await withDependencies {
565559
$0.date.now = .now
@@ -586,6 +580,11 @@ class IngestionTests: AppTestCase {
586580
path: "/foo/bar/with-jwt-2.jpg"))
587581
])
588582
}
583+
$0.s3.storeReadme = { _, _, _ in "objectUrl" }
584+
$0.s3.storeReadmeImages = { imagesToCache in
585+
storeS3ReadmeImagesCalls.increment()
586+
XCTAssertEqual(imagesToCache.count, 2)
587+
}
589588
} operation: {
590589
// MUT
591590
try await Ingestion.ingest(client: app.client, database: app.db, mode: .limit(1))
@@ -601,10 +600,6 @@ class IngestionTests: AppTestCase {
601600
let pkg = Package(url: "https://github.com/foo/bar".url, processingStage: .reconciliation)
602601
try await pkg.save(on: app.db)
603602
let storeCalls = QueueIsolated(0)
604-
Current.storeS3Readme = { owner, repo, html throws(S3Readme.Error) in
605-
storeCalls.increment()
606-
throw .storeReadmeFailed
607-
}
608603

609604
do { // first ingestion, no readme has been saved
610605
try await withDependencies {
@@ -617,6 +612,10 @@ class IngestionTests: AppTestCase {
617612
htmlUrl: "readme url",
618613
imagesToCache: [])
619614
}
615+
$0.s3.storeReadme = { owner, repo, html throws(S3Readme.Error) in
616+
storeCalls.increment()
617+
throw .storeReadmeFailed
618+
}
620619
} operation: {
621620
// MUT
622621
let app = self.app!

Tests/AppTests/Mocks/AppEnvironment+mock.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import Vapor
2222
extension AppEnvironment {
2323
static func mock(eventLoop: EventLoop) -> Self {
2424
.init(
25-
fetchS3Readme: { _, _, _ in "" },
2625
fileManager: .mock,
2726
getStatusCount: { _, _ in 100 },
2827
git: .mock,
@@ -32,8 +31,6 @@ extension AppEnvironment {
3231
logger: { logger },
3332
setLogger: { logger in Self.logger = logger },
3433
shell: .mock,
35-
storeS3Readme: { _, _, _ in "s3ObjectUrl" },
36-
storeS3ReadmeImages: { _, _ in },
3734
triggerBuild: { _, _, _, _, _, _, _, _ in .init(status: .ok, webUrl: "http://web_url") }
3835
)
3936
}

0 commit comments

Comments
 (0)