mirror of
https://github.com/pesde-pkg/tooling.git
synced 2025-01-10 16:29:09 +00:00
Erica Marigold
ead60c003e
Formerly, we used metatables to get custom `Option` and `Result` objects which were difficult to type properly, leading to a lot of `unknown` and `any` casts. This refactor fixes it by making extensions opt-in, where we import the extension methods separately from the original implementations, thereby allowing us to not have to typecast things everywhere.
116 lines
2.8 KiB
Text
116 lines
2.8 KiB
Text
local net = require("@lune/net")
|
|
|
|
local Result = require("../lune_packages/result")
|
|
local Option = require("../lune_packages/option")
|
|
type Result<T, E> = Result.Result<T, E>
|
|
type Option<T> = Option.Option<T>
|
|
|
|
local copy = require("./utils/copy")
|
|
|
|
local Github = {}
|
|
export type Github = typeof(setmetatable(Github :: GithubFields, { __index = Github }))
|
|
type GithubFields = {
|
|
req: net.FetchParams,
|
|
retries: number,
|
|
}
|
|
|
|
export type Config = {
|
|
authToken: Option<string>,
|
|
retries: Option<number>,
|
|
}
|
|
export type GithubOperation =
|
|
"FetchReleases"
|
|
| "GetMetadata"
|
|
| "GetActionArtifacts"
|
|
| { type: "Custom", payload: net.FetchParams }
|
|
|
|
export type GithubRelease = {
|
|
tag_name: string,
|
|
created_at: string,
|
|
published_at: string,
|
|
prerelease: boolean,
|
|
draft: boolean,
|
|
assets: {
|
|
{
|
|
name: string,
|
|
browser_download_url: string,
|
|
size: number,
|
|
content_type: string,
|
|
}
|
|
},
|
|
}
|
|
export type GithubReleases = { GithubRelease }
|
|
|
|
local API_BASE_URL = "https://api.github.com"
|
|
local DEFAULT_MAX_RETRIES = 5
|
|
local DEFAULT_CONFIG: Config = {
|
|
authToken = Option.None :: Option<string>,
|
|
retries = Option.Some(DEFAULT_MAX_RETRIES) :: Option<number>,
|
|
}
|
|
|
|
function Github.new(repo: string, config: Option<Config>)
|
|
local configOrDefault = config:unwrapOr(DEFAULT_CONFIG)
|
|
return setmetatable(
|
|
{
|
|
req = {
|
|
url = API_BASE_URL .. "/repos/" .. repo,
|
|
headers = {
|
|
["Authorization"] = configOrDefault.authToken:mapOr("", function(token)
|
|
return `Bearer {token}`
|
|
end),
|
|
} :: net.HttpHeaderMap,
|
|
} :: net.FetchParams,
|
|
config = config,
|
|
retries = configOrDefault.retries:unwrapOr(DEFAULT_MAX_RETRIES),
|
|
} :: GithubFields,
|
|
{
|
|
__index = Github,
|
|
}
|
|
)
|
|
end
|
|
|
|
-- FIXME: Remove unknown usage here
|
|
function Github.queueTransactions(self: Github, operations: { GithubOperation }): { Result<unknown, string> }
|
|
local queue: { (retries: number) -> Result<unknown, string> } = table.create(#operations)
|
|
|
|
for _, operation: GithubOperation in operations do
|
|
local req: net.FetchParams = copy(self.req)
|
|
|
|
if operation == "FetchReleases" then
|
|
req.url ..= "/releases"
|
|
req.method = "GET"
|
|
end
|
|
|
|
if typeof(operation) == "table" and operation.type == "Custom" then
|
|
req = operation.payload
|
|
end
|
|
|
|
-- TODO: Other methods
|
|
|
|
table.insert(queue, function(retries: number)
|
|
local lastCode: number
|
|
for _ = 1, retries do
|
|
local resp = net.request(req)
|
|
lastCode = resp.statusCode
|
|
|
|
if not resp.ok then
|
|
continue
|
|
end
|
|
|
|
return Result.Ok(net.jsonDecode(resp.body))
|
|
end
|
|
|
|
return Result.Err(`Github::RespErr(statusCode={lastCode})`)
|
|
end)
|
|
end
|
|
|
|
local results = {}
|
|
for _, req in queue do
|
|
local ok, respRes: Result<unknown, string> = pcall(req, self.retries)
|
|
table.insert(results, if ok then respRes else Result.Err("Github::IoError"))
|
|
end
|
|
|
|
return results
|
|
end
|
|
|
|
return Github
|