-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGraphqlClient.swift
126 lines (100 loc) · 3.22 KB
/
GraphqlClient.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import Foundation
import ArgumentParser
import AsyncHTTPClient
import NIOFoundationCompat
import Yams
import GithubApiClient
import GithubGraphqlQueryable
/// An object representing configuration values for the GraphQL client
struct GraphqlClientConfiguration: Codable {
/// GitHub App ID used to perform the API call
let appId: String
/// GitHub App private key (PEM-encoded) used to perform the API call
let privateKey: String
/// Name of user/organization the GitHub App is installed on, to fetch an installation access token
let username: String
}
struct ProjectItem: GithubGraphqlQueryable, CustomStringConvertible {
struct Project: GithubGraphqlQueryable {
static let query = Node(type: "ProjectV2") {
Field("title", containing: \._title)
Field("url", containing: \._url)
}
@Value var title: String
@Value var url: String
}
struct ProjectFieldValue: GithubGraphqlQueryable {
static let query = Node(type: "ProjectV2ItemFieldSingleSelectValue") {
Field("name", containing: \._value)
Field("field") {
IfType("ProjectV2FieldCommon") {
Field("name", containing: \._field)
}
}
}
@Value var field: String?
@Value var value: String?
}
static let query = Node(type: "ProjectV2Item") {
Field("content") {
IfType("DraftIssue") {
Field("title", containing: \._title)
}
IfType("Issue") {
Field("title", containing: \._title)
Field("url", containing: \._url)
}
IfType("PullRequest") {
Field("title", containing: \._title)
Field("url", containing: \._url)
}
}
FieldList("fieldValues", first: 10, containing: \._fieldValues)
Field("project", containing: \._project)
}
@Value var title: String
@Value var url: String?
@Value var project: Project
@Value var fieldValues: [ProjectFieldValue]
var status: String? {
let statusField = fieldValues.first { $0.field == "Status" }
return statusField?.value
}
var description: String {
return """
title: \(self.title)
url: \(self.url ?? "(None)")
project:
title: \(self.project.title)
url: \(self.project.url)
status: \(self.status ?? "(None)")
"""
}
}
@main
struct GraphqlClient: AsyncParsableCommand {
@Option(name: [.customLong("config"), .short], help: "Path to config file to pull credentials and configuration information from")
var configurationFile: String = "config.yaml"
@Argument(help: "Projects V2 Item node ID for querying the GraphQL API (starts with `PVTI_`)")
var itemId: String
func run() async throws {
let configurationData: Data = try .init(contentsOf: .init(fileURLWithPath: configurationFile))
let decoder = YAMLDecoder()
let configuration = try decoder.decode(GraphqlClientConfiguration.self, from: configurationData)
let client: GithubApiClient = try .init(
appId: configuration.appId,
privateKey: configuration.privateKey
)
do {
let item = try await client.graphqlQuery(ProjectItem.self, id: self.itemId, for: configuration.username)
print(item)
}
catch GithubApiClient.GraphqlError.httpError(let response) {
print("Status: \(response.status)")
let responseBody: Data = .init(buffer: try await response.body.collect(upTo: 10 * 1024))
print("Body:")
print(String(data: responseBody, encoding: .utf8)!)
throw ExitCode.failure
}
}
}