From 55b8a9ea91ea91d299292e42983b37f3dd43e5d9 Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 20:57:42 +0000 Subject: [PATCH 01/12] feat: add support to show jobs from trigger pipelines ( beta ) Currently hard coded to one bridge pipeline --- cmd/app/pipeline.go | 41 +++++-- lua/gitlab/actions/pipeline.lua | 182 ++++++++++++++++++++------------ 2 files changed, 148 insertions(+), 75 deletions(-) diff --git a/cmd/app/pipeline.go b/cmd/app/pipeline.go index 174b4acc..4610a0b0 100644 --- a/cmd/app/pipeline.go +++ b/cmd/app/pipeline.go @@ -24,12 +24,13 @@ type PipelineWithJobs struct { type GetPipelineAndJobsResponse struct { SuccessResponse - Pipeline PipelineWithJobs `json:"latest_pipeline"` + Pipelines []PipelineWithJobs `json:"latest_pipeline"` } type PipelineManager interface { ListProjectPipelines(pid interface{}, opt *gitlab.ListProjectPipelinesOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.PipelineInfo, *gitlab.Response, error) ListPipelineJobs(pid interface{}, pipelineID int, opts *gitlab.ListJobsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Job, *gitlab.Response, error) + ListPipelineBridges(pid interface{}, pipelineID int, opts *gitlab.ListJobsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Bridge, *gitlab.Response, error) RetryPipelineBuild(pid interface{}, pipeline int, options ...gitlab.RequestOptionFunc) (*gitlab.Pipeline, *gitlab.Response, error) } @@ -101,24 +102,52 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque } jobs, res, err := a.client.ListPipelineJobs(a.projectInfo.ProjectId, pipeline.ID, &gitlab.ListJobsOptions{}) - if err != nil { handleError(w, err, "Could not get pipeline jobs", http.StatusInternalServerError) return } + bridges, res, err := a.client.ListPipelineBridges(a.projectInfo.ProjectId, pipeline.ID, &gitlab.ListJobsOptions{}) + + pipelineIdInBridge := bridges[0].DownstreamPipeline.ID + bridgePipelineJobs := []*gitlab.Job{} + if len(jobs) == 0 { + bridgePipelineJobs, res, err = a.client.ListPipelineJobs(a.projectInfo.ProjectId, pipelineIdInBridge, &gitlab.ListJobsOptions{}) + if err != nil { + handleError(w, err, "Could not get pipeline jobs", http.StatusInternalServerError) + return + } + if res.StatusCode >= 300 { + handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) + return + } + } + + if err != nil { + handleError(w, err, "Could not get pipeline bridges", http.StatusInternalServerError) + return + } + if res.StatusCode >= 300 { handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) return } + pipelines := []PipelineWithJobs{ + { + Jobs: bridgePipelineJobs, + LatestPipeline: bridges[0].DownstreamPipeline, + }, + { + Jobs: jobs, + LatestPipeline: pipeline, + }, + } + w.WriteHeader(http.StatusOK) response := GetPipelineAndJobsResponse{ SuccessResponse: SuccessResponse{Message: "Pipeline retrieved"}, - Pipeline: PipelineWithJobs{ - LatestPipeline: pipeline, - Jobs: jobs, - }, + Pipelines: pipelines, } err = json.NewEncoder(w).Encode(response) diff --git a/lua/gitlab/actions/pipeline.lua b/lua/gitlab/actions/pipeline.lua index 00dc5c29..4c0bda80 100644 --- a/lua/gitlab/actions/pipeline.lua +++ b/lua/gitlab/actions/pipeline.lua @@ -12,36 +12,67 @@ local M = { pipeline_popup = nil, } -local function get_latest_pipeline() - local pipeline = state.PIPELINE and state.PIPELINE.latest_pipeline - if type(pipeline) ~= "table" or (type(pipeline) == "table" and u.table_size(pipeline) == 0) then - u.notify("Pipeline not found", vim.log.levels.WARN) - return +local function get_latest_pipelines(count) + count = count or 1 -- Default to 1 if count is not provided + local pipelines = {} + + if not state.PIPELINE then + u.notify("Pipeline state is not initialized", vim.log.levels.WARN) + return nil end - return pipeline -end -local function get_pipeline_jobs() - M.latest_pipeline = get_latest_pipeline() - if not M.latest_pipeline then - return + for i = 1, math.max(count, #state.PIPELINE) do + local pipeline = state.PIPELINE[i].latest_pipeline + if type(pipeline) == "table" and u.table_size(pipeline) > 0 then + table.insert(pipelines, pipeline) + end + end + + if #pipelines == 0 then + u.notify("No valid pipelines found", vim.log.levels.WARN) + return nil end - return u.reverse(type(state.PIPELINE.jobs) == "table" and state.PIPELINE.jobs or {}) + return pipelines +end + + +local function get_pipeline_jobs(idx) + return u.reverse(type(state.PIPELINE[idx].jobs) == "table" and state.PIPELINE[idx].jobs or {}) end -- The function will render the Pipeline state in a popup M.open = function() - M.pipeline_jobs = get_pipeline_jobs() - M.latest_pipeline = get_latest_pipeline() - if M.latest_pipeline == nil then + M.latest_pipelines = get_latest_pipelines() + if not M.latest_pipelines then + return + end + if not M.latest_pipelines or #M.latest_pipelines == 0 then return end - local width = string.len(M.latest_pipeline.web_url) + 10 - local height = 6 + #M.pipeline_jobs + 3 + local max_width = 0 + local total_height = 0 + local pipelines_data = {} + + for idx, pipeline in ipairs(M.latest_pipelines) do + local width = string.len(pipeline.web_url) + 10 + max_width = math.max(max_width, width) + local pipeline_jobs = get_pipeline_jobs(idx) + local pipeline_status = M.get_pipeline_status(idx, false) + local height = 6 + #pipeline_jobs + 3 + total_height = total_height + height + + table.insert(pipelines_data, { + pipeline = pipeline, + pipeline_status = pipeline_status, + jobs = pipeline_jobs, + width = width, + height = 6 + #pipeline_jobs + 3, + lines = {} + }) + end - local pipeline_popup = - Popup(popup.create_popup_state("Loading Pipeline...", state.settings.popup.pipeline, width, height, 60)) + local pipeline_popup = Popup(popup.create_popup_state("Loading Pipelines...", state.settings.popup.pipeline, max_width, total_height, 60)) popup.set_up_autocommands(pipeline_popup, nil, vim.api.nvim_get_current_win()) M.pipeline_popup = pipeline_popup pipeline_popup:mount() @@ -49,57 +80,78 @@ M.open = function() local bufnr = vim.api.nvim_get_current_buf() vim.opt_local.wrap = false - local lines = {} - u.switch_can_edit_buf(bufnr, true) - table.insert(lines, "Status: " .. M.get_pipeline_status(false)) - table.insert(lines, "") - table.insert(lines, string.format("Last Run: %s", u.time_since(M.latest_pipeline.created_at))) - table.insert(lines, string.format("Url: %s", M.latest_pipeline.web_url)) - table.insert(lines, string.format("Triggered By: %s", M.latest_pipeline.source)) - - table.insert(lines, "") - table.insert(lines, "Jobs:") - - local longest_title = u.get_longest_string(u.map(M.pipeline_jobs, function(v) - return v.name - end)) - - local function row_offset(name) - local offset = longest_title - string.len(name) - local res = string.rep(" ", offset + 5) - return res - end - for _, pipeline_job in ipairs(M.pipeline_jobs) do - local offset = row_offset(pipeline_job.name) - local row = string.format( - "%s%s %s (%s)", - pipeline_job.name, - offset, - state.settings.pipeline[pipeline_job.status] or "*", - pipeline_job.status or "" - ) - - table.insert(lines, row) + local all_lines = {} + for _, data in ipairs(pipelines_data) do + local pipeline = data.pipeline + local lines = data.lines + + table.insert(lines, "Status: " .. data.pipeline_status) + table.insert(lines, "") + table.insert(lines, string.format("Last Run: %s", u.time_since(pipeline.created_at))) + table.insert(lines, string.format("Url: %s", pipeline.web_url)) + table.insert(lines, string.format("Triggered By: %s", pipeline.source)) + table.insert(lines, "") + table.insert(lines, "Jobs:") + + local longest_title = u.get_longest_string(u.map(data.jobs, function(v) + return v.name + end)) + + local function row_offset(name) + local offset = longest_title - string.len(name) + local res = string.rep(" ", offset + 5) + return res + end + + for _, pipeline_job in ipairs(data.jobs) do + local offset = row_offset(pipeline_job.name) + local row = string.format( + "%s%s %s (%s)", + pipeline_job.name, + offset, + state.settings.pipeline[pipeline_job.status] or "*", + pipeline_job.status or "" + ) + table.insert(lines, row) + end + + -- Add separator between pipelines + table.insert(lines, "") + table.insert(lines, string.rep("-", max_width)) + table.insert(lines, "") + + -- Append to all_lines + for _, line in ipairs(lines) do + table.insert(all_lines, line) + end end vim.schedule(function() - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) - M.color_status(M.latest_pipeline.status, bufnr, lines[1], 1) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, all_lines) - for i, pipeline_job in ipairs(M.pipeline_jobs) do - M.color_status(pipeline_job.status, bufnr, lines[7 + i], 7 + i) + local line_offset = 0 + for i, data in ipairs(pipelines_data) do + local pipeline = data.pipeline + local lines = data.lines + + M.color_status(pipeline.status, bufnr, all_lines[line_offset + 1], line_offset + 1) + + for j, pipeline_job in ipairs(data.jobs) do + M.color_status(pipeline_job.status, bufnr, all_lines[line_offset + 7 + j], line_offset + 7 + j) + end + + line_offset = line_offset + #lines end - pipeline_popup.border:set_text("top", "Pipeline Status", "center") + pipeline_popup.border:set_text("top", "Pipelines Status", "center") popup.set_popup_keymaps(pipeline_popup, M.retrigger, M.see_logs) u.switch_can_edit_buf(bufnr, false) end) end - M.retrigger = function() - M.latest_pipeline = get_latest_pipeline() + M.latest_pipeline = get_latest_pipelines() if not M.latest_pipeline then return end @@ -173,12 +225,8 @@ end ---colorize the pipeline icon. ---@param wrap_with_color boolean ---@return string -M.get_pipeline_icon = function(wrap_with_color) - M.latest_pipeline = get_latest_pipeline() - if not M.latest_pipeline then - return "" - end - local symbol = state.settings.pipeline[M.latest_pipeline.status] +M.get_pipeline_icon = function(idx, wrap_with_color) + local symbol = state.settings.pipeline[state.PIPELINE[idx].latest_pipeline.status] if not wrap_with_color then return symbol end @@ -196,12 +244,8 @@ end ---colorize the pipeline icon. ---@param wrap_with_color boolean ---@return string -M.get_pipeline_status = function(wrap_with_color) - M.latest_pipeline = get_latest_pipeline() - if not M.latest_pipeline then - return "" - end - return string.format("%s (%s)", M.get_pipeline_icon(wrap_with_color), M.latest_pipeline.status) +M.get_pipeline_status = function(idx, wrap_with_color) + return string.format("%s (%s)", M.get_pipeline_icon(idx, wrap_with_color), state.PIPELINE[idx].latest_pipeline.status) end M.color_status = function(status, bufnr, status_line, linnr) From 18f693c83ad2d2b66e9c9d2dba5e5f2f06ed9588 Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 20:57:42 +0000 Subject: [PATCH 02/12] feat: add support for multiple pipeline in bridge --- cmd/app/pipeline.go | 53 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/cmd/app/pipeline.go b/cmd/app/pipeline.go index 4610a0b0..01d6ae96 100644 --- a/cmd/app/pipeline.go +++ b/cmd/app/pipeline.go @@ -107,47 +107,46 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque return } + if res.StatusCode >= 300 { + handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) + return + } + + pipelines := []PipelineWithJobs{} + pipelines = append(pipelines, PipelineWithJobs{ + Jobs: jobs, + LatestPipeline: pipeline, + }) + bridges, res, err := a.client.ListPipelineBridges(a.projectInfo.ProjectId, pipeline.ID, &gitlab.ListJobsOptions{}) - pipelineIdInBridge := bridges[0].DownstreamPipeline.ID - bridgePipelineJobs := []*gitlab.Job{} - if len(jobs) == 0 { - bridgePipelineJobs, res, err = a.client.ListPipelineJobs(a.projectInfo.ProjectId, pipelineIdInBridge, &gitlab.ListJobsOptions{}) + // Iterate through all bridges + for _, bridge := range bridges { + if bridge.DownstreamPipeline == nil { + continue + } + + pipelineIdInBridge := bridge.DownstreamPipeline.ID + bridgePipelineJobs, res, err := a.client.ListPipelineJobs(a.projectInfo.ProjectId, pipelineIdInBridge, &gitlab.ListJobsOptions{}) if err != nil { - handleError(w, err, "Could not get pipeline jobs", http.StatusInternalServerError) + handleError(w, err, "Could not get pipeline jobs for bridge", http.StatusInternalServerError) return } if res.StatusCode >= 300 { - handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) + handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs for bridge", res.StatusCode) return } - } - - if err != nil { - handleError(w, err, "Could not get pipeline bridges", http.StatusInternalServerError) - return - } - if res.StatusCode >= 300 { - handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) - return + pipelines = append(pipelines, PipelineWithJobs{ + Jobs: bridgePipelineJobs, + LatestPipeline: bridge.DownstreamPipeline, + }) } - pipelines := []PipelineWithJobs{ - { - Jobs: bridgePipelineJobs, - LatestPipeline: bridges[0].DownstreamPipeline, - }, - { - Jobs: jobs, - LatestPipeline: pipeline, - }, - } - w.WriteHeader(http.StatusOK) response := GetPipelineAndJobsResponse{ SuccessResponse: SuccessResponse{Message: "Pipeline retrieved"}, - Pipelines: pipelines, + Pipelines: pipelines, } err = json.NewEncoder(w).Encode(response) From 885fb065afbe4a373d629ce1d9c9c307ad405f19 Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 20:57:42 +0000 Subject: [PATCH 03/12] feat: add name of the bridge pipeline --- cmd/app/pipeline.go | 20 ++++++++++++++++---- lua/gitlab/actions/pipeline.lua | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/cmd/app/pipeline.go b/cmd/app/pipeline.go index 01d6ae96..b5bb614a 100644 --- a/cmd/app/pipeline.go +++ b/cmd/app/pipeline.go @@ -20,6 +20,7 @@ type RetriggerPipelineResponse struct { type PipelineWithJobs struct { Jobs []*gitlab.Job `json:"jobs"` LatestPipeline *gitlab.PipelineInfo `json:"latest_pipeline"` + Name string `json:"name"` } type GetPipelineAndJobsResponse struct { @@ -107,19 +108,29 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque return } - if res.StatusCode >= 300 { - handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) - return - } + if res.StatusCode >= 300 { + handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) + return + } pipelines := []PipelineWithJobs{} pipelines = append(pipelines, PipelineWithJobs{ Jobs: jobs, LatestPipeline: pipeline, + Name: "", }) bridges, res, err := a.client.ListPipelineBridges(a.projectInfo.ProjectId, pipeline.ID, &gitlab.ListJobsOptions{}) + if err != nil { + handleError(w, err, "Could not get pipeline jobs", http.StatusInternalServerError) + return + } + if res.StatusCode >= 300 { + handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) + return + } + // Iterate through all bridges for _, bridge := range bridges { if bridge.DownstreamPipeline == nil { @@ -140,6 +151,7 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque pipelines = append(pipelines, PipelineWithJobs{ Jobs: bridgePipelineJobs, LatestPipeline: bridge.DownstreamPipeline, + Name: bridge.Name, }) } diff --git a/lua/gitlab/actions/pipeline.lua b/lua/gitlab/actions/pipeline.lua index 4c0bda80..0b4d9f0d 100644 --- a/lua/gitlab/actions/pipeline.lua +++ b/lua/gitlab/actions/pipeline.lua @@ -245,7 +245,7 @@ end ---@param wrap_with_color boolean ---@return string M.get_pipeline_status = function(idx, wrap_with_color) - return string.format("%s (%s)", M.get_pipeline_icon(idx, wrap_with_color), state.PIPELINE[idx].latest_pipeline.status) + return string.format("%s %s (%s)", state.PIPELINE[idx].name, M.get_pipeline_icon(idx, wrap_with_color), state.PIPELINE[idx].latest_pipeline.status) end M.color_status = function(status, bufnr, status_line, linnr) From 113226358f6d0440aa687ba96a8e1da65181bf5e Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 20:57:42 +0000 Subject: [PATCH 04/12] style: better formatting --- cmd/app/pipeline.go | 2 +- lua/gitlab/actions/pipeline.lua | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/app/pipeline.go b/cmd/app/pipeline.go index b5bb614a..cc7520ee 100644 --- a/cmd/app/pipeline.go +++ b/cmd/app/pipeline.go @@ -117,7 +117,7 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque pipelines = append(pipelines, PipelineWithJobs{ Jobs: jobs, LatestPipeline: pipeline, - Name: "", + Name: "root", }) bridges, res, err := a.client.ListPipelineBridges(a.projectInfo.ProjectId, pipeline.ID, &gitlab.ListJobsOptions{}) diff --git a/lua/gitlab/actions/pipeline.lua b/lua/gitlab/actions/pipeline.lua index 0b4d9f0d..e19509f7 100644 --- a/lua/gitlab/actions/pipeline.lua +++ b/lua/gitlab/actions/pipeline.lua @@ -59,7 +59,7 @@ M.open = function() max_width = math.max(max_width, width) local pipeline_jobs = get_pipeline_jobs(idx) local pipeline_status = M.get_pipeline_status(idx, false) - local height = 6 + #pipeline_jobs + 3 + local height = 6 + #pipeline_jobs + 4 total_height = total_height + height table.insert(pipelines_data, { @@ -87,7 +87,7 @@ M.open = function() local pipeline = data.pipeline local lines = data.lines - table.insert(lines, "Status: " .. data.pipeline_status) + table.insert(lines, data.pipeline_status) table.insert(lines, "") table.insert(lines, string.format("Last Run: %s", u.time_since(pipeline.created_at))) table.insert(lines, string.format("Url: %s", pipeline.web_url)) @@ -245,7 +245,7 @@ end ---@param wrap_with_color boolean ---@return string M.get_pipeline_status = function(idx, wrap_with_color) - return string.format("%s %s (%s)", state.PIPELINE[idx].name, M.get_pipeline_icon(idx, wrap_with_color), state.PIPELINE[idx].latest_pipeline.status) + return string.format("[%s]: Status: %s (%s)", state.PIPELINE[idx].name, M.get_pipeline_icon(idx, wrap_with_color), state.PIPELINE[idx].latest_pipeline.status) end M.color_status = function(status, bufnr, status_line, linnr) From b0cf1b5be693f16c9923d90851fac8c0539c87d9 Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 20:57:42 +0000 Subject: [PATCH 05/12] chore: implement pipeline bridges mock for testing --- cmd/app/pipeline_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmd/app/pipeline_test.go b/cmd/app/pipeline_test.go index db354946..cde3797b 100644 --- a/cmd/app/pipeline_test.go +++ b/cmd/app/pipeline_test.go @@ -27,6 +27,14 @@ func (f fakePipelineManager) ListPipelineJobs(pid interface{}, pipelineID int, o return []*gitlab.Job{}, resp, err } +func (f fakePipelineManager) ListPipelineBridges(pid interface{}, pipelineID int, opts *gitlab.ListJobsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Bridge, *gitlab.Response, error) { + resp, err := f.handleGitlabError() + if err != nil { + return nil, nil, err + } + return []*gitlab.Bridge{}, resp, err +} + func (f fakePipelineManager) RetryPipelineBuild(pid interface{}, pipeline int, options ...gitlab.RequestOptionFunc) (*gitlab.Pipeline, *gitlab.Response, error) { resp, err := f.handleGitlabError() if err != nil { From 4c8deb81dc7e3e9f1c0472b49653a392405e504c Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 20:57:42 +0000 Subject: [PATCH 06/12] chore: formatting --- cmd/app/pipeline_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/app/pipeline_test.go b/cmd/app/pipeline_test.go index cde3797b..ba090423 100644 --- a/cmd/app/pipeline_test.go +++ b/cmd/app/pipeline_test.go @@ -28,11 +28,11 @@ func (f fakePipelineManager) ListPipelineJobs(pid interface{}, pipelineID int, o } func (f fakePipelineManager) ListPipelineBridges(pid interface{}, pipelineID int, opts *gitlab.ListJobsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Bridge, *gitlab.Response, error) { - resp, err := f.handleGitlabError() - if err != nil { - return nil, nil, err - } - return []*gitlab.Bridge{}, resp, err + resp, err := f.handleGitlabError() + if err != nil { + return nil, nil, err + } + return []*gitlab.Bridge{}, resp, err } func (f fakePipelineManager) RetryPipelineBuild(pid interface{}, pipeline int, options ...gitlab.RequestOptionFunc) (*gitlab.Pipeline, *gitlab.Response, error) { From ed27797e566e408435f9e4ea4f0504f445b93ec7 Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 20:57:42 +0000 Subject: [PATCH 07/12] chore: more informative logging --- cmd/app/pipeline.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/app/pipeline.go b/cmd/app/pipeline.go index cc7520ee..2e573fa1 100644 --- a/cmd/app/pipeline.go +++ b/cmd/app/pipeline.go @@ -123,11 +123,11 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque bridges, res, err := a.client.ListPipelineBridges(a.projectInfo.ProjectId, pipeline.ID, &gitlab.ListJobsOptions{}) if err != nil { - handleError(w, err, "Could not get pipeline jobs", http.StatusInternalServerError) + handleError(w, err, "Could not get pipeline trigger jobs", http.StatusInternalServerError) return } if res.StatusCode >= 300 { - handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs", res.StatusCode) + handleError(w, GenericError{r.URL.Path}, "Could not get pipeline trigger jobs", res.StatusCode) return } @@ -140,11 +140,11 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque pipelineIdInBridge := bridge.DownstreamPipeline.ID bridgePipelineJobs, res, err := a.client.ListPipelineJobs(a.projectInfo.ProjectId, pipelineIdInBridge, &gitlab.ListJobsOptions{}) if err != nil { - handleError(w, err, "Could not get pipeline jobs for bridge", http.StatusInternalServerError) + handleError(w, err, "Could not get jobs for a pipeline form trigger a trigger job", http.StatusInternalServerError) return } if res.StatusCode >= 300 { - handleError(w, GenericError{r.URL.Path}, "Could not get pipeline jobs for bridge", res.StatusCode) + handleError(w, GenericError{r.URL.Path}, "Could not get jobs for a pipeline form trigger a trigger job", res.StatusCode) return } From 0e6649044d010f7941e3428675508ae3850bf3df Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 20:57:42 +0000 Subject: [PATCH 08/12] chore: docs --- cmd/app/pipeline.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/app/pipeline.go b/cmd/app/pipeline.go index 2e573fa1..f801f844 100644 --- a/cmd/app/pipeline.go +++ b/cmd/app/pipeline.go @@ -131,7 +131,6 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque return } - // Iterate through all bridges for _, bridge := range bridges { if bridge.DownstreamPipeline == nil { continue From d88b472744cadfff07b856e27086c651658a3494 Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Sun, 26 Jan 2025 22:28:34 +0000 Subject: [PATCH 09/12] chore: fix typo in error message --- cmd/app/pipeline.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/app/pipeline.go b/cmd/app/pipeline.go index f801f844..a9d61004 100644 --- a/cmd/app/pipeline.go +++ b/cmd/app/pipeline.go @@ -139,11 +139,11 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque pipelineIdInBridge := bridge.DownstreamPipeline.ID bridgePipelineJobs, res, err := a.client.ListPipelineJobs(a.projectInfo.ProjectId, pipelineIdInBridge, &gitlab.ListJobsOptions{}) if err != nil { - handleError(w, err, "Could not get jobs for a pipeline form trigger a trigger job", http.StatusInternalServerError) + handleError(w, err, "Could not get jobs for a pipeline from a trigger job", http.StatusInternalServerError) return } if res.StatusCode >= 300 { - handleError(w, GenericError{r.URL.Path}, "Could not get jobs for a pipeline form trigger a trigger job", res.StatusCode) + handleError(w, GenericError{r.URL.Path}, "Could not get jobs for a pipeline from a trigger job", res.StatusCode) return } From 16ada575c2eda18e3202e47021233e657cffba4a Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Mon, 27 Jan 2025 10:20:52 +0000 Subject: [PATCH 10/12] fix: projectId was not being inferred from downstream pipeline --- cmd/app/pipeline.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/app/pipeline.go b/cmd/app/pipeline.go index a9d61004..9cf90c61 100644 --- a/cmd/app/pipeline.go +++ b/cmd/app/pipeline.go @@ -137,7 +137,7 @@ func (a pipelineService) GetPipelineAndJobs(w http.ResponseWriter, r *http.Reque } pipelineIdInBridge := bridge.DownstreamPipeline.ID - bridgePipelineJobs, res, err := a.client.ListPipelineJobs(a.projectInfo.ProjectId, pipelineIdInBridge, &gitlab.ListJobsOptions{}) + bridgePipelineJobs, res, err := a.client.ListPipelineJobs(bridge.DownstreamPipeline.ProjectID, pipelineIdInBridge, &gitlab.ListJobsOptions{}) if err != nil { handleError(w, err, "Could not get jobs for a pipeline from a trigger job", http.StatusInternalServerError) return From a6d831f24cd39399a68421a4e55b048ae80a1d4f Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Mon, 27 Jan 2025 12:25:09 +0000 Subject: [PATCH 11/12] chore: do not add separator for last pipeline --- lua/gitlab/actions/pipeline.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lua/gitlab/actions/pipeline.lua b/lua/gitlab/actions/pipeline.lua index e19509f7..161027c4 100644 --- a/lua/gitlab/actions/pipeline.lua +++ b/lua/gitlab/actions/pipeline.lua @@ -59,7 +59,7 @@ M.open = function() max_width = math.max(max_width, width) local pipeline_jobs = get_pipeline_jobs(idx) local pipeline_status = M.get_pipeline_status(idx, false) - local height = 6 + #pipeline_jobs + 4 + local height = 6 + #pipeline_jobs + 3 total_height = total_height + height table.insert(pipelines_data, { @@ -83,7 +83,7 @@ M.open = function() u.switch_can_edit_buf(bufnr, true) local all_lines = {} - for _, data in ipairs(pipelines_data) do + for i, data in ipairs(pipelines_data) do local pipeline = data.pipeline local lines = data.lines @@ -118,11 +118,12 @@ M.open = function() end -- Add separator between pipelines - table.insert(lines, "") - table.insert(lines, string.rep("-", max_width)) - table.insert(lines, "") + if i < #pipelines_data then + table.insert(lines, "") + table.insert(lines, string.rep("-", max_width)) + table.insert(lines, "") + end - -- Append to all_lines for _, line in ipairs(lines) do table.insert(all_lines, line) end From 8d9cd52a065c8bc869340ce17327c13861bea340 Mon Sep 17 00:00:00 2001 From: "ashish.alex10@gmail.com" Date: Thu, 30 Jan 2025 17:24:20 +0000 Subject: [PATCH 12/12] fix: lua linting --- .github/CONTRIBUTING.md | 6 +++--- lua/gitlab/actions/pipeline.lua | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d220b816..a92dfb02 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -10,7 +10,7 @@ It's possible that the feature you want is already implemented, or does not belo If you are using Lazy as a plugin manager, the easiest way to work on changes is by setting a specific path for the plugin that points to your repository locally. This is what I do: -```lua +```lua { "harrisoncramer/gitlab.nvim", dependencies = { @@ -54,8 +54,8 @@ $ luacheck --globals vim busted --no-max-line-length -- . 4. Make the merge request to the `develop` branch of `.gitlab.nvim` -Please provide a description of the feature, and links to any relevant issues. +Please provide a description of the feature, and links to any relevant issues. -That's it! I'll try to respond to any incoming merge request in a few days. Once we've reviewed it, it will be merged into the develop branch. +That's it! I'll try to respond to any incoming merge request in a few days. Once we've reviewed it, it will be merged into the develop branch. After some time, if the develop branch is found to be stable, that branch will be merged into `main` and released. When merged into `main` the pipeline will detect whether we're merging in a patch, minor, or major change, and create a new tag (e.g. 1.0.12) and release. diff --git a/lua/gitlab/actions/pipeline.lua b/lua/gitlab/actions/pipeline.lua index 161027c4..bc113c2d 100644 --- a/lua/gitlab/actions/pipeline.lua +++ b/lua/gitlab/actions/pipeline.lua @@ -35,7 +35,6 @@ local function get_latest_pipelines(count) return pipelines end - local function get_pipeline_jobs(idx) return u.reverse(type(state.PIPELINE[idx].jobs) == "table" and state.PIPELINE[idx].jobs or {}) end @@ -68,11 +67,12 @@ M.open = function() jobs = pipeline_jobs, width = width, height = 6 + #pipeline_jobs + 3, - lines = {} + lines = {}, }) end - local pipeline_popup = Popup(popup.create_popup_state("Loading Pipelines...", state.settings.popup.pipeline, max_width, total_height, 60)) + local pipeline_popup = + Popup(popup.create_popup_state("Loading Pipelines...", state.settings.popup.pipeline, max_width, total_height, 60)) popup.set_up_autocommands(pipeline_popup, nil, vim.api.nvim_get_current_win()) M.pipeline_popup = pipeline_popup pipeline_popup:mount() @@ -119,10 +119,10 @@ M.open = function() -- Add separator between pipelines if i < #pipelines_data then - table.insert(lines, "") - table.insert(lines, string.rep("-", max_width)) - table.insert(lines, "") - end + table.insert(lines, "") + table.insert(lines, string.rep("-", max_width)) + table.insert(lines, "") + end for _, line in ipairs(lines) do table.insert(all_lines, line) @@ -133,7 +133,7 @@ M.open = function() vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, all_lines) local line_offset = 0 - for i, data in ipairs(pipelines_data) do + for _, data in ipairs(pipelines_data) do local pipeline = data.pipeline local lines = data.lines @@ -246,7 +246,12 @@ end ---@param wrap_with_color boolean ---@return string M.get_pipeline_status = function(idx, wrap_with_color) - return string.format("[%s]: Status: %s (%s)", state.PIPELINE[idx].name, M.get_pipeline_icon(idx, wrap_with_color), state.PIPELINE[idx].latest_pipeline.status) + return string.format( + "[%s]: Status: %s (%s)", + state.PIPELINE[idx].name, + M.get_pipeline_icon(idx, wrap_with_color), + state.PIPELINE[idx].latest_pipeline.status + ) end M.color_status = function(status, bufnr, status_line, linnr)