Skip to content

Commit ff58e5f

Browse files
committed
Add custom package collection link to custom collections page
1 parent 02c9049 commit ff58e5f

File tree

9 files changed

+74
-18
lines changed

9 files changed

+74
-18
lines changed

Sources/App/Controllers/PackageCollectionController.swift

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,34 @@ enum PackageCollectionController {
2020
static func generate(req: Request) async throws -> SignedCollection {
2121
AppMetrics.packageCollectionGetTotal?.inc()
2222

23-
guard let owner = req.parameters.get("owner") else { throw Abort(.notFound) }
23+
guard let collectionType = getCollectionType(req: req) else {
24+
throw Abort(.notFound)
25+
}
2426

2527
do {
26-
return try await SignedCollection.generate(
27-
db: req.db,
28-
filterBy: .author(owner),
29-
authorName: "\(owner) via the Swift Package Index"
30-
)
28+
switch collectionType {
29+
case let .author(owner):
30+
return try await SignedCollection.generate(
31+
db: req.db,
32+
filterBy: .author(owner),
33+
authorName: "\(owner) via the Swift Package Index"
34+
)
35+
case let .custom(name):
36+
fatalError("FIXME")
37+
}
3138
} catch PackageCollection.Error.noResults {
3239
throw Abort(.notFound)
3340
}
3441
}
42+
43+
enum CollectionType {
44+
case author(String)
45+
case custom(String)
46+
}
47+
48+
static func getCollectionType(req: Request) -> CollectionType? {
49+
if let owner = req.parameters.get("owner") { return .author(owner) }
50+
if let name = req.parameters.get("name") { return .custom(name) }
51+
return nil
52+
}
3553
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ extension String {
5858
var pathEncoded: Self {
5959
replacingOccurrences(of: "/", with: "-")
6060
}
61+
62+
var urlPathEncoded: Self {
63+
addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? self
64+
}
6165
}
6266

6367

Sources/App/Core/SiteURL.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ enum SiteURL: Resourceable, Sendable {
121121
case javascripts(String)
122122
case keywords(_ keyword: Parameter<String>)
123123
case package(_ owner: Parameter<String>, _ repository: Parameter<String>, PackagePathComponents?)
124-
case packageCollection(_ owner: Parameter<String>)
124+
case packageCollectionAuthor(_ owner: Parameter<String>)
125+
case packageCollectionCustom(_ name: Parameter<String>)
125126
case packageCollections
126127
case privacy
127128
case readyForSwift6
@@ -171,7 +172,7 @@ enum SiteURL: Resourceable, Sendable {
171172
return "build-monitor"
172173

173174
case let .collections(.value(name)):
174-
return "collections/\(name)"
175+
return "collections/\(name.urlPathEncoded)"
175176

176177
case .collections(.key):
177178
fatalError("path must not be called with a name parameter")
@@ -208,10 +209,16 @@ enum SiteURL: Resourceable, Sendable {
208209
case .package:
209210
fatalError("invalid path: \(self)")
210211

211-
case let .packageCollection(.value(owner)):
212+
case let .packageCollectionAuthor(.value(owner)):
212213
return "\(owner)/collection.json"
213214

214-
case .packageCollection(.key):
215+
case .packageCollectionAuthor(.key):
216+
fatalError("invalid path: \(self)")
217+
218+
case let .packageCollectionCustom(.value(name)):
219+
return "collections/\(name.urlPathEncoded)/collection.json"
220+
221+
case .packageCollectionCustom(.key):
215222
fatalError("invalid path: \(self)")
216223

217224
case .packageCollections:
@@ -311,10 +318,16 @@ enum SiteURL: Resourceable, Sendable {
311318
case .package:
312319
fatalError("pathComponents must not be called with a value parameter")
313320

314-
case .packageCollection(.key):
321+
case .packageCollectionAuthor(.key):
315322
return [":owner", "collection.json"]
316323

317-
case .packageCollection(.value):
324+
case .packageCollectionAuthor(.value):
325+
fatalError("pathComponents must not be called with a value parameter")
326+
327+
case .packageCollectionCustom(.key):
328+
return ["collections", ":name", "collection.json"]
329+
330+
case .packageCollectionCustom(.value):
318331
fatalError("pathComponents must not be called with a value parameter")
319332

320333
case .images, .javascripts, .stylesheets:

Sources/App/Views/Author/AuthorShow+View.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ enum AuthorShow {
5959
),
6060
.copyableInputForm(buttonName: "Copy Package Collection URL",
6161
eventName: "Copy Package Collection URL Button",
62-
valueToCopy: SiteURL.packageCollection(.value(model.owner)).absoluteURL()),
62+
valueToCopy: SiteURL.packageCollectionAuthor(.value(model.owner)).absoluteURL()),
6363
.hr(.class("minor")),
6464
.ul(
6565
.id("package-list"),

Sources/App/Views/CustomCollection/CustomCollectionShow+View.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ enum CustomCollectionShow {
4848
.class("trimmed"),
4949
.text("Packages for collection “\(model.name)")
5050
),
51+
.p(
52+
.text("These packages are available as a package collection, "),
53+
.a(
54+
.href(SiteURL.packageCollections.relativeURL()),
55+
"usable in Xcode 13 or the Swift Package Manager 5.5"
56+
),
57+
.text(".")
58+
),
59+
.copyableInputForm(buttonName: "Copy Package Collection URL",
60+
eventName: "Copy Package Collection URL Button",
61+
valueToCopy: SiteURL.packageCollectionCustom(.value(model.name)).absoluteURL()),
62+
.hr(.class("minor")),
5163
.ul(
5264
.id("package-list"),
5365
.group(

Sources/App/routes.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ func routes(_ app: Application) throws {
8484
}
8585
}
8686

87-
do { // package collection page
88-
app.get(SiteURL.packageCollection(.key).pathComponents,
87+
do { // package collection pages
88+
app.get(SiteURL.packageCollectionAuthor(.key).pathComponents,
89+
use: PackageCollectionController.generate).excludeFromOpenAPI()
90+
app.get(SiteURL.packageCollectionCustom(.key).pathComponents,
8991
use: PackageCollectionController.generate).excludeFromOpenAPI()
9092
}
9193

Tests/AppTests/SiteURLTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ class SiteURLTests: XCTestCase {
140140
}
141141

142142
func test_packageCollectionURL() throws {
143-
XCTAssertEqual(SiteURL.packageCollection(.value("foo")).path,
143+
XCTAssertEqual(SiteURL.packageCollectionAuthor(.value("foo")).path,
144144
"foo/collection.json")
145-
XCTAssertEqual(SiteURL.packageCollection(.key).pathComponents
145+
XCTAssertEqual(SiteURL.packageCollectionAuthor(.key).pathComponents
146146
.map(\.description),
147147
[":owner", "collection.json"])
148148
}

Tests/AppTests/__Snapshots__/WebpageSnapshotTests/test_CustomCollectionShow.1.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ <h1>
8383
<main>
8484
<div class="inner">
8585
<h2 class="trimmed">Packages for collection “Some Collection”</h2>
86+
<p>These packages are available as a package collection,
87+
<a href="/package-collections">usable in Xcode 13 or the Swift Package Manager 5.5</a>.
88+
</p>
89+
<form class="copyable-input">
90+
<input type="text" data-button-name="Copy Package Collection URL" data-event-name="Copy Package Collection URL Button" value="http://localhost:8080/collections/Some%20Collection/collection.json" readonly/>
91+
</form>
92+
<hr class="minor"/>
8693
<ul id="package-list">
8794
<li>
8895
<a href="https://example.com/owner/name.git">

Tests/AppTests/__Snapshots__/WebpageSnapshotTests/test_PackageShowView_customCollection.1.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ <h4>When working with a Swift Package Manager manifest:</h4>
169169
<li class="plugins">No plugins</li>
170170
<li class="macros">2 macros</li>
171171
<li class="custom-collections">
172-
<a href="/collections/Custom Collection">Custom Collection</a>
172+
<a href="/collections/Custom%20Collection">Custom Collection</a>
173173
</li>
174174
</ul>
175175
</section>

0 commit comments

Comments
 (0)