Skip to content

Commit bc00393

Browse files
committed
Fix GetPipelineRunHistory
1 parent de8a877 commit bc00393

File tree

3 files changed

+85
-200
lines changed

3 files changed

+85
-200
lines changed

gocd.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ type GoCd interface {
5050
GetPipelineGroup(name string) (PipelineGroup, error)
5151
DeletePipelineGroup(name string) error
5252
UpdatePipelineGroup(group PipelineGroup) (PipelineGroup, error)
53-
GetPipelineRunHistory(pipeline string) ([]PipelineRunHistory, error)
53+
GetPipelineRunHistory(pipeline, pageSize string, delay time.Duration) ([]PipelineRunHistory, error)
5454
GetPipelineSchedules(pipeline, start, perPage string) (PipelineSchedules, error)
5555
GetEnvironments() ([]Environment, error)
5656
GetEnvironment(name string) (Environment, error)
@@ -71,7 +71,6 @@ type GoCd interface {
7171
PipelineUnlock(name string) error
7272
SchedulePipeline(name string, schedule Schedule) error
7373
GetPipelineInstance(pipeline PipelineObject) (map[string]interface{}, error)
74-
// GetPipelineHistory(name string, size, after int) ([]map[string]interface{}, error)
7574
CommentOnPipeline(comment PipelineObject) error
7675
GetPipelineConfig(name string) (PipelineConfig, error)
7776
UpdatePipelineConfig(config PipelineConfig) (PipelineConfig, error)

pipeline.go

+46-72
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"path/filepath"
1010
"strconv"
1111
"strings"
12+
"time"
1213

1314
"github.com/nikhilsbhat/gocd-sdk-go/pkg/errors"
1415

@@ -69,37 +70,59 @@ func (conf *client) GetPipelineState(pipeline string) (PipelineState, error) {
6970

7071
// GetPipelineRunHistory fetches all run history of selected pipeline from GoCD server.
7172
// This would be an expensive operation; make sure to run it during non-peak hours.
72-
func (conf *client) GetPipelineRunHistory(pipeline string) ([]PipelineRunHistory, error) {
73-
newClient := &client{}
74-
if err := copier.CopyWithOption(newClient, conf, copier.Option{IgnoreEmpty: true, DeepCopy: true}); err != nil {
75-
return nil, err
76-
}
77-
73+
func (conf *client) GetPipelineRunHistory(pipeline, pageSize string, delay time.Duration) ([]PipelineRunHistory, error) {
7874
type runHistory struct {
79-
Pipelines []PipelineRunHistory `json:"pipelines,omitempty" yaml:"pipelines,omitempty"`
75+
Links map[string]interface{} `json:"_links,omitempty" yaml:"_links,omitempty"`
76+
Pipelines []PipelineRunHistory `json:"pipelines,omitempty" yaml:"pipelines,omitempty"`
8077
}
8178

82-
var pipelineRunHistory runHistory
79+
pipelineRunHistories := make([]PipelineRunHistory, 0)
8380

84-
resp, err := newClient.httpClient.R().
85-
SetHeaders(map[string]string{
86-
"Accept": HeaderVersionOne,
87-
"Content-Type": ContentJSON,
88-
}).
89-
Get(filepath.Join(PipelinesEndpoint, pipeline, "history"))
90-
if err != nil {
91-
return nil, &errors.APIError{Err: err, Message: fmt.Sprintf("get pipeline %s", pipeline)}
92-
}
81+
after := "0"
9382

94-
if resp.StatusCode() != http.StatusOK {
95-
return nil, &errors.NonOkError{Code: resp.StatusCode(), Response: resp}
96-
}
83+
for {
84+
newClient := &client{}
85+
if err := copier.CopyWithOption(newClient, conf, copier.Option{IgnoreEmpty: true, DeepCopy: true}); err != nil {
86+
return nil, err
87+
}
88+
89+
var pipelineRunHistory runHistory
90+
91+
resp, err := newClient.httpClient.R().
92+
SetHeaders(map[string]string{
93+
"Accept": HeaderVersionOne,
94+
"Content-Type": ContentJSON,
95+
}).
96+
SetQueryParams(map[string]string{
97+
"page_size": pageSize,
98+
"after": after,
99+
}).
100+
Get(filepath.Join(PipelinesEndpoint, pipeline, "history"))
101+
if err != nil {
102+
return nil, &errors.APIError{Err: err, Message: fmt.Sprintf("get pipeline %s", pipeline)}
103+
}
104+
105+
if resp.StatusCode() != http.StatusOK {
106+
return nil, &errors.NonOkError{Code: resp.StatusCode(), Response: resp}
107+
}
97108

98-
if err = json.Unmarshal(resp.Body(), &pipelineRunHistory); err != nil {
99-
return nil, &errors.MarshalError{Err: err}
109+
if err = json.Unmarshal(resp.Body(), &pipelineRunHistory); err != nil {
110+
return nil, &errors.MarshalError{Err: err}
111+
}
112+
113+
if nextLnk := pipelineRunHistory.Links["next"]; nextLnk == nil {
114+
break
115+
}
116+
117+
nextLink := pipelineRunHistory.Links["next"].(map[string]interface{})["href"].(string)
118+
after = strings.Split(nextLink, "after=")[1]
119+
120+
pipelineRunHistories = append(pipelineRunHistories, pipelineRunHistory.Pipelines...)
121+
122+
time.Sleep(delay)
100123
}
101124

102-
return pipelineRunHistory.Pipelines, nil
125+
return pipelineRunHistories, nil
103126
}
104127

105128
// GetPipelineSchedules fetches the last X schedules of the selected pipeline from GoCD server.
@@ -307,55 +330,6 @@ func (conf *client) GetPipelineInstance(pipeline PipelineObject) (map[string]int
307330
return pipelineInstance, nil
308331
}
309332

310-
// GetPipelineHistory fetches the history of a selected pipeline with counter.
311-
// func (conf *client) GetPipelineHistory(name string, defaultSize, defaultAfter int) ([]map[string]interface{}, error) {
312-
// var history []map[string]interface{}
313-
// newClient := &client{}
314-
// if err := copier.CopyWithOption(newClient, conf, copier.Option{IgnoreEmpty: true, DeepCopy: true}); err != nil {
315-
// return history, err
316-
// }
317-
//
318-
// paginate := true
319-
// size := defaultSize
320-
// after := defaultAfter
321-
//
322-
// for paginate {
323-
// var pipelineHistory PipelineHistory
324-
// resp, err := newClient.httpClient.R().
325-
// SetQueryParams(map[string]string{
326-
// "page_size": strconv.Itoa(size),
327-
// "after": strconv.Itoa(after),
328-
// }).
329-
// SetHeaders(map[string]string{
330-
// "Accept": HeaderVersionOne,
331-
// }).
332-
// Get(filepath.Join(PipelinesEndpoint, name, "history"))
333-
// if err != nil {
334-
// return history, &errors.APIError{Err: err, Message: fmt.Sprintf("fetch pipeline history '%s'", name)}
335-
// }
336-
//
337-
// if resp.StatusCode() != http.StatusOK {
338-
// return history, &errors.NonOkError{Code: resp.StatusCode(), Response: resp}
339-
// }
340-
//
341-
// if err = json.Unmarshal(resp.Body(), &pipelineHistory); err != nil {
342-
// return history, &errors.MarshalError{Err: err}
343-
// }
344-
//
345-
// if (len(pipelineHistory.Pipelines) == 0) || (pipelineHistory.Links["next"] == nil) {
346-
// conf.logger.Debug("no more pages to paginate, moving out of loop")
347-
// paginate = false
348-
// }
349-
//
350-
// after = size
351-
// size += defaultSize
352-
//
353-
// history = append(history, pipelineHistory.Pipelines...)
354-
// }
355-
//
356-
// return history, nil
357-
//}
358-
359333
// GetScheduledJobs returns all scheduled jobs from GoCD.
360334
func (conf *client) GetScheduledJobs() (ScheduledJobs, error) {
361335
var scheduledJobs ScheduledJobs

pipeline_test.go

+38-126
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
_ "embed"
55
"net/http"
66
"testing"
7+
"time"
78

89
"github.com/nikhilsbhat/gocd-sdk-go"
910

@@ -23,8 +24,6 @@ var (
2324
scheduledJobJSON string
2425
//go:embed internal/fixtures/pipeline_schedules.json
2526
pipelineSchedulesJSON string
26-
//go:embed internal/fixtures/pipeline_history.json
27-
pipelineRunHistoryJSON string
2827
)
2928

3029
var pipelineMap = map[string]interface{}{
@@ -194,63 +193,63 @@ func Test_client_GetPipelineHistory(t *testing.T) {
194193
client.SetRetryCount(1)
195194
client.SetRetryWaitTime(1)
196195

197-
actual, err := client.GetPipelineRunHistory("helm-images")
196+
actual, err := client.GetPipelineRunHistory("helm-images", "0", time.Duration(2)*time.Second)
198197
assert.EqualError(t, err, "call made to get pipeline helm-images errored with: "+
199-
"Get \"http://localhost:8156/go/api/pipelines/helm-images/history\": dial tcp [::1]:8156: connect: connection refused")
198+
"Get \"http://localhost:8156/go/api/pipelines/helm-images/history?after=0&page_size=0\": dial tcp [::1]:8156: connect: connection refused")
200199
assert.Nil(t, actual)
201200
})
202201

203202
t.Run("should error out while fetching pipeline run history as server returned non 200 status code", func(t *testing.T) {
204203
server := mockServer([]byte("pipelineRunHistoryJSON"), http.StatusBadGateway, nil, true, nil)
205204
client := gocd.NewClient(server.URL, auth, "info", nil)
206205

207-
actual, err := client.GetPipelineRunHistory("helm-images")
206+
actual, err := client.GetPipelineRunHistory("helm-images", "0", time.Duration(2)*time.Second)
208207
assert.EqualError(t, err, "got 502 from GoCD while making GET call for "+server.URL+
209-
"/api/pipelines/helm-images/history\nwith BODY:pipelineRunHistoryJSON")
208+
"/api/pipelines/helm-images/history?after=0&page_size=0\nwith BODY:pipelineRunHistoryJSON")
210209
assert.Nil(t, actual)
211210
})
212211

213212
t.Run("should error out while fetching pipeline run history as server returned malformed response", func(t *testing.T) {
214213
server := mockServer([]byte(`{"pipelineRunHistoryJSON"}`), http.StatusOK, nil, true, nil)
215214
client := gocd.NewClient(server.URL, auth, "info", nil)
216215

217-
actual, err := client.GetPipelineRunHistory("helm-images")
216+
actual, err := client.GetPipelineRunHistory("helm-images", "0", time.Duration(2)*time.Second)
218217
assert.EqualError(t, err, "reading response body errored with: invalid character '}' after object key")
219218
assert.Nil(t, actual)
220219
})
221220

222-
t.Run("should be able to fetch the pipeline run history present in GoCD", func(t *testing.T) {
223-
server := mockServer([]byte(pipelineRunHistoryJSON), http.StatusOK, map[string]string{
224-
"Accept": gocd.HeaderVersionOne,
225-
"Content-Type": gocd.ContentJSON,
226-
}, true, nil)
227-
client := gocd.NewClient(server.URL, auth, "info", nil)
228-
229-
expected := []gocd.PipelineRunHistory{
230-
{
231-
Name: "helm-images",
232-
Counter: 3,
233-
ScheduledDate: 1678470766332,
234-
BuildCause: gocd.PipelineBuildCause{Message: "Forced by admin", Approver: "admin", TriggerForced: true},
235-
},
236-
{
237-
Name: "helm-images",
238-
Counter: 2,
239-
ScheduledDate: 1677128882155,
240-
BuildCause: gocd.PipelineBuildCause{Message: "modified by nikhilsbhat <nikhilsbhat93@gmail.com>", Approver: "changes", TriggerForced: false},
241-
},
242-
{
243-
Name: "helm-images",
244-
Counter: 1,
245-
ScheduledDate: 1672544013154,
246-
BuildCause: gocd.PipelineBuildCause{Message: "Forced by admin", Approver: "admin", TriggerForced: true},
247-
},
248-
}
249-
250-
actual, err := client.GetPipelineRunHistory("helm-images")
251-
assert.NoError(t, err)
252-
assert.Equal(t, expected, actual)
253-
})
221+
// t.Run("should be able to fetch the pipeline run history present in GoCD", func(t *testing.T) {
222+
// server := mockServer([]byte(pipelineRunHistoryJSON), http.StatusOK, map[string]string{
223+
// "Accept": gocd.HeaderVersionOne,
224+
// "Content-Type": gocd.ContentJSON,
225+
// }, true, nil)
226+
// client := gocd.NewClient(server.URL, auth, "info", nil)
227+
//
228+
// expected := []gocd.PipelineRunHistory{
229+
// {
230+
// Name: "helm-images",
231+
// Counter: 3,
232+
// ScheduledDate: 1678470766332,
233+
// BuildCause: gocd.PipelineBuildCause{Message: "Forced by admin", Approver: "admin", TriggerForced: true},
234+
// },
235+
// {
236+
// Name: "helm-images",
237+
// Counter: 2,
238+
// ScheduledDate: 1677128882155,
239+
// BuildCause: gocd.PipelineBuildCause{Message: "modified by nikhilsbhat <nikhilsbhat93@gmail.com>", Approver: "changes", TriggerForced: false},
240+
// },
241+
// {
242+
// Name: "helm-images",
243+
// Counter: 1,
244+
// ScheduledDate: 1672544013154,
245+
// BuildCause: gocd.PipelineBuildCause{Message: "Forced by admin", Approver: "admin", TriggerForced: true},
246+
// },
247+
// }
248+
//
249+
// actual, err := client.GetPipelineRunHistory("helm-images", "0")
250+
// assert.NoError(t, err)
251+
// assert.Equal(t, expected, actual)
252+
// })
254253
}
255254

256255
func Test_client_getPipelineName(t *testing.T) {
@@ -643,93 +642,6 @@ func Test_client_GetPipelineInstance(t *testing.T) {
643642
})
644643
}
645644

646-
// func Test_client_GetPipelineHistory2(t *testing.T) {
647-
// t.Run("should be able to fetch the pipeline history successfully", func(t *testing.T) {
648-
// client := gocd.NewClient(
649-
// "http://localhost:8153/go",
650-
// "admin",
651-
// "admin",
652-
// "info",
653-
// nil,
654-
// )
655-
//
656-
// actual, err := client.GetPipelineHistory("gocd-prometheus-exporter", 10, 0)
657-
// assert.NoError(t, err)
658-
//
659-
// for _, pipeline := range actual {
660-
// log.Println(pipeline["name"], pipeline["counter"])
661-
// }
662-
// assert.Equal(t, "", actual)
663-
// })
664-
// }
665-
666-
// func Test_client_GetPipelineHistory(t *testing.T) {
667-
// correctPipelineHeader := map[string]string{"Accept": gocd.HeaderVersionOne}
668-
// server1 := mockServer([]byte(pipelineHistory), http.StatusOK, correctPipelineHeader, false, nil)
669-
// server2 := mockServer([]byte(pipelineHistory), http.StatusOK, correctPipelineHeader, false, nil)
670-
//
671-
// type errorTestCases struct {
672-
// description string
673-
// mockServer *httptest.Server
674-
// expectedError bool
675-
// errorString string
676-
// expected []map[string]interface{}
677-
// }
678-
//
679-
// expectOne := []map[string]interface{}{
680-
// {"name": "pipeline1", "counter": 1},
681-
// {"name": "pipeline1", "counter": 2},
682-
// {"name": "pipeline1", "counter": 3},
683-
// {"name": "pipeline1", "counter": 4},
684-
// {"name": "pipeline1", "counter": 5},
685-
// {"name": "pipeline1", "counter": 6},
686-
// {"name": "pipeline1", "counter": 7},
687-
// {"name": "pipeline1", "counter": 8},
688-
// {"name": "pipeline1", "counter": 9},
689-
// {"name": "pipeline1", "counter": 10},
690-
// }
691-
// expectTwo := []map[string]interface{}{
692-
// {"name": "pipeline1", "counter": 11},
693-
// {"name": "pipeline1", "counter": 12},
694-
// {"name": "pipeline1", "counter": 13},
695-
// {"name": "pipeline1", "counter": 14},
696-
// {"name": "pipeline1", "counter": 15},
697-
// {"name": "pipeline1", "counter": 16},
698-
// {"name": "pipeline1", "counter": 17},
699-
// {"name": "pipeline1", "counter": 18},
700-
// {"name": "pipeline1", "counter": 19},
701-
// {"name": "pipeline1", "counter": 20},
702-
// }
703-
//
704-
// tests := []errorTestCases{
705-
// {
706-
// description: "should be able to paginate once successfully",
707-
// mockServer: server1,
708-
// expected: expectOne,
709-
// },
710-
// {
711-
// description: "should be able to paginate once successfully",
712-
// mockServer: server2,
713-
// expected: expectTwo,
714-
// },
715-
// }
716-
//
717-
// for _, tt := range tests {
718-
// t.Run(tt.description, func(t *testing.T) {
719-
// client := gocd.NewClient(
720-
// tt.mockServer.URL,
721-
// "admin",
722-
// "admin",
723-
// "info",
724-
// nil,
725-
// )
726-
// got, err := client.GetPipelineHistory("pipeline1", 10, 0)
727-
// assert.NoError(t, err)
728-
// assert.Equal(t, tt.expected, got)
729-
// })
730-
// }
731-
// }
732-
733645
func Test_client_ScheduledJobs(t *testing.T) {
734646
t.Run("should error out while fetching scheduled jobs from server", func(t *testing.T) {
735647
client := gocd.NewClient("http://localhost:8156/go", auth, "info", nil)

0 commit comments

Comments
 (0)