Skip to content

Commit 21bc9d0

Browse files
committed
implement indexing private repos using app installations
1 parent aca8281 commit 21bc9d0

16 files changed

+140
-50
lines changed

Assets/css/Main.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/css/Main.css.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/GitHubAPI/GitHub.Repo.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ extension GitHub
4949
public
5050
var fork:Bool
5151

52-
/// The repo’s visibility on GitHub. Some queries return only public repositories and so
53-
/// omit this field.
52+
/// The repo’s visibility on GitHub.
5453
public
55-
var visibility:RepoVisibility?
54+
var visibility:RepoVisibility
5655
/// The repo’s dominant language, if GitHub was able to detect one.
5756
public
5857
var language:String?
@@ -90,7 +89,7 @@ extension GitHub
9089
archived:Bool,
9190
disabled:Bool,
9291
fork:Bool,
93-
visibility:RepoVisibility? = nil,
92+
visibility:RepoVisibility,
9493
language:String? = nil,
9594
homepage:String? = nil,
9695
about:String? = nil,
@@ -172,7 +171,7 @@ extension GitHub.Repo:JSONObjectDecodable
172171
archived: try json[.archived].decode(),
173172
disabled: try json[.disabled].decode(),
174173
fork: try json[.fork].decode(),
175-
visibility: try json[.visibility]?.decode(),
174+
visibility: try json[.visibility].decode(),
176175
language: try json[.language]?.decode(),
177176
homepage: try json[.homepage]?.decode(),
178177
about: try json[.description]?.decode(),

Sources/GitHubAPI/GitHub.RepoVisibility.swift

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,47 @@ import JSON
33
extension GitHub
44
{
55
@frozen public
6-
enum RepoVisibility:String, JSONEncodable, JSONDecodable, Equatable, Sendable
6+
enum RepoVisibility:Equatable, Comparable, Sendable
77
{
8-
case `public`
98
case `private`
9+
case `internal`
10+
case `public`
11+
}
12+
}
13+
extension GitHub.RepoVisibility:CustomStringConvertible
14+
{
15+
@inlinable public
16+
var description:String
17+
{
18+
switch self
19+
{
20+
case .private: "private"
21+
case .internal: "internal"
22+
case .public: "public"
23+
}
1024
}
1125
}
26+
extension GitHub.RepoVisibility:LosslessStringConvertible
27+
{
28+
@inlinable public
29+
init?(_ description:String)
30+
{
31+
// Note: the GraphQL API returns the visibility in all caps, for some reason.
32+
switch description
33+
{
34+
case "PRIVATE": self = .private
35+
case "private": self = .private
36+
37+
case "INTERNAL": self = .internal
38+
case "internal": self = .internal
39+
40+
case "PUBLIC": self = .public
41+
case "public": self = .public
42+
43+
default: return nil
44+
}
45+
}
46+
}
47+
extension GitHub.RepoVisibility:JSONStringDecodable
48+
{
49+
}

Sources/GitHubClient/GitHub.Client.Connection.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,17 @@ extension GitHub.Client
2626
}
2727
}
2828
}
29-
extension GitHub.Client<GitHub.PersonalAccessToken>.Connection
29+
extension GitHub.Client<Void>.Connection
3030
{
3131
/// Run a GraphQL API request.
3232
///
3333
/// The request will be charged to the user associated with the stored token. It is not
3434
/// possible to run a GraphQL API request without a token.
3535
@inlinable public
36-
func post<Response>(query:String,
37-
for _:Response.Type = Response.self) async throws -> GraphQL.Response<Response>
38-
where Response:JSONDecodable
36+
func post<T>(query:String,
37+
expecting _:T.Type = T.self,
38+
with authorization:GitHub.ClientAuthorization) async throws -> GraphQL.Response<T>
39+
where T:JSONDecodable
3940
{
4041
let request:HTTP.Client2.Request = .init(headers:
4142
[
@@ -44,7 +45,7 @@ extension GitHub.Client<GitHub.PersonalAccessToken>.Connection
4445
":authority": self.http2.remote,
4546
":path": "/graphql",
4647

47-
"authorization": "Bearer \(self.app)",
48+
"authorization": authorization.header,
4849

4950
// GitHub will reject the API request if the user-agent is not set.
5051
"user-agent": self.agent,
@@ -65,8 +66,7 @@ extension GitHub.Client<GitHub.PersonalAccessToken>.Connection
6566
if let second:String = response.headers?["x-ratelimit-reset"].first,
6667
let second:Int64 = .init(second)
6768
{
68-
throw GitHub.Client<GitHub.PersonalAccessToken>.RateLimitError.init(
69-
until: .second(second))
69+
throw GitHub.Client<Application>.RateLimitError.init(until: .second(second))
7070
}
7171
else
7272
{

Sources/GitHubClient/GitHub.Client.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ extension GitHub
2727
}
2828
}
2929
}
30-
extension GitHub.Client<GitHub.PersonalAccessToken>
30+
extension GitHub.Client<Void>
3131
{
3232
public static
33-
func graphql(pat:consuming GitHub.PersonalAccessToken,
33+
func graphql(
3434
threads:consuming MultiThreadedEventLoopGroup,
3535
niossl:consuming NIOSSLContext,
36-
as agent:String) -> GitHub.Client<GitHub.PersonalAccessToken>
36+
as agent:String) -> GitHub.Client<Void>
3737
{
3838
.init(http2: .init(threads: threads, niossl: niossl, remote: "api.github.com"),
3939
agent: agent,
40-
app: pat)
40+
app: ())
4141
}
4242
}
4343
extension GitHub.Client where Application:GitHubApplication

Sources/GitHubClient/GitHub.ClientAuthorization.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,21 @@ import GitHubAPI
44
extension GitHub
55
{
66
@frozen public
7-
enum ClientAuthorization
7+
enum ClientAuthorization:Sendable
88
{
99
case basic(GitHub.OAuth)
1010
case token(String)
1111
}
1212
}
1313
extension GitHub.ClientAuthorization
14+
{
15+
@inlinable public
16+
static func token(_ iat:GitHub.InstallationAccessToken) -> Self { .token(iat.rawValue) }
17+
18+
@inlinable public
19+
static func token(_ pat:GitHub.PersonalAccessToken) -> Self { .token(pat.rawValue) }
20+
}
21+
extension GitHub.ClientAuthorization
1422
{
1523
@inlinable
1624
var header:String

Sources/UnidocDB/Packages/Unidoc.PackageRepo (ext).swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extension Unidoc.PackageRepo
4545
created: .init(created),
4646
updated: updated,
4747
license: repo.license.map { .init(spdx: $0.id, name: $0.name) },
48-
private: repo.visibility == .private,
48+
private: repo.visibility < .public,
4949
topics: repo.topics,
5050
master: repo.master,
5151
origin: .github(.init(

Sources/UnidocServer/Operations/Interactions/Unidoc.PackageIndexOperation.Subject.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ extension Unidoc.PackageIndexOperation
22
{
33
enum Subject
44
{
5-
case repo(owner:String, name:String, private:Bool)
5+
case repo(owner:String, name:String, githubInstallation:Int32?)
66
case ref(Unidoc.Package, ref:String)
77
}
88
}
@@ -19,7 +19,9 @@ extension Unidoc.PackageIndexOperation.Subject
1919
return nil
2020
}
2121

22-
self = .repo(owner: owner, name: repo, private: form["private"] == "true")
22+
let githubInstallation:Int32? = form["installation"].flatMap(Int32.init(_:))
23+
24+
self = .repo(owner: owner, name: repo, githubInstallation: githubInstallation)
2325
}
2426
else if
2527
let package:String = form["package"],

Sources/UnidocServer/Operations/Interactions/Unidoc.PackageIndexOperation.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,18 @@ extension Unidoc.PackageIndexOperation:Unidoc.MeteredOperation
4545

4646
switch self.subject
4747
{
48-
case .repo(owner: let owner, name: let repo, private: let `private`):
48+
case .repo(owner: let owner, name: let repo, githubInstallation: let appInstallation):
4949
if let error:Unidoc.PolicyErrorPage = try await self.charge(cost: 8,
5050
from: server,
5151
with: session)
5252
{
5353
return error.response(format: format)
5454
}
5555

56-
let repo:GitHub.Repo? = try await github.connect
56+
let repo:GitHub.Repo? = try await github.connect(
57+
with: .init(githubInstallation: appInstallation))
5758
{
58-
try await $0.lookup(owner: owner, repo: repo, private: `private`)
59+
try await $0.lookup(owner: owner, repo: repo)
5960
}
6061

6162
guard
@@ -110,7 +111,7 @@ extension Unidoc.PackageIndexOperation:Unidoc.MeteredOperation
110111
return error.response(format: format)
111112
}
112113

113-
let ref:GitHub.Ref? = try await github.connect
114+
let ref:GitHub.Ref? = try await github.connect(with: .init())
114115
{
115116
try await $0.lookup(owner: origin.owner, repo: origin.name, ref: ref)
116117
}

0 commit comments

Comments
 (0)