Skip to content

Commit 02bdcda

Browse files
committed
Merge branch 'luis-gustavo/1245-package-collections-keywords-result-page' of github.com:luis-gustavo/SwiftPackageIndex-Server into luis-gustavo/1245-package-collections-keywords-result-page
2 parents ecf709f + 0432a04 commit 02bdcda

18 files changed

+584
-705
lines changed

Package.resolved

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/App/Commands/TriggerBuilds.swift

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,7 @@ struct TriggerBuildsCommand: AsyncCommand {
8585
}
8686

8787
do {
88-
try await triggerBuilds(on: context.application.db,
89-
client: context.application.client,
90-
mode: mode)
88+
try await triggerBuilds(on: context.application.db, mode: mode)
9189
} catch {
9290
Current.logger().critical("\(error)")
9391
}
@@ -122,9 +120,7 @@ extension TriggerBuildsCommand {
122120
/// - client: `Client` used for http request
123121
/// - parameter: `BuildTriggerCommand.Parameter` holding either a list of package ids
124122
/// or a fetch limit for candidate selection.
125-
func triggerBuilds(on database: Database,
126-
client: Client,
127-
mode: TriggerBuildsCommand.Mode) async throws {
123+
func triggerBuilds(on database: Database, mode: TriggerBuildsCommand.Mode) async throws {
128124
@Dependency(\.environment) var environment
129125
let start = DispatchTime.now().uptimeNanoseconds
130126

@@ -138,15 +134,12 @@ func triggerBuilds(on database: Database,
138134
AppMetrics.buildCandidatesCount?.set(candidates.count)
139135

140136
let limitedCandidates = Array(candidates.prefix(limit))
141-
try await triggerBuilds(on: database,
142-
client: client,
143-
packages: limitedCandidates)
137+
try await triggerBuilds(on: database, packages: limitedCandidates)
144138
AppMetrics.buildTriggerDurationSeconds?.time(since: start)
145139

146140
case let .packageId(id, force):
147141
Current.logger().info("Triggering builds (packageID: \(id)) ...")
148142
try await triggerBuilds(on: database,
149-
client: client,
150143
packages: [id],
151144
force: force)
152145
AppMetrics.buildTriggerDurationSeconds?.time(since: start)
@@ -159,9 +152,7 @@ func triggerBuilds(on database: Database,
159152
Current.logger().error("Failed to create trigger.")
160153
return
161154
}
162-
try await triggerBuildsUnchecked(on: database,
163-
client: client,
164-
triggers: [trigger])
155+
try await triggerBuildsUnchecked(on: database, triggers: [trigger])
165156

166157
}
167158
}
@@ -175,7 +166,6 @@ func triggerBuilds(on database: Database,
175166
/// - packages: list of `Package.Id`s to trigger
176167
/// - force: do not check pipeline capacity and ignore downscaling
177168
func triggerBuilds(on database: Database,
178-
client: Client,
179169
packages: [Package.Id],
180170
force: Bool = false) async throws {
181171
@Dependency(\.environment) var environment
@@ -191,15 +181,15 @@ func triggerBuilds(on database: Database,
191181
for package in packages {
192182
group.addTask {
193183
let triggerInfo = try await findMissingBuilds(database, packageId: package)
194-
try await triggerBuildsUnchecked(on: database, client: client, triggers: triggerInfo)
184+
try await triggerBuildsUnchecked(on: database, triggers: triggerInfo)
195185
}
196186
}
197187
}
198188
}
199189

200190
let getStatusCount = buildSystem.getStatusCount
201-
async let pendingJobsTask = getStatusCount(client, .pending)
202-
async let runningJobsTask = getStatusCount(client, .running)
191+
async let pendingJobsTask = getStatusCount(.pending)
192+
async let runningJobsTask = getStatusCount(.running)
203193
let pendingJobs = try await pendingJobsTask
204194
let runningJobs = try await runningJobsTask
205195

@@ -237,9 +227,7 @@ func triggerBuilds(on database: Database,
237227
let triggeredJobCount = triggers.reduce(0) { $0 + $1.buildPairs.count }
238228
await newJobs.withValue { $0 += triggeredJobCount }
239229

240-
try await triggerBuildsUnchecked(on: database,
241-
client: client,
242-
triggers: triggers)
230+
try await triggerBuildsUnchecked(on: database, triggers: triggers)
243231
}
244232
}
245233
}
@@ -255,9 +243,7 @@ func triggerBuilds(on database: Database,
255243
/// - database: `Database` handle used for database access
256244
/// - client: `Client` used for http request
257245
/// - triggers: trigger information for builds to trigger
258-
func triggerBuildsUnchecked(on database: Database,
259-
client: Client,
260-
triggers: [BuildTriggerInfo]) async throws {
246+
func triggerBuildsUnchecked(on database: Database, triggers: [BuildTriggerInfo]) async throws {
261247
await withThrowingTaskGroup(of: Void.self) { group in
262248
for trigger in triggers {
263249
if let packageName = trigger.packageName, let reference = trigger.reference {
@@ -272,7 +258,6 @@ func triggerBuildsUnchecked(on database: Database,
272258
let buildId = Build.Id()
273259

274260
let response = try await Build.trigger(database: database,
275-
client: client,
276261
buildId: buildId,
277262
isDocBuild: trigger.docPairs.contains(pair),
278263
platform: pair.platform,

Sources/App/Core/Dependencies/BuildSystemClient.swift

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,12 @@
1414

1515
import Dependencies
1616
import DependenciesMacros
17-
import Vapor
1817

1918

2019
@DependencyClient
2120
struct BuildSystemClient {
22-
#warning("remove client")
23-
var getStatusCount: @Sendable (_ client: Client, _ status: Gitlab.Builder.Status) async throws -> Int
24-
#warning("remove client")
25-
var triggerBuild: @Sendable (_ client: Client,
26-
_ buildId: Build.Id,
21+
var getStatusCount: @Sendable (_ status: Gitlab.Builder.Status) async throws -> Int
22+
var triggerBuild: @Sendable (_ buildId: Build.Id,
2723
_ cloneURL: String,
2824
_ isDocBuild: Bool,
2925
_ platform: Build.Platform,
@@ -36,16 +32,14 @@ struct BuildSystemClient {
3632
extension BuildSystemClient: DependencyKey {
3733
static var liveValue: Self {
3834
.init(
39-
getStatusCount: { client, status in
40-
try await Gitlab.Builder.getStatusCount(client: client,
41-
status: status,
35+
getStatusCount: { status in
36+
try await Gitlab.Builder.getStatusCount(status: status,
4237
page: 1,
4338
pageSize: 100,
4439
maxPageCount: 5)
4540
},
46-
triggerBuild: { client, buildId, cloneURL, isDocBuild, platform, ref, swiftVersion, versionID in
47-
try await Gitlab.Builder.triggerBuild(client: client,
48-
buildId: buildId,
41+
triggerBuild: { buildId, cloneURL, isDocBuild, platform, ref, swiftVersion, versionID in
42+
try await Gitlab.Builder.triggerBuild(buildId: buildId,
4943
cloneURL: cloneURL,
5044
isDocBuild: isDocBuild,
5145
platform: platform,

Sources/App/Core/Dependencies/HTTPClient.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ extension HTTPClient: DependencyKey {
6868
}
6969

7070
func get(url: String) async throws -> Response { try await get(url: url, headers: .init()) }
71+
func post(url: String, body: Data?) async throws -> Response {
72+
try await post(url: url, headers: .init(), body: body)
73+
}
7174
}
7275

7376

@@ -112,6 +115,7 @@ extension HTTPClient.Response {
112115
static var notFound: Self { .init(status: .notFound) }
113116
static var tooManyRequests: Self { .init(status: .tooManyRequests) }
114117
static var ok: Self { .init(status: .ok) }
118+
static var created: Self { .init(status: .created) }
115119

116120
static func ok(body: String, headers: HTTPHeaders = .init()) -> Self {
117121
.init(status: .ok, headers: headers, body: .init(string: body))
@@ -121,5 +125,10 @@ extension HTTPClient.Response {
121125
let data = try JSONEncoder().encode(value)
122126
return .init(status: .ok, headers: headers, body: .init(data: data))
123127
}
128+
129+
static func created<T: Encodable>(jsonEncode value: T, headers: HTTPHeaders = .init()) throws -> Self {
130+
let data = try JSONEncoder().encode(value)
131+
return .init(status: .created, headers: headers, body: .init(data: data))
132+
}
124133
}
125134
#endif

Sources/App/Core/Gitlab.swift

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ enum Gitlab {
2323
enum Error: LocalizedError {
2424
case missingConfiguration(String)
2525
case missingToken
26-
case requestFailed(HTTPStatus, URI)
26+
case noBody
27+
case requestFailed(status: HTTPStatus, url: String)
2728
}
2829

29-
static let decoder: JSONDecoder = {
30+
static var decoder: JSONDecoder {
3031
let d = JSONDecoder()
3132
d.keyDecodingStrategy = .convertFromSnakeCase
3233
d.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
3334
return d
34-
}()
35+
}
3536

3637
}
3738

@@ -69,15 +70,15 @@ extension Gitlab.Builder {
6970
}
7071
}
7172

72-
static func triggerBuild(client: Client,
73-
buildId: Build.Id,
73+
static func triggerBuild(buildId: Build.Id,
7474
cloneURL: String,
7575
isDocBuild: Bool,
7676
platform: Build.Platform,
7777
reference: Reference,
7878
swiftVersion: SwiftVersion,
7979
versionID: Version.Id) async throws -> Build.TriggerResponse {
8080
@Dependency(\.environment) var environment
81+
@Dependency(\.httpClient) var httpClient
8182

8283
guard let pipelineToken = environment.gitlabPipelineToken(),
8384
let builderToken = environment.builderToken()
@@ -88,31 +89,33 @@ extension Gitlab.Builder {
8889
}
8990
let timeout = environment.buildTimeout() + (isDocBuild ? 5 : 0)
9091

91-
let uri: URI = .init(string: "\(projectURL)/trigger/pipeline")
92-
let response = try await client
93-
.post(uri) { req in
94-
let data = PostDTO(
95-
token: pipelineToken,
96-
ref: branch,
97-
variables: [
98-
"API_BASEURL": SiteURL.apiBaseURL,
99-
"AWS_DOCS_BUCKET": awsDocsBucket,
100-
"BUILD_ID": buildId.uuidString,
101-
"BUILD_PLATFORM": platform.rawValue,
102-
"BUILDER_TOKEN": builderToken,
103-
"CLONE_URL": cloneURL,
104-
"REFERENCE": "\(reference)",
105-
"SWIFT_VERSION": "\(swiftVersion.major).\(swiftVersion.minor)",
106-
"TIMEOUT": "\(timeout)m",
107-
"VERSION_ID": versionID.uuidString
108-
])
109-
try req.query.encode(data)
110-
}
92+
let dto = PostDTO(
93+
token: pipelineToken,
94+
ref: branch,
95+
variables: [
96+
"API_BASEURL": SiteURL.apiBaseURL,
97+
"AWS_DOCS_BUCKET": awsDocsBucket,
98+
"BUILD_ID": buildId.uuidString,
99+
"BUILD_PLATFORM": platform.rawValue,
100+
"BUILDER_TOKEN": builderToken,
101+
"CLONE_URL": cloneURL,
102+
"REFERENCE": "\(reference)",
103+
"SWIFT_VERSION": "\(swiftVersion.major).\(swiftVersion.minor)",
104+
"TIMEOUT": "\(timeout)m",
105+
"VERSION_ID": versionID.uuidString
106+
]
107+
)
108+
let body = try URLEncodedFormEncoder().encode(dto)
109+
let response = try await httpClient.post(
110+
url: "\(projectURL)/trigger/pipeline",
111+
headers: .contentTypeFormURLEncoded,
112+
body: Data(body.utf8)
113+
)
114+
111115
do {
112-
let res = Build.TriggerResponse(
113-
status: response.status,
114-
webUrl: try response.content.decode(Response.self).webUrl
115-
)
116+
guard let body = response.body else { throw Gitlab.Error.noBody }
117+
let webUrl = try JSONDecoder().decode(Response.self, from: body).webUrl
118+
let res = Build.TriggerResponse(status: response.status, webUrl: webUrl)
116119
Current.logger().info("Triggered build: \(res.webUrl)")
117120
return res
118121
} catch {
@@ -154,30 +157,31 @@ extension Gitlab.Builder {
154157
}
155158

156159
// https://docs.gitlab.com/ee/api/pipelines.html
157-
static func fetchPipelines(client: Client,
158-
status: Status,
160+
static func fetchPipelines(status: Status,
159161
page: Int,
160162
pageSize: Int = 20) async throws -> [Pipeline] {
161163
@Dependency(\.environment) var environment
164+
@Dependency(\.httpClient) var httpClient
162165
guard let apiToken = environment.gitlabApiToken() else { throw Gitlab.Error.missingToken }
166+
let url = "\(projectURL)/pipelines?status=\(status)&page=\(page)&per_page=\(pageSize)"
163167

164-
let uri: URI = .init(string: "\(projectURL)/pipelines?status=\(status)&page=\(page)&per_page=\(pageSize)")
165-
let response = try await client.get(uri, headers: .bearer(apiToken))
168+
let response = try await httpClient.get(url: url, headers: .bearer(apiToken))
166169

167-
guard response.status == .ok else { throw Gitlab.Error.requestFailed(response.status, uri) }
170+
guard response.status == .ok else {
171+
throw Gitlab.Error.requestFailed(status: response.status, url: url)
172+
}
173+
guard let body = response.body else { throw Gitlab.Error.noBody }
168174

169-
return try response.content.decode([Pipeline].self, using: Gitlab.decoder)
175+
return try Gitlab.decoder.decode([Pipeline].self, from: body)
170176
}
171177

172-
static func getStatusCount(client: Client,
173-
status: Status,
178+
static func getStatusCount(status: Status,
174179
page: Int = 1,
175180
pageSize: Int = 20,
176181
maxPageCount: Int = 5) async throws -> Int {
177-
let count = try await fetchPipelines(client: client, status: status, page: page, pageSize: pageSize).count
182+
let count = try await fetchPipelines(status: status, page: page, pageSize: pageSize).count
178183
if count == pageSize && page < maxPageCount {
179-
let statusCount = try await getStatusCount(client: client,
180-
status: status,
184+
let statusCount = try await getStatusCount(status: status,
181185
page: page + 1,
182186
pageSize: pageSize,
183187
maxPageCount: maxPageCount)
@@ -205,6 +209,10 @@ private extension HTTPHeaders {
205209
static func bearer(_ token: String) -> Self {
206210
.init([("Authorization", "Bearer \(token)")])
207211
}
212+
213+
static var contentTypeFormURLEncoded: Self {
214+
.init([("Content-Type", "application/x-www-form-urlencoded")])
215+
}
208216
}
209217

210218

Sources/App/Core/Supporters+GitHub.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ extension Array<Supporters.Community> {
260260
.init(
261261
login: "Vkt0r",
262262
name: "Victor Sigler",
263-
avatarUrl: "https://avatars.githubusercontent.com/u/4573453?u=ecc5faaa658a54d2c705c24c891d870a3993cce7&v=4"
263+
avatarUrl: "https://avatars.githubusercontent.com/u/4573453?u=0ed9d1e41dd700d559b9435022db4cab0bdf6d76&v=4"
264264
),
265265
.init(
266266
login: "JonPulfer",

Sources/App/Models/Build.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ extension Build {
175175
}
176176

177177
static func trigger(database: Database,
178-
client: Client,
179178
buildId: Build.Id,
180179
isDocBuild: Bool,
181180
platform: Build.Platform,
@@ -189,8 +188,7 @@ extension Build {
189188
.unwrap(or: Abort(.notFound))
190189

191190
@Dependency(\.buildSystem) var buildSystem
192-
return try await buildSystem.triggerBuild(client,
193-
buildId,
191+
return try await buildSystem.triggerBuild(buildId,
194192
version.package.url,
195193
isDocBuild,
196194
platform,

Sources/App/Views/Keyword/KeywordShow+View.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ enum KeywordShow {
8383
private func packageCollectionLimitNote() -> Node<HTML.BodyContext> {
8484
guard model.totalPackageCount > Constants.maxKeywordPackageCollectionCount else { return .empty }
8585
return .p(
86-
.strong("Note: Package collections are limited to a maximum of \(Constants.maxKeywordPackageCollectionCount) packages. If a keyword has more than \(Constants.maxKeywordPackageCollectionCount) packages, only the top \(Constants.maxKeywordPackageCollectionCount) packages will be included based on their package score."
86+
.strong("Note: "),
87+
.text("Package collections are limited to a maximum of \(Constants.maxKeywordPackageCollectionCount) packages. If a keyword has more than \(Constants.maxKeywordPackageCollectionCount) packages, only the top \(Constants.maxKeywordPackageCollectionCount) packages will be included based on their package score."
8788
)
8889
)
8990
}

0 commit comments

Comments
 (0)