From 72efedba614355b48109206ecf2cd3e2ce62731d Mon Sep 17 00:00:00 2001 From: William Boman Date: Sat, 8 Oct 2022 15:34:20 +0200 Subject: [PATCH] feat(registry): add api module (#524) --- lua/mason-core/managers/github/client.lua | 41 +++++++++-------------- lua/mason-registry/api.lua | 21 ++++++++++++ tests/mason-registry/api_spec.lua | 37 ++++++++++++++++++++ 3 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 lua/mason-registry/api.lua create mode 100644 tests/mason-registry/api_spec.lua diff --git a/lua/mason-core/managers/github/client.lua b/lua/mason-core/managers/github/client.lua index 9ef914799..dd77f39dd 100644 --- a/lua/mason-core/managers/github/client.lua +++ b/lua/mason-core/managers/github/client.lua @@ -2,6 +2,7 @@ local _ = require "mason-core.functional" local log = require "mason-core.log" local fetch = require "mason-core.fetch" local spawn = require "mason-core.spawn" +local api = require "mason-registry.api" local M = {} @@ -10,12 +11,14 @@ local M = {} ---@alias GitHubTag {name: string} ---@alias GitHubCommit {sha: string} +local stringify_params = _.compose(_.join "&", _.map(_.join "="), _.sort_by(_.head), _.to_pairs) + ---@param path string ---@param opts { params: table? }? ---@return Result # JSON decoded response. -local function api_call(path, opts) +local function gh_api_call(path, opts) if opts and opts.params then - local params = _.join("&", _.map(_.join "=", _.sort_by(_.head, _.to_pairs(opts.params)))) + local params = stringify_params(opts.params) path = ("%s?%s"):format(path, params) end return spawn @@ -27,19 +30,7 @@ local function api_call(path, opts) :map_catching(vim.json.decode) end -M.api_call = api_call - ----@param path string ----@param opts { params: table? }? ----@return Result # JSON decoded response. -local function proxy_api_call(path, opts) - if opts and opts.params then - local params = _.join("&", _.map(_.join "=", _.sort_by(_.head, _.to_pairs(opts.params)))) - path = ("%s?%s"):format(path, params) - end - -- https://github.com/williamboman/github-api-proxy - return fetch(("https://github-api-proxy.redwill.se/%s"):format(path)) -end +M.api_call = gh_api_call ---@async ---@param repo string The GitHub repo ("username/repo"). @@ -47,7 +38,7 @@ end 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 gh_api_call(path):map_err(function() return ("Failed to fetch releases for GitHub repository %s."):format(repo) end) end @@ -58,7 +49,7 @@ end 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 gh_api_call(path):map_err(function() return ("Failed to fetch release %q for GitHub repository %s."):format(tag_name, repo) end) end @@ -71,12 +62,12 @@ end ---@return Result # Result function M.fetch_latest_release(repo, opts) opts = opts or { include_prerelease = false } - local path = ("api/repo/%s/latest-release"):format(repo) - return proxy_api_call(path, { + local path = ("/api/repo/%s/latest-release"):format(repo) + return api.get(path, { params = { include_prerelease = opts.include_prerelease and "true" or "false", }, - }):map_catching(vim.json.decode) + }) end ---@async @@ -84,7 +75,7 @@ end ---@return Result # Result function M.fetch_tags(repo) local path = ("repos/%s/tags"):format(repo) - return api_call(path):map_err(function() + return gh_api_call(path):map_err(function() return ("Failed to fetch tags for GitHub repository %s."):format(repo) end) end @@ -93,8 +84,8 @@ end ---@param repo string The GitHub repo ("username/repo"). ---@return Result # Result The latest tag name. function M.fetch_latest_tag(repo) - local path = ("api/repo/%s/latest-tag"):format(repo) - return proxy_api_call(path):map_catching(vim.json.decode):map(_.prop "tag") + local path = ("/api/repo/%s/latest-tag"):format(repo) + return api.get(path):map(_.prop "tag") end ---@async @@ -103,7 +94,7 @@ end ---@return Result # Result function M.fetch_commits(repo, opts) local path = ("repos/%s/commits"):format(repo) - return api_call(path, { + return gh_api_call(path, { params = { page = opts and opts.page or 1, per_page = opts and opts.per_page or 30, @@ -119,7 +110,7 @@ end ---@async --@return Result @of GitHubRateLimitResponse function M.fetch_rate_limit() - return api_call "rate_limit" + return gh_api_call "rate_limit" end return M diff --git a/lua/mason-registry/api.lua b/lua/mason-registry/api.lua new file mode 100644 index 000000000..1fa01b267 --- /dev/null +++ b/lua/mason-registry/api.lua @@ -0,0 +1,21 @@ +local _ = require "mason-core.functional" +local fetch = require "mason-core.fetch" + +local api = {} + +local stringify_params = _.compose(_.join "&", _.map(_.join "="), _.sort_by(_.head), _.to_pairs) + +---@async +---@param path string +---@param opts { params: table? }? +---@return Result # JSON decoded response. +function api.get(path, opts) + if opts and opts.params then + local params = stringify_params(opts.params) + path = ("%s?%s"):format(path, params) + end + -- https://github.com/williamboman/mason-registry-api + return fetch(("https://api.mason-registry.dev%s"):format(path)):map_catching(vim.json.decode) +end + +return api diff --git a/tests/mason-registry/api_spec.lua b/tests/mason-registry/api_spec.lua new file mode 100644 index 000000000..b871520b1 --- /dev/null +++ b/tests/mason-registry/api_spec.lua @@ -0,0 +1,37 @@ +local stub = require "luassert.stub" +local Result = require "mason-core.result" + +describe("mason-registry API", function() + ---@module "mason-registry.api" + local api + local fetch + before_each(function() + fetch = stub.new() + package.loaded["mason-core.fetch"] = fetch + package.loaded["mason-registry.api"] = nil + api = require "mason-registry.api" + end) + + it("should stringify query parameters", function() + fetch.returns(Result.success [[{}]]) + + api.get("/api/data", { + params = { + page = 2, + page_limit = 10, + sort = "ASC", + }, + }) + + assert.spy(fetch).was_called(1) + assert.spy(fetch).was_called_with "https://api.mason-registry.dev/api/data?page=2&page_limit=10&sort=ASC" + end) + + it("should deserialize JSON", function() + fetch.returns(Result.success [[{"field": ["value"]}]]) + + local result = api.get("/"):get_or_throw() + + assert.same({ field = { "value" } }, result) + end) +end)