aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/managers/github/client.lua
diff options
context:
space:
mode:
authorWilliam Boman <william@redwill.se>2022-07-08 18:34:38 +0200
committerGitHub <noreply@github.com>2022-07-08 18:34:38 +0200
commit976aa4fbee8a070f362cab6f6ec84e9251a90cf9 (patch)
tree5e8d9c9c59444a25c7801b8f39763c4ba6e1f76d /lua/mason-core/managers/github/client.lua
parentfeat: add gotests, gomodifytags, impl (#28) (diff)
downloadmason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar
mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.gz
mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.bz2
mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.lz
mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.xz
mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.zst
mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.zip
refactor: add mason-schemas and mason-core modules (#29)
* refactor: add mason-schemas and move generated filetype map to mason-lspconfig * refactor: add mason-core module
Diffstat (limited to 'lua/mason-core/managers/github/client.lua')
-rw-r--r--lua/mason-core/managers/github/client.lua117
1 files changed, 117 insertions, 0 deletions
diff --git a/lua/mason-core/managers/github/client.lua b/lua/mason-core/managers/github/client.lua
new file mode 100644
index 00000000..1bcede7a
--- /dev/null
+++ b/lua/mason-core/managers/github/client.lua
@@ -0,0 +1,117 @@
+local _ = require "mason-core.functional"
+local log = require "mason-core.log"
+local fetch = require "mason-core.fetch"
+local spawn = require "mason-core.spawn"
+
+local M = {}
+
+---@alias GitHubReleaseAsset {url: string, id: integer, name: string, browser_download_url: string, created_at: string, updated_at: string, size: integer, download_count: integer}
+---@alias GitHubRelease {tag_name: string, prerelease: boolean, draft: boolean, assets:GitHubReleaseAsset[]}
+---@alias GitHubTag {name: string}
+
+---@param path string
+---@return Result @JSON decoded response.
+local function api_call(path)
+ return spawn
+ .gh({ "api", path })
+ :map(_.prop "stdout")
+ :recover_catching(function()
+ return fetch(("https://api.github.com/%s"):format(path)):get_or_throw()
+ end)
+ :map_catching(vim.json.decode)
+end
+
+---@async
+---@param repo string @The GitHub repo ("username/repo").
+---@return Result @of GitHubRelease[]
+function M.fetch_releases(repo)
+ log.fmt_trace("Fetching GitHub releases for repo=%s", repo)
+ local path = ("repos/%s/releases"):format(repo)
+ return api_call(path):map_err(function()
+ return ("Failed to fetch releases for GitHub repository %s."):format(repo)
+ end)
+end
+
+---@async
+---@param repo string @The GitHub repo ("username/repo").
+---@param tag_name string @The tag_name of the release to fetch.
+function M.fetch_release(repo, tag_name)
+ log.fmt_trace("Fetching GitHub release for repo=%s, tag_name=%s", repo, tag_name)
+ local path = ("repos/%s/releases/tags/%s"):format(repo, tag_name)
+ return api_call(path):map_err(function()
+ return ("Failed to fetch release %q for GitHub repository %s."):format(tag_name, repo)
+ end)
+end
+
+---@param opts {include_prerelease: boolean, tag_name_pattern: string}
+function M.release_predicate(opts)
+ local is_not_draft = _.prop_eq("draft", false)
+ local is_not_prerelease = _.prop_eq("prerelease", false)
+ local tag_name_matches = _.prop_satisfies(_.matches(opts.tag_name_pattern), "tag_name")
+
+ return _.all_pass {
+ _.if_else(_.always(opts.include_prerelease), _.T, is_not_prerelease),
+ _.if_else(_.always(opts.tag_name_pattern), tag_name_matches, _.T),
+ is_not_draft,
+ }
+end
+
+---@alias FetchLatestGithubReleaseOpts {tag_name_pattern:string|nil, include_prerelease: boolean}
+
+---@async
+---@param repo string @The GitHub repo ("username/repo").
+---@param opts FetchLatestGithubReleaseOpts|nil
+---@return Result @of GitHubRelease
+function M.fetch_latest_release(repo, opts)
+ opts = opts or {
+ tag_name_pattern = nil,
+ include_prerelease = false,
+ }
+ return M.fetch_releases(repo):map_catching(
+ ---@param releases GitHubRelease[]
+ function(releases)
+ local is_stable_release = M.release_predicate(opts)
+ ---@type GitHubRelease|nil
+ local latest_release = _.find_first(is_stable_release, releases)
+
+ if not latest_release then
+ log.fmt_info("Failed to find latest release. repo=%s, opts=%s", repo, opts)
+ error "Failed to find latest release."
+ end
+
+ log.fmt_debug("Resolved latest version repo=%s, tag_name=%s", repo, latest_release.tag_name)
+ return latest_release
+ end
+ )
+end
+
+---@async
+---@param repo string @The GitHub repo ("username/repo").
+---@return Result @of GitHubTag[]
+function M.fetch_tags(repo)
+ local path = ("repos/%s/tags"):format(repo)
+ return api_call(path):map_err(function()
+ return ("Failed to fetch tags for GitHub repository %s."):format(repo)
+ end)
+end
+
+---@async
+---@param repo string @The GitHub repo ("username/repo").
+---@return Result @Result<string> - The latest tag name.
+function M.fetch_latest_tag(repo)
+ -- https://github.com/williamboman/vercel-github-api-latest-tag-proxy
+ return fetch(("https://latest-github-tag.redwill.se/api/latest-tag?repo=%s"):format(repo))
+ :map_catching(vim.json.decode)
+ :map(_.prop "tag")
+end
+
+---@alias GitHubRateLimit {limit: integer, remaining: integer, reset: integer, used: integer}
+---@alias GitHubRateLimitResponse {resources: { core: GitHubRateLimit }}
+
+---@async
+--@return Result @of GitHubRateLimitResponse
+function M.fetch_rate_limit()
+ return api_call "rate_limit"
+end
+
+return M