Skip to content

Commit

Permalink
Split client and provider into separate packages (#2)
Browse files Browse the repository at this point in the history
* Add client package

* Added project import

Fix token defaults

* Add pipeline import

* Add project tests

* Refactoring

* Add pipeline tests

* Fix pipeline triggers

* Added tests for pipeline triggers

* Refactoring

* Add original_yaml_string and runtime_environment to pipeline

* Add pipeline revision

* Added a test for pipeline revision

* Fix SetVariables methods
  • Loading branch information
palson-cf authored Jun 9, 2020
1 parent 9f013fe commit b924e06
Show file tree
Hide file tree
Showing 14 changed files with 1,753 additions and 610 deletions.
92 changes: 92 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
)

// Client token, host, htpp.Client
type Client struct {
Token string
Host string
Client *http.Client
}

// RequestOptions path, method, etc
type RequestOptions struct {
Path string
Method string
Body []byte
QS map[string]string
}

// NewClient returns a new client configured to communicate on a server with the
// given hostname and to send an Authorization Header with the value of
// token
func NewClient(hostname string, token string) *Client {
return &Client{
Host: hostname,
Token: token,
Client: &http.Client{},
}

}

// RequestAPI http request to Codefresh API
func (client *Client) RequestAPI(opt *RequestOptions) ([]byte, error) {
finalURL := fmt.Sprintf("%s%s", client.Host, opt.Path)
if opt.QS != nil {
finalURL += ToQS(opt.QS)
}
request, err := http.NewRequest(opt.Method, finalURL, bytes.NewBuffer(opt.Body))
if err != nil {
return nil, err
}

request.Header.Set("Authorization", client.Token)
request.Header.Set("Content-Type", "application/json; charset=utf-8")

resp, err := client.Client.Do(request)

if err != nil {
return nil, err
}
defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("Failed to read body %v %v", resp.StatusCode, resp.Status)
}

if resp.StatusCode != 200 {
return nil, fmt.Errorf("%v, %s", resp.Status, string(body))
}
return body, nil
}

// ToQS add extra parameters to path
func ToQS(qs map[string]string) string {
var arr = []string{}
for k, v := range qs {
arr = append(arr, fmt.Sprintf("%s=%s", k, v))
}
return "?" + strings.Join(arr, "&")
}

// DecodeResponseInto json Unmarshall
func DecodeResponseInto(body []byte, target interface{}) error {
return json.Unmarshal(body, target)
}

// EncodeToJSON json Marshal
func EncodeToJSON(object interface{}) ([]byte, error) {
body, err := json.Marshal(object)
if err != nil {
return nil, err
}
return body, nil
}
198 changes: 198 additions & 0 deletions client/pipeline.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package client

import (
"errors"
"fmt"
"strings"
)

type ErrorResponse struct {
Status int `json:"status,omitempty"`
Message string `json:"message,omitempty"`
Error string `json:"error,omitempty"`
}

type Labels struct {
Tags []string `json:"tags,omitempty"`
}

type Metadata struct {
Name string `json:"name,omitempty"`
ID string `json:"id,omitempty"`
Labels Labels `json:"labels,omitempty"`
OriginalYamlString string `json:"originalYamlString,omitempty"`
Project string `json:"project,omitempty"`
ProjectId string `json:"projectId,omitempty"`
Revision int `json:"revision,omitempty"`
}

type SpecTemplate struct {
Location string `json:"location,omitempty"`
Repo string `json:"repo,omitempty"`
Path string `json:"path,omitempty"`
Revision string `json:"revision,omitempty"`
Context string `json:"context,omitempty"`
}

type Trigger struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Type string `json:"type,omitempty"`
Repo string `json:"repo,omitempty"`
Events []string `json:"events,omitempty"`
BranchRegex string `json:"branchRegex,omitempty"`
ModifiedFilesGlob string `json:"modifiedFilesGlob,omitempty"`
Provider string `json:"provider,omitempty"`
Disabled bool `json:"disabled,omitempty"`
Context string `json:"context,omitempty"`
Variables []Variable `json:"variables,omitempty"`
}

type RuntimeEnvironment struct {
Name string `json:"name,omitempty"`
Memory string `json:"memory,omitempty"`
CPU string `json:"cpu,omitempty"`
DindStorage string `json:"dindStorage,omitempty"`
}

func (t *Trigger) SetVariables(variables map[string]string) {
for key, value := range variables {
t.Variables = append(t.Variables, Variable{Key: key, Value: value})
}
}

type Spec struct {
Variables []Variable `json:"variables,omitempty"`
SpecTemplate *SpecTemplate `json:"specTemplate,omitempty"`
Triggers []Trigger `json:"triggers,omitempty"`
Priority int `json:"priority,omitempty"`
Concurrency int `json:"concurrency,omitempty"`
Contexts []interface{} `json:"contexts,omitempty"`
Steps map[string]interface{} `json:"steps,omitempty"`
Stages []interface{} `json:"stages,omitempty"`
Mode string `json:"mode,omitempty"`
RuntimeEnvironment RuntimeEnvironment `json:"runtimeEnvironment,omitempty"`
}

type Pipeline struct {
Metadata Metadata `json:"metadata,omitempty"`
Spec Spec `json:"spec,omitempty"`
Version string `json:"version,omitempty"`
}

func (p *Pipeline) SetVariables(variables map[string]string) {
for key, value := range variables {
p.Spec.Variables = append(p.Spec.Variables, Variable{Key: key, Value: value})
}
}

func (pipeline *Pipeline) GetID() string {
if pipeline.Metadata.ID != "" {
return pipeline.Metadata.ID
} else {
return pipeline.Metadata.Name
}
}

func (client *Client) GetPipeline(name string) (*Pipeline, error) {
fullPath := fmt.Sprintf("/pipelines/%s", strings.Replace(name, "/", "%2F", 1))
opts := RequestOptions{
Path: fullPath,
Method: "GET",
}

resp, err := client.RequestAPI(&opts)

if err != nil {
return nil, err
}

var pipeline Pipeline

err = DecodeResponseInto(resp, &pipeline)
if err != nil {
return nil, err
}

return &pipeline, nil
}

func (client *Client) CreatePipeline(pipeline *Pipeline) (*Pipeline, error) {

body, err := EncodeToJSON(pipeline)

if err != nil {
return nil, err
}
opts := RequestOptions{
Path: "/pipelines",
Method: "POST",
Body: body,
}

resp, err := client.RequestAPI(&opts)

if err != nil {
return nil, err
}

var respPipeline Pipeline
err = DecodeResponseInto(resp, &respPipeline)
if err != nil {
return nil, err
}

return &respPipeline, nil

}

func (client *Client) UpdatePipeline(pipeline *Pipeline) (*Pipeline, error) {

body, err := EncodeToJSON(pipeline)

if err != nil {
return nil, err
}

id := pipeline.GetID()
if id == "" {
return nil, errors.New("[ERROR] Both Pipeline ID and Name are empty")
}

fullPath := fmt.Sprintf("/pipelines/%s", strings.Replace(id, "/", "%2F", 1))
opts := RequestOptions{
Path: fullPath,
Method: "PUT",
Body: body,
}

resp, err := client.RequestAPI(&opts)
if err != nil {
return nil, err
}

var respPipeline Pipeline
err = DecodeResponseInto(resp, &respPipeline)
if err != nil {
return nil, err
}

return &respPipeline, nil
}

func (client *Client) DeletePipeline(name string) error {

fullPath := fmt.Sprintf("/pipelines/%s", strings.Replace(name, "/", "%2F", 1))
opts := RequestOptions{
Path: fullPath,
Method: "DELETE",
}

_, err := client.RequestAPI(&opts)

if err != nil {
return err
}

return nil
}
Loading

0 comments on commit b924e06

Please sign in to comment.