Skip to content

Commit

Permalink
Add support to GET all materials API
Browse files Browse the repository at this point in the history
  • Loading branch information
nikhilsbhat committed Dec 29, 2022
1 parent 7a325a3 commit 8d96eda
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 13 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ linters:
- forcetypeassert
- dupl
- goconst
- maligned

issues:
exclude-rules:
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ Below are the list of supported APIs:
- [x] Create Package Material
- [x] Update Package Material
- [x] Delete Package Material
- [x] [Materials](hhttps://api.gocd.org/current/#materials)
- [x] Get All Materials
- [ ] Get material modifications
- [x] [Site URL](https://api.gocd.org/current/#siteurls-config)
- [x] Get Site URL
- [x] Create or Update Site URL
Expand Down
1 change: 1 addition & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
SecretsConfigEndpoint = "api/admin/secret_configs"
PackageRepositoriesEndpoint = "api/admin/repositories"
PackagesEndpoint = "api/admin/packages"
MaterialEndpoint = "/api/config/materials"
HeaderVersionOne = "application/vnd.go.cd.v1+json"
HeaderVersionTwo = "application/vnd.go.cd.v2+json"
HeaderVersionThree = "application/vnd.go.cd.v3+json"
Expand Down
1 change: 1 addition & 0 deletions gocd.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ type GoCd interface {
CreatePackage(config Package) (Package, error)
UpdatePackage(config Package) (Package, error)
DeletePackage(id string) error
GetMaterials() ([]Material, error)
SetRetryCount(count int)
SetRetryWaitTime(count int)
}
Expand Down
53 changes: 53 additions & 0 deletions internal/fixtures/materials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"_links": {
"doc": {
"href": "https://api.gocd.org/#materials"
},
"self": {
"href": "https://ci.example.com/go/api/config/materials"
}
},
"_embedded": {
"materials": [
{
"type": "svn",
"fingerprint": "6b0cd6b9181434866c555f3c3bb780e950389a456764c876d804c848efbad554",
"attributes": {
"url": "https://github.com/gocd/gocd",
"destination": "test",
"filter": null,
"invert_filter": false,
"name": null,
"auto_update": false,
"username": "admin",
"encrypted_password": "AES:lTFKwi5NvrlqmQ3LOQ5UQA==:Ebggz5N27w54NrhSXKIbng==",
"check_externals": false
}
},
{
"type": "hg",
"fingerprint": "f6b61bc6b33e524c2a94c5be4a4661e5f1d2b74ca089418de20de10b282e39e9",
"attributes": {
"url": "ssh://[email protected]/example/gocd-hg",
"destination": "test",
"filter": null,
"invert_filter": false,
"name": null,
"auto_update": false,
"branch": ""
}
},
{
"type": "dependency",
"fingerprint": "21f7963a8eca6cced5b4f20b57b4e9cb8edaed29d683c83621a77dfb499c553d",
"attributes": {
"pipeline": "up42",
"stage": "up42_stage",
"name": "up42_material",
"auto_update": true,
"ignore_for_scheduling": false
}
}
]
}
}
36 changes: 36 additions & 0 deletions materials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package gocd

import (
"encoding/json"
"fmt"
"net/http"

"github.com/jinzhu/copier"
)

func (conf *client) GetMaterials() ([]Material, error) {
newClient := &client{}
if err := copier.CopyWithOption(newClient, conf, copier.Option{IgnoreEmpty: true, DeepCopy: true}); err != nil {
return nil, err
}

var materials Materials
resp, err := newClient.httpClient.R().
SetHeaders(map[string]string{
"Accept": HeaderVersionTwo,
}).
Get(MaterialEndpoint)
if err != nil {
return nil, fmt.Errorf("call made to get all available materials errored with: %w", err)
}

if resp.StatusCode() != http.StatusOK {
return nil, APIErrorWithBody(resp.String(), resp.StatusCode())
}

if err = json.Unmarshal(resp.Body(), &materials); err != nil {
return nil, ResponseReadError(err.Error())
}

return materials.Materials.Materials, nil
}
150 changes: 150 additions & 0 deletions materials_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package gocd_test

import (
_ "embed"
"net/http"
"testing"

"github.com/nikhilsbhat/gocd-sdk-go"
"github.com/stretchr/testify/assert"
)

//go:embed internal/fixtures/materials.json
var attributesJSON string

func Test_client_GetMaterials(t *testing.T) {
correctArtifactHeader := map[string]string{"Accept": gocd.HeaderVersionTwo}
t.Run("should be able to fetch all available materials present in GoCD successfully", func(t *testing.T) {
server := mockServer([]byte(attributesJSON), http.StatusOK,
correctArtifactHeader, false, nil)

client := gocd.NewClient(
server.URL,
"admin",
"admin",
"info",
nil,
)

expected := []gocd.Material{
{
Type: "svn",
Fingerprint: "6b0cd6b9181434866c555f3c3bb780e950389a456764c876d804c848efbad554",
Attributes: gocd.Attribute{
URL: "https://github.com/gocd/gocd",
Username: "admin",
EncryptedPassword: "AES:lTFKwi5NvrlqmQ3LOQ5UQA==:Ebggz5N27w54NrhSXKIbng==",
Destination: "test",
AutoUpdate: false,
CheckExternals: false,
UseTickets: false,
IgnoreForScheduling: false,
InvertFilter: false,
},
},
{
Type: "hg",
Fingerprint: "f6b61bc6b33e524c2a94c5be4a4661e5f1d2b74ca089418de20de10b282e39e9",
Attributes: gocd.Attribute{
URL: "ssh://[email protected]/example/gocd-hg",
Destination: "test",
AutoUpdate: false,
CheckExternals: false,
UseTickets: false,
IgnoreForScheduling: false,
InvertFilter: false,
},
},
{
Type: "dependency",
Fingerprint: "21f7963a8eca6cced5b4f20b57b4e9cb8edaed29d683c83621a77dfb499c553d",
Attributes: gocd.Attribute{
Pipeline: "up42",
Stage: "up42_stage",
Name: "up42_material",
AutoUpdate: true,
IgnoreForScheduling: false,
},
},
}

actual, err := client.GetMaterials()
assert.NoError(t, err)
assert.Equal(t, expected, actual)
})

t.Run("should error out while fetching all available materials present in GoCD due to wrong headers", func(t *testing.T) {
server := mockServer([]byte(attributesJSON), http.StatusOK,
map[string]string{"Accept": gocd.HeaderVersionThree}, false, nil)

client := gocd.NewClient(
server.URL,
"admin",
"admin",
"info",
nil,
)

var expected []gocd.Material

actual, err := client.GetMaterials()
assert.EqualError(t, err, "body: <html>\n<body>\n\t<h2>404 Not found</h2>\n</body>\n\n</html> httpcode: 404")
assert.Equal(t, expected, actual)
})

t.Run("should error out while fetching all available materials present in GoCD due to missing headers", func(t *testing.T) {
server := mockServer([]byte(attributesJSON), http.StatusOK,
nil, false, nil)
client := gocd.NewClient(
server.URL,
"admin",
"admin",
"info",
nil,
)

var expected []gocd.Material

actual, err := client.GetMaterials()
assert.EqualError(t, err, "body: <html>\n<body>\n\t<h2>404 Not found</h2>\n</body>\n\n</html> httpcode: 404")
assert.Equal(t, expected, actual)
})

t.Run("should error out while fetching all available materials from GoCD as server returned malformed response", func(t *testing.T) {
server := mockServer([]byte("attributesJSON"), http.StatusOK, correctArtifactHeader,
false, nil)
client := gocd.NewClient(
server.URL,
"admin",
"admin",
"info",
nil,
)

var expected []gocd.Material

actual, err := client.GetMaterials()
assert.EqualError(t, err, "reading response body errored with: invalid character 'a' looking for beginning of value")
assert.Equal(t, expected, actual)
})

t.Run("should error out while fetching all available materials present in GoCD as server is not reachable", func(t *testing.T) {
client := gocd.NewClient(
"http://localhost:8156/go",
"admin",
"admin",
"info",
nil,
)

client.SetRetryCount(1)
client.SetRetryWaitTime(1)

var expected []gocd.Material

actual, err := client.GetMaterials()
assert.EqualError(t, err, "call made to get all available materials errored with: "+
"Get \"http://localhost:8156/go/api/config/materials\": dial tcp [::1]:8156: connect: connection refused")
assert.Equal(t, expected, actual)
})
}
56 changes: 43 additions & 13 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,9 @@ type ConfigRepos struct {

// ConfigRepo holds information of the specified config-repo.
type ConfigRepo struct {
PluginID string `json:"plugin_id"`
ID string `json:"config_repos,omitempty"`
Material struct {
Type string `json:"type,omitempty"`
Attributes struct {
URL string `json:"url,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
EncryptedPassword string `json:"encrypted_password,omitempty"`
Branch string `json:"branch,omitempty"`
AutoUpdate bool `json:"auto_update,omitempty"`
}
}
PluginID string `json:"plugin_id"`
ID string `json:"config_repos,omitempty"`
Material Material `json:"material,omitempty"`
Configuration []map[string]interface{} `json:"configuration,omitempty"`
Rules []map[string]interface{} `json:"rules,omitempty"`
ETAG string
Expand Down Expand Up @@ -392,3 +382,43 @@ type Package struct {
Configuration []PluginConfiguration `json:"configuration,omitempty"`
ETAG string `json:"etag,omitempty"`
}

// Materials holds information of all material type present in GoCD.
type Materials struct {
Materials struct {
Materials []Material `json:"materials,omitempty"`
} `json:"_embedded,omitempty"`
}

// Material holds information of a particular material type present in GoCD.
type Material struct {
Type string `json:"type,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
Attributes Attribute `json:"attributes,omitempty"`
}

// Attribute holds information of material type present in GoCD.
type Attribute struct {
URL string `json:"url,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
EncryptedPassword string `json:"encrypted_password,omitempty"`
Branch string `json:"branch,omitempty"`
AutoUpdate bool `json:"auto_update,omitempty"`
CheckExternals bool `json:"check_externals,omitempty"`
UseTickets bool `json:"use_tickets,omitempty"`
View string `json:"view,omitempty"`
Port string `json:"port,omitempty"`
ProjectPath string `json:"project_path,omitempty"`
Domain string `json:"domain,omitempty"`
Ref string `json:"ref,omitempty"`
Name string `json:"name,omitempty"`
Stage string `json:"stage,omitempty"`
Pipeline string `json:"pipeline,omitempty"`
IgnoreForScheduling bool `json:"ignore_for_scheduling,omitempty"`
Destination string `json:"destination,omitempty"`
InvertFilter bool `json:"invert_filter,omitempty"`
Filter struct {
Ignore []string `json:"ignore,omitempty"`
} `json:"filter,omitempty"`
}

0 comments on commit 8d96eda

Please sign in to comment.