Skip to content

Commit

Permalink
refactor: simplify github fetch and render errors inline
Browse files Browse the repository at this point in the history
  • Loading branch information
topaxi committed Dec 3, 2024
1 parent 78c4736 commit c0ce68c
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 88 deletions.
2 changes: 2 additions & 0 deletions lua/pipeline/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ local defaultConfig = {
},
---@class pipeline.config.Highlights
highlights = {
---@type vim.api.keyset.highlight
PipelineError = { link = 'LspDiagnosticsVirtualTextError' },
---@type vim.api.keyset.highlight
PipelineRunIconSuccess = { link = 'LspDiagnosticsVirtualTextHint' },
---@type vim.api.keyset.highlight
Expand Down
146 changes: 62 additions & 84 deletions lua/pipeline/providers/github/rest/_api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,26 @@ end
local M = {}

---@class pipeline.providers.github.rest.FetchOptions
---@field method 'get'|'patch'|'post'|'put'|'delete'
---@field method? 'get'|'patch'|'post'|'put'|'delete'
---@field callback fun(err: plenary.curl.Error|nil, response: table|nil)

---@param server string
---@param path string
---@param opts? pipeline.providers.github.rest.FetchOptions
function M.fetch(server, path, opts)
---@param opts pipeline.providers.github.rest.FetchOptions
local function fetch(server, path, opts)
if vim.fn.has('nvim-0.11') == 1 then
vim.validate('server', server, 'string')
vim.validate('path', path, 'string')
vim.validate('opts', opts, 'table', true)
vim.validate('opts', opts, 'table', 'opts must be a table')
else
vim.validate {
server = { server, 'string' },
path = { path, 'string' },
opts = { opts, 'table', true },
opts = { opts, 'table' },
}
end

opts = opts or {}
opts.callback = opts.callback and vim.schedule_wrap(opts.callback)
opts.callback = vim.schedule_wrap(opts.callback)

local url = string.format('https://api.github.com%s', path)
if server ~= 'github.com' then
Expand Down Expand Up @@ -57,6 +56,38 @@ function M.fetch(server, path, opts)
)
end

---@class pipeline.providers.github.rest.FetchJsonOptions: pipeline.providers.github.rest.FetchOptions
---@field map_response? fun(response: table): any

---@param server string
---@param path string
---@param opts pipeline.providers.github.rest.FetchJsonOptions
local function fetch_json(server, path, opts)
return fetch(
server,
path,
vim.tbl_extend('force', opts, {
callback = function(err, response)
if err then
return opts.callback(err, nil)
end

if not response then
return opts.callback({ message = 'No response body' }, nil)
end

local response_data = vim.json.decode(response.body)

if opts.map_response then
response_data = opts.map_response(response_data)
end

opts.callback(nil, response_data)
end,
})
)
end

---@class GhWorkflow
---@field id number
---@field node_id string
Expand All @@ -75,29 +106,15 @@ end

---@param server string
---@param repo string
---@param opts? { callback?: fun(workflows: GhWorkflow[]): any }
---@param opts { callback: fun(error: plenary.curl.Error|nil, workflows: GhWorkflow[]): any }
function M.get_workflows(server, repo, opts)
opts = opts or {}

return M.fetch(
return fetch_json(
server,
string.format('/repos/%s/actions/workflows', repo),
vim.tbl_deep_extend('force', opts, {
callback = function(err, response)
if err or not response then
return {}
end

---@type GhWorkflowsResponse | nil
local response_data = vim.json.decode(response.body)

local ret = response_data and response_data.workflows or {}

if opts.callback then
return opts.callback(ret)
else
return ret
end
---@param response GhWorkflowsResponse
map_response = function(response)
return response.workflows
end,
})
)
Expand All @@ -121,43 +138,19 @@ end
---@field total_count number
---@field workflow_runs GhWorkflowRun[]

---@param opts? { callback?: fun(workflow_runs: GhWorkflowRun[]): any }
local function process_workflow_runs_response(opts)
opts = opts or {}

---@param err plenary.curl.Error | nil
---@param response table
---@return GhWorkflowRunsResponse
return function(err, response)
if err or not response then
return {}
end

---@type GhWorkflowRunsResponse | nil
local response_data = vim.json.decode(response.body)

local ret = (response_data and response_data.workflow_runs or {})

if opts.callback then
return opts.callback(ret)
else
return ret
end
end
end

---@param server string
---@param repo string
---@param per_page? integer
---@param opts? { callback?: fun(workflow_runs: GhWorkflowRun[]): any }
---@param opts { callback: fun(err: plenary.curl.Error|nil, workflow_runs: GhWorkflowRun[]): any }
function M.get_repository_workflow_runs(server, repo, per_page, opts)
opts = opts or {}

return M.fetch(
return fetch_json(
server,
string.format('/repos/%s/actions/runs', repo),
vim.tbl_deep_extend('force', { query = { per_page = per_page } }, opts, {
callback = process_workflow_runs_response(opts),
---@param response GhWorkflowRunsResponse
map_response = function(response)
return response.workflow_runs
end,
})
)
end
Expand All @@ -166,15 +159,16 @@ end
---@param repo string
---@param workflow_id integer|string
---@param per_page? integer
---@param opts? { callback?: fun(workflow_runs: GhWorkflowRun[]): any }
---@param opts { callback: fun(err: plenary.curl.Error|nil, workflow_runs: GhWorkflowRun[]): any }
function M.get_workflow_runs(server, repo, workflow_id, per_page, opts)
opts = opts or {}

return M.fetch(
return fetch_json(
server,
string.format('/repos/%s/actions/workflows/%d/runs', repo, workflow_id),
vim.tbl_deep_extend('force', { query = { per_page = per_page } }, opts, {
callback = process_workflow_runs_response(opts),
---@param response GhWorkflowRunsResponse
map_response = function(response)
return response.workflow_runs
end,
})
)
end
Expand All @@ -183,11 +177,9 @@ end
---@param repo string
---@param workflow_id integer|string
---@param ref string
---@param opts? table
---@param opts { body: table, callback?: fun(err: plenary.curl.Error|nil, response: unknown): any }
function M.dispatch_workflow(server, repo, workflow_id, ref, opts)
opts = opts or {}

return M.fetch(
return fetch(
server,
string.format(
'/repos/%s/actions/workflows/%d/dispatches',
Expand Down Expand Up @@ -227,29 +219,15 @@ end
---@param repo string
---@param workflow_run_id integer
---@param per_page? integer
---@param opts? { callback?: fun(workflow_runs: GhWorkflowRunJob[]): any }
---@param opts { callback: fun(err: plenary.curl.Error|nil, workflow_runs: GhWorkflowRunJob[]): any }
function M.get_workflow_run_jobs(server, repo, workflow_run_id, per_page, opts)
opts = opts or {}

return M.fetch(
return fetch_json(
server,
string.format('/repos/%s/actions/runs/%d/jobs', repo, workflow_run_id),
vim.tbl_deep_extend('force', { query = { per_page = per_page } }, opts, {
callback = function(err, response)
if err or not response then
return {}
end

---@type GhWorkflowRunJobsResponse | nil
local response_data = vim.json.decode(response.body)

local ret = response_data and response_data.jobs or {}

if opts.callback then
return opts.callback(ret)
else
return ret
end
---@param response GhWorkflowRunJobsResponse
map_response = function(response)
return response.jobs
end,
})
)
Expand Down
12 changes: 8 additions & 4 deletions lua/pipeline/providers/github/rest/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,16 @@ function GithubRestProvider:fetch()
local Mapper = require('pipeline.providers.github.rest._mapper')

gh_api().get_workflows(self.server, self.repo, {
callback = function(workflows)
callback = function(err, workflows)
self.store.update_state(function(state)
state.error = err and err.message or nil
state.pipelines = vim.tbl_map(Mapper.to_pipeline, workflows)
end)
end,
})

gh_api().get_repository_workflow_runs(self.server, self.repo, 100, {
callback = function(workflow_runs)
callback = function(err, workflow_runs)
---@type pipeline.Run[]
local runs = vim.tbl_map(Mapper.to_run, workflow_runs)
---@type pipeline.Run[]
Expand All @@ -79,6 +80,7 @@ function GithubRestProvider:fetch()
:totable()

self.store.update_state(function(state)
state.error = err and err.message or nil
state.latest_run = runs[1]
state.runs = utils.group_by(function(run)
return run.pipeline_id
Expand All @@ -96,8 +98,9 @@ function GithubRestProvider:fetch()

for _, run in ipairs(running_workflows) do
gh_api().get_workflow_run_jobs(self.server, self.repo, run.run_id, 20, {
callback = function(jobs)
callback = function(err, jobs)
self.store.update_state(function(state)
state.error = err and err.message or nil
state.jobs[run.run_id] = vim.tbl_map(Mapper.to_job, jobs)

for _, job in ipairs(jobs) do
Expand Down Expand Up @@ -170,12 +173,13 @@ function GithubRestProvider:dispatch(pipeline)
pipeline.pipeline_id,
5,
{
callback = function(workflow_runs)
callback = function(err, workflow_runs)
local Mapper =
require('pipeline.providers.github.rest._mapper')
local runs = vim.tbl_map(Mapper.to_run, workflow_runs)

store.update_state(function(state)
state.error = err and err.message or nil
state.runs = utils.group_by(
function(run)
return run.pipeline_id
Expand Down
2 changes: 2 additions & 0 deletions lua/pipeline/store.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ local utils = require('pipeline.utils')
---@field title string
---@field repo string
---@field server string
---@field error string|nil
---@field pipelines pipeline.Pipeline[]
---@field runs table<integer | string, pipeline.Run[]> Runs indexed by pipeline id
---@field jobs table<integer | string, pipeline.Job[]> Jobs indexed by run id
Expand All @@ -17,6 +18,7 @@ local initialState = {
title = 'pipeline.nvim',
repo = '',
server = '',
error = nil,
pipelines = {},
latest_run = nil,
runs = {},
Expand Down
9 changes: 9 additions & 0 deletions lua/pipeline/ui/render.lua
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ function PipelineRender:render(bufnr)
local state = self.store:get_state()

self:title(state)
self:error(state)
self:pipelines(state)
self:trim()

Expand All @@ -89,6 +90,14 @@ function PipelineRender:title(state)
self:append(state.title):nl():nl()
end

--- Render error message
---@param state pipeline.State
function PipelineRender:error(state)
if state.error then
self:append(state.error, 'PipelineError'):nl():nl()
end
end

--- Render each pipeline
---@param state pipeline.State
function PipelineRender:pipelines(state)
Expand Down

0 comments on commit c0ce68c

Please sign in to comment.