fix(ci): Fix issue where `ci get` fails if user is not maintainer

This commit is contained in:
Shekhar Patnaik 2023-02-08 18:09:41 +00:00 committed by Gary Holtz
parent b7e9261562
commit 1dbeae7bb6
4 changed files with 200 additions and 21 deletions

View File

@ -172,17 +172,11 @@ var GetPipeline = func(client *gitlab.Client, pid int, l *gitlab.RequestOptionFu
return pipe, nil
}
var GetPipelineVariables = func(client *gitlab.Client, pid int, l *gitlab.RequestOptionFunc, repo interface{}) ([]*gitlab.PipelineVariable, error) {
var GetPipelineVariables = func(client *gitlab.Client, pid int, l *gitlab.RequestOptionFunc, projectID int) ([]*gitlab.PipelineVariable, error) {
if client == nil {
client = apiClient.Lab()
}
pipe, _, err := client.Pipelines.GetPipeline(repo, pid)
if err != nil {
return nil, err
}
projectID := pipe.ProjectID
pipelineVars, _, err := client.Pipelines.GetPipelineVariables(projectID, pid)
if err != nil {
return nil, err

View File

@ -3,6 +3,7 @@ package status
import (
"encoding/json"
"fmt"
"io"
"strconv"
"github.com/xanzy/go-gitlab"
@ -15,6 +16,8 @@ import (
"github.com/spf13/cobra"
)
const NoVariablesInPipelineMessage = "No variables found in pipeline."
type PipelineMergedResponse struct {
*gitlab.Pipeline
Jobs []*gitlab.Job `json:"jobs"`
@ -68,9 +71,14 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command {
return err
}
variables, err := api.GetPipelineVariables(apiClient, pipelineId, nil, repo.FullName())
if err != nil {
return err
showVariables, _ := cmd.Flags().GetBool("with-variables")
var variables []*gitlab.PipelineVariable
if showVariables {
variables, err = api.GetPipelineVariables(apiClient, pipelineId, nil, pipeline.ProjectID)
if err != nil {
return err
}
}
mergedPipelineObject := &PipelineMergedResponse{
@ -83,7 +91,7 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command {
if outputFormat == "json" {
printJSON(*mergedPipelineObject)
} else {
printTable(*mergedPipelineObject)
printTable(*mergedPipelineObject, f.IO.StdOut)
}
return nil
@ -93,6 +101,7 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command {
pipelineGetCmd.Flags().StringP("branch", "b", "", "Check pipeline status for a branch. (Default is current branch)")
pipelineGetCmd.Flags().IntP("pipeline-id", "p", 0, "Provide pipeline ID")
pipelineGetCmd.Flags().StringP("output-format", "o", "text", "Format output as: text, json")
pipelineGetCmd.Flags().Bool("with-variables", false, "Show variables in pipeline (maintainer role required)")
return pipelineGetCmd
}
@ -102,8 +111,8 @@ func printJSON(p PipelineMergedResponse) {
fmt.Println(string(JSONStr))
}
func printTable(p PipelineMergedResponse) {
fmt.Print("# Pipeline:\n")
func printTable(p PipelineMergedResponse, dest io.Writer) {
fmt.Fprint(dest, "# Pipeline:\n")
pipelineTable := tableprinter.NewTablePrinter()
pipelineTable.AddRow("id:", strconv.Itoa(p.ID))
pipelineTable.AddRow("status:", p.Status)
@ -116,20 +125,26 @@ func printTable(p PipelineMergedResponse) {
pipelineTable.AddRow("created:", p.CreatedAt)
pipelineTable.AddRow("started:", p.StartedAt)
pipelineTable.AddRow("updated:", p.UpdatedAt)
fmt.Println(pipelineTable.String())
fmt.Fprintln(dest, pipelineTable.String())
fmt.Print("# Jobs:\n")
fmt.Fprint(dest, "# Jobs:\n")
jobTable := tableprinter.NewTablePrinter()
for _, j := range p.Jobs {
j := j
jobTable.AddRow(j.Name+":", j.Status)
}
fmt.Println(jobTable.String())
fmt.Fprintln(dest, jobTable.String())
fmt.Print("# Variables:\n")
varTable := tableprinter.NewTablePrinter()
for _, v := range p.Variables {
varTable.AddRow(v.Key+":", v.Value)
if p.Variables != nil {
fmt.Fprint(dest, "# Variables:\n")
if len(p.Variables) == 0 {
fmt.Fprint(dest, NoVariablesInPipelineMessage)
}
varTable := tableprinter.NewTablePrinter()
for _, v := range p.Variables {
varTable.AddRow(v.Key+":", v.Value)
}
fmt.Fprintln(dest, varTable.String())
}
fmt.Println(varTable.String())
}

169
commands/ci/get/get_test.go Normal file
View File

@ -0,0 +1,169 @@
package status
import (
"net/http"
"testing"
"gitlab.com/gitlab-org/cli/commands/cmdtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/cli/pkg/httpmock"
"gitlab.com/gitlab-org/cli/test"
)
func runCommand(rt http.RoundTripper, isTTY bool, args string) (*test.CmdOut, error) {
ios, _, stdout, stderr := cmdtest.InitIOStreams(isTTY, "")
factory := cmdtest.InitFactory(ios, rt)
_, _ = factory.HttpClient()
cmd := NewCmdGet(factory)
return cmdtest.ExecuteCommand(cmd, args, stdout, stderr)
}
func TestCIGet(t *testing.T) {
type httpMock struct {
method string
path string
status int
body string
}
tests := []struct {
name string
args string
httpMocks []httpMock
expectedOut string
}{
{
name: "when get is called on an existing pipeline",
args: "-p=123 -b=main",
httpMocks: []httpMock{
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/pipelines/123",
http.StatusOK,
`{
"id": 123,
"iid": 123,
"status": "pending",
"source": "push",
"user": {
"username": "test"
},
"created_at": "2023-10-10T00:00:00Z",
"started_at": "2023-10-10T00:00:00Z",
"updated_at": "2023-10-10T00:00:00Z"
}`,
},
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/pipelines/123/jobs?per_page=100",
http.StatusOK,
`[]`,
},
},
expectedOut: "# Pipeline:\nid:\t123\nstatus:\tpending\nsource:\tpush\nref:\t\nsha:\t\ntag:\tfalse\nyaml Errors:\t\nuser:\ttest\ncreated:\t2023-10-10 00:00:00 +0000 UTC\nstarted:\t2023-10-10 00:00:00 +0000 UTC\nupdated:\t2023-10-10 00:00:00 +0000 UTC\n\n# Jobs:\n\n",
},
{
name: "when get is called on an existing pipeline with variables",
args: "-p=456 -b=main --with-variables",
httpMocks: []httpMock{
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/pipelines/456",
http.StatusOK,
`{
"id": 456,
"iid": 456,
"project_id": 5,
"status": "pending",
"source": "push",
"user": {
"username": "test"
},
"created_at": "2023-10-10T00:00:00Z",
"started_at": "2023-10-10T00:00:00Z",
"updated_at": "2023-10-10T00:00:00Z"
}`,
},
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/pipelines/456/jobs?per_page=100",
http.StatusOK,
`[]`,
},
{
http.MethodGet,
"/api/v4/projects/5/pipelines/456/variables",
http.StatusOK,
`[{
"key": "RUN_NIGHTLY_BUILD",
"variable_type": "env_var",
"value": "true"
}]`,
},
},
expectedOut: "# Pipeline:\nid:\t456\nstatus:\tpending\nsource:\tpush\nref:\t\nsha:\t\ntag:\tfalse\nyaml Errors:\t\nuser:\ttest\ncreated:\t2023-10-10 00:00:00 +0000 UTC\nstarted:\t2023-10-10 00:00:00 +0000 UTC\nupdated:\t2023-10-10 00:00:00 +0000 UTC\n\n# Jobs:\n\n# Variables:\nRUN_NIGHTLY_BUILD:\ttrue\n\n",
},
{
name: "when get is called on an existing pipeline with variables however no variables are found",
args: "-p=456 -b=main --with-variables",
httpMocks: []httpMock{
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/pipelines/456",
http.StatusOK,
`{
"id": 456,
"iid": 456,
"project_id": 5,
"status": "pending",
"source": "push",
"user": {
"username": "test"
},
"created_at": "2023-10-10T00:00:00Z",
"started_at": "2023-10-10T00:00:00Z",
"updated_at": "2023-10-10T00:00:00Z"
}`,
},
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/pipelines/456/jobs?per_page=100",
http.StatusOK,
`[]`,
},
{
http.MethodGet,
"/api/v4/projects/5/pipelines/456/variables",
http.StatusOK,
"[]",
},
},
expectedOut: "# Pipeline:\nid:\t456\nstatus:\tpending\nsource:\tpush\nref:\t\nsha:\t\ntag:\tfalse\nyaml Errors:\t\nuser:\ttest\ncreated:\t2023-10-10 00:00:00 +0000 UTC\nstarted:\t2023-10-10 00:00:00 +0000 UTC\nupdated:\t2023-10-10 00:00:00 +0000 UTC\n\n# Jobs:\n\n# Variables:\nNo variables found in pipeline.\n",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
fakeHTTP := &httpmock.Mocker{
MatchURL: httpmock.PathAndQuerystring,
}
defer fakeHTTP.Verify(t)
for _, mock := range tc.httpMocks {
fakeHTTP.RegisterResponder(mock.method, mock.path, httpmock.NewStringResponse(mock.status, mock.body))
}
output, err := runCommand(fakeHTTP, false, tc.args)
require.Nil(t, err)
assert.Equal(t, tc.expectedOut, output.String())
assert.Empty(t, output.Stderr())
})
}
}

View File

@ -31,6 +31,7 @@ glab ci -R some/project -p 12345
-b, --branch string Check pipeline status for a branch. (Default is current branch)
-o, --output-format string Format output as: text, json (default "text")
-p, --pipeline-id int Provide pipeline ID
--with-variables Show variables in pipeline (maintainer role required)
```
## Options inherited from parent commands