bunnyshell.com/sdk@v0.16.0/client.go (about) 1 /* 2 API Bunnyshell Environments 3 4 Interact with Bunnyshell Platform 5 6 API version: 1.1.0 7 Contact: osi+support@bunnyshell.com 8 */ 9 10 // Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. 11 12 package sdk 13 14 import ( 15 "bytes" 16 "context" 17 "encoding/json" 18 "encoding/xml" 19 "errors" 20 "fmt" 21 "io" 22 "log" 23 "mime/multipart" 24 "net/http" 25 "net/http/httputil" 26 "net/url" 27 "os" 28 "path/filepath" 29 "reflect" 30 "regexp" 31 "strconv" 32 "strings" 33 "time" 34 "unicode/utf8" 35 36 "gopkg.in/yaml.v3" 37 38 ) 39 40 var ( 41 jsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:(?:hal|problem|vnd\.[^;]+)\+)?json)`) 42 xmlCheck = regexp.MustCompile(`(?i:(?:application|text)/xml)`) 43 yamlCheck = regexp.MustCompile(`(?i:(?:application|text)/x\+yaml)`) 44 queryParamSplit = regexp.MustCompile(`(^|&)([^&]+)`) 45 queryDescape = strings.NewReplacer( "%5B", "[", "%5D", "]" ) 46 ) 47 48 // APIClient manages communication with the API Bunnyshell Environments API v1.1.0 49 // In most cases there should be only one, shared, APIClient. 50 type APIClient struct { 51 cfg *Configuration 52 common service // Reuse a single struct instead of allocating one for each service on the heap. 53 54 // API Services 55 56 ComponentAPI *ComponentAPIService 57 58 ComponentEndpointAPI *ComponentEndpointAPIService 59 60 ComponentGitAPI *ComponentGitAPIService 61 62 EnvironmentAPI *EnvironmentAPIService 63 64 EnvironmentVariableAPI *EnvironmentVariableAPIService 65 66 EventAPI *EventAPIService 67 68 KubernetesIntegrationAPI *KubernetesIntegrationAPIService 69 70 OrganizationAPI *OrganizationAPIService 71 72 PipelineAPI *PipelineAPIService 73 74 ProjectAPI *ProjectAPIService 75 76 ProjectVariableAPI *ProjectVariableAPIService 77 78 RegistryIntegrationAPI *RegistryIntegrationAPIService 79 80 SecretAPI *SecretAPIService 81 82 ServiceComponentVariableAPI *ServiceComponentVariableAPIService 83 84 TemplateAPI *TemplateAPIService 85 86 TemplatesRepositoryAPI *TemplatesRepositoryAPIService 87 88 WorkflowAPI *WorkflowAPIService 89 } 90 91 type service struct { 92 client *APIClient 93 } 94 95 // NewAPIClient creates a new API client. Requires a userAgent string describing your application. 96 // optionally a custom http.Client to allow for advanced features such as caching. 97 func NewAPIClient(cfg *Configuration) *APIClient { 98 if cfg.HTTPClient == nil { 99 cfg.HTTPClient = http.DefaultClient 100 } 101 102 c := &APIClient{} 103 c.cfg = cfg 104 c.common.client = c 105 106 // API Services 107 c.ComponentAPI = (*ComponentAPIService)(&c.common) 108 c.ComponentEndpointAPI = (*ComponentEndpointAPIService)(&c.common) 109 c.ComponentGitAPI = (*ComponentGitAPIService)(&c.common) 110 c.EnvironmentAPI = (*EnvironmentAPIService)(&c.common) 111 c.EnvironmentVariableAPI = (*EnvironmentVariableAPIService)(&c.common) 112 c.EventAPI = (*EventAPIService)(&c.common) 113 c.KubernetesIntegrationAPI = (*KubernetesIntegrationAPIService)(&c.common) 114 c.OrganizationAPI = (*OrganizationAPIService)(&c.common) 115 c.PipelineAPI = (*PipelineAPIService)(&c.common) 116 c.ProjectAPI = (*ProjectAPIService)(&c.common) 117 c.ProjectVariableAPI = (*ProjectVariableAPIService)(&c.common) 118 c.RegistryIntegrationAPI = (*RegistryIntegrationAPIService)(&c.common) 119 c.SecretAPI = (*SecretAPIService)(&c.common) 120 c.ServiceComponentVariableAPI = (*ServiceComponentVariableAPIService)(&c.common) 121 c.TemplateAPI = (*TemplateAPIService)(&c.common) 122 c.TemplatesRepositoryAPI = (*TemplatesRepositoryAPIService)(&c.common) 123 c.WorkflowAPI = (*WorkflowAPIService)(&c.common) 124 125 return c 126 } 127 128 func atoi(in string) (int, error) { 129 return strconv.Atoi(in) 130 } 131 132 // selectHeaderContentType select a content type from the available list. 133 func selectHeaderContentType(contentTypes []string) string { 134 if len(contentTypes) == 0 { 135 return "" 136 } 137 if contains(contentTypes, "application/json") { 138 return "application/json" 139 } 140 return contentTypes[0] // use the first content type specified in 'consumes' 141 } 142 143 // selectHeaderAccept join all accept types and return 144 func selectHeaderAccept(accepts []string) string { 145 if len(accepts) == 0 { 146 return "" 147 } 148 149 if contains(accepts, "application/json") { 150 return "application/json" 151 } 152 153 return strings.Join(accepts, ",") 154 } 155 156 // contains is a case insensitive match, finding needle in a haystack 157 func contains(haystack []string, needle string) bool { 158 for _, a := range haystack { 159 if strings.EqualFold(a, needle) { 160 return true 161 } 162 } 163 return false 164 } 165 166 // Verify optional parameters are of the correct type. 167 func typeCheckParameter(obj interface{}, expected string, name string) error { 168 // Make sure there is an object. 169 if obj == nil { 170 return nil 171 } 172 173 // Check the type is as expected. 174 if reflect.TypeOf(obj).String() != expected { 175 return fmt.Errorf("expected %s to be of type %s but received %s", name, expected, reflect.TypeOf(obj).String()) 176 } 177 return nil 178 } 179 180 func parameterValueToString( obj interface{}, key string ) string { 181 if reflect.TypeOf(obj).Kind() != reflect.Ptr { 182 return fmt.Sprintf("%v", obj) 183 } 184 var param,ok = obj.(MappedNullable) 185 if !ok { 186 return "" 187 } 188 dataMap,err := param.ToMap() 189 if err != nil { 190 return "" 191 } 192 return fmt.Sprintf("%v", dataMap[key]) 193 } 194 195 // parameterAddToHeaderOrQuery adds the provided object to the request header or url query 196 // supporting deep object syntax 197 func parameterAddToHeaderOrQuery(headerOrQueryParams interface{}, keyPrefix string, obj interface{}, collectionType string) { 198 var v = reflect.ValueOf(obj) 199 var value = "" 200 if v == reflect.ValueOf(nil) { 201 value = "null" 202 } else { 203 switch v.Kind() { 204 case reflect.Invalid: 205 value = "invalid" 206 207 case reflect.Struct: 208 if t,ok := obj.(MappedNullable); ok { 209 dataMap,err := t.ToMap() 210 if err != nil { 211 return 212 } 213 parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, dataMap, collectionType) 214 return 215 } 216 if t, ok := obj.(time.Time); ok { 217 parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, t.Format(time.RFC3339), collectionType) 218 return 219 } 220 value = v.Type().String() + " value" 221 case reflect.Slice: 222 var indValue = reflect.ValueOf(obj) 223 if indValue == reflect.ValueOf(nil) { 224 return 225 } 226 var lenIndValue = indValue.Len() 227 for i:=0;i<lenIndValue;i++ { 228 var arrayValue = indValue.Index(i) 229 parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, arrayValue.Interface(), collectionType) 230 } 231 return 232 233 case reflect.Map: 234 var indValue = reflect.ValueOf(obj) 235 if indValue == reflect.ValueOf(nil) { 236 return 237 } 238 iter := indValue.MapRange() 239 for iter.Next() { 240 k,v := iter.Key(), iter.Value() 241 parameterAddToHeaderOrQuery(headerOrQueryParams, fmt.Sprintf("%s[%s]", keyPrefix, k.String()), v.Interface(), collectionType) 242 } 243 return 244 245 case reflect.Interface: 246 fallthrough 247 case reflect.Ptr: 248 parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, v.Elem().Interface(), collectionType) 249 return 250 251 case reflect.Int, reflect.Int8, reflect.Int16, 252 reflect.Int32, reflect.Int64: 253 value = strconv.FormatInt(v.Int(), 10) 254 case reflect.Uint, reflect.Uint8, reflect.Uint16, 255 reflect.Uint32, reflect.Uint64, reflect.Uintptr: 256 value = strconv.FormatUint(v.Uint(), 10) 257 case reflect.Float32, reflect.Float64: 258 value = strconv.FormatFloat(v.Float(), 'g', -1, 32) 259 case reflect.Bool: 260 value = strconv.FormatBool(v.Bool()) 261 case reflect.String: 262 value = v.String() 263 default: 264 value = v.Type().String() + " value" 265 } 266 } 267 268 switch valuesMap := headerOrQueryParams.(type) { 269 case url.Values: 270 if collectionType == "csv" && valuesMap.Get(keyPrefix) != "" { 271 valuesMap.Set(keyPrefix, valuesMap.Get(keyPrefix) + "," + value) 272 } else { 273 valuesMap.Add(keyPrefix, value) 274 } 275 break 276 case map[string]string: 277 valuesMap[keyPrefix] = value 278 break 279 } 280 } 281 282 // helper for converting interface{} parameters to json strings 283 func parameterToJson(obj interface{}) (string, error) { 284 jsonBuf, err := json.Marshal(obj) 285 if err != nil { 286 return "", err 287 } 288 return string(jsonBuf), err 289 } 290 291 // callAPI do the request. 292 func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { 293 if c.cfg.Debug { 294 dump, err := httputil.DumpRequestOut(request, true) 295 if err != nil { 296 return nil, err 297 } 298 log.Printf("\n%s\n", string(dump)) 299 } 300 301 resp, err := c.cfg.HTTPClient.Do(request) 302 if err != nil { 303 return resp, err 304 } 305 306 if c.cfg.Debug { 307 dump, err := httputil.DumpResponse(resp, true) 308 if err != nil { 309 return resp, err 310 } 311 log.Printf("\n%s\n", string(dump)) 312 } 313 return resp, err 314 } 315 316 // Allow modification of underlying config for alternate implementations and testing 317 // Caution: modifying the configuration while live can cause data races and potentially unwanted behavior 318 func (c *APIClient) GetConfig() *Configuration { 319 return c.cfg 320 } 321 322 type formFile struct { 323 fileBytes []byte 324 fileName string 325 formFileName string 326 } 327 328 // prepareRequest build the request 329 func (c *APIClient) prepareRequest( 330 ctx context.Context, 331 path string, method string, 332 postBody interface{}, 333 headerParams map[string]string, 334 queryParams url.Values, 335 formParams url.Values, 336 formFiles []formFile) (localVarRequest *http.Request, err error) { 337 338 var body *bytes.Buffer 339 340 // Detect postBody type and post. 341 if postBody != nil { 342 contentType := headerParams["Content-Type"] 343 if contentType == "" { 344 contentType = detectContentType(postBody) 345 headerParams["Content-Type"] = contentType 346 } 347 348 body, err = setBody(postBody, contentType) 349 if err != nil { 350 return nil, err 351 } 352 } 353 354 // add form parameters and file if available. 355 if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(formFiles) > 0) { 356 if body != nil { 357 return nil, errors.New("Cannot specify postBody and multipart form at the same time.") 358 } 359 body = &bytes.Buffer{} 360 w := multipart.NewWriter(body) 361 362 for k, v := range formParams { 363 for _, iv := range v { 364 if strings.HasPrefix(k, "@") { // file 365 err = addFile(w, k[1:], iv) 366 if err != nil { 367 return nil, err 368 } 369 } else { // form value 370 w.WriteField(k, iv) 371 } 372 } 373 } 374 for _, formFile := range formFiles { 375 if len(formFile.fileBytes) > 0 && formFile.fileName != "" { 376 w.Boundary() 377 part, err := w.CreateFormFile(formFile.formFileName, filepath.Base(formFile.fileName)) 378 if err != nil { 379 return nil, err 380 } 381 _, err = part.Write(formFile.fileBytes) 382 if err != nil { 383 return nil, err 384 } 385 } 386 } 387 388 // Set the Boundary in the Content-Type 389 headerParams["Content-Type"] = w.FormDataContentType() 390 391 // Set Content-Length 392 headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) 393 w.Close() 394 } 395 396 if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 { 397 if body != nil { 398 return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.") 399 } 400 body = &bytes.Buffer{} 401 body.WriteString(formParams.Encode()) 402 // Set Content-Length 403 headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) 404 } 405 406 // Setup path and query parameters 407 url, err := url.Parse(path) 408 if err != nil { 409 return nil, err 410 } 411 412 // Override request host, if applicable 413 if c.cfg.Host != "" { 414 url.Host = c.cfg.Host 415 } 416 417 // Override request scheme, if applicable 418 if c.cfg.Scheme != "" { 419 url.Scheme = c.cfg.Scheme 420 } 421 422 // Adding Query Param 423 query := url.Query() 424 for k, v := range queryParams { 425 for _, iv := range v { 426 query.Add(k, iv) 427 } 428 } 429 430 // Encode the parameters. 431 url.RawQuery = queryParamSplit.ReplaceAllStringFunc(query.Encode(), func(s string) string { 432 pieces := strings.Split(s, "=") 433 pieces[0] = queryDescape.Replace(pieces[0]) 434 return strings.Join(pieces, "=") 435 }) 436 437 // Generate a new request 438 if body != nil { 439 localVarRequest, err = http.NewRequest(method, url.String(), body) 440 } else { 441 localVarRequest, err = http.NewRequest(method, url.String(), nil) 442 } 443 if err != nil { 444 return nil, err 445 } 446 447 // add header parameters, if any 448 if len(headerParams) > 0 { 449 headers := http.Header{} 450 for h, v := range headerParams { 451 headers[h] = []string{v} 452 } 453 localVarRequest.Header = headers 454 } 455 456 // Add the user agent to the request. 457 localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) 458 459 if ctx != nil { 460 // add context to the request 461 localVarRequest = localVarRequest.WithContext(ctx) 462 463 // Walk through any authentication. 464 465 } 466 467 for header, value := range c.cfg.DefaultHeader { 468 localVarRequest.Header.Add(header, value) 469 } 470 return localVarRequest, nil 471 } 472 473 func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { 474 if len(b) == 0 { 475 return nil 476 } 477 if s, ok := v.(*string); ok { 478 *s = string(b) 479 return nil 480 } 481 if f, ok := v.(*os.File); ok { 482 f, err = os.CreateTemp("", "HttpClientFile") 483 if err != nil { 484 return 485 } 486 _, err = f.Write(b) 487 if err != nil { 488 return 489 } 490 _, err = f.Seek(0, io.SeekStart) 491 err = os.Remove(f.Name()) 492 return 493 } 494 if f, ok := v.(**os.File); ok { 495 *f, err = os.CreateTemp("", "HttpClientFile") 496 if err != nil { 497 return 498 } 499 _, err = (*f).Write(b) 500 if err != nil { 501 return 502 } 503 _, err = (*f).Seek(0, io.SeekStart) 504 err = os.Remove((*f).Name()) 505 return 506 } 507 if xmlCheck.MatchString(contentType) { 508 if err = xml.Unmarshal(b, v); err != nil { 509 return err 510 } 511 return nil 512 } 513 if jsonCheck.MatchString(contentType) { 514 if actualObj, ok := v.(interface{ GetActualInstance() interface{} }); ok { // oneOf, anyOf schemas 515 if unmarshalObj, ok := actualObj.(interface{ UnmarshalJSON([]byte) error }); ok { // make sure it has UnmarshalJSON defined 516 if err = unmarshalObj.UnmarshalJSON(b); err != nil { 517 return err 518 } 519 } else { 520 return errors.New("Unknown type with GetActualInstance but no unmarshalObj.UnmarshalJSON defined") 521 } 522 } else if err = json.Unmarshal(b, v); err != nil { // simple model 523 return err 524 } 525 return nil 526 } 527 if yamlCheck.MatchString(contentType) { 528 if actualObj, ok := v.(interface{ GetActualInstance() interface{} }); ok { // oneOf, anyOf schemas 529 if unmarshalObj, ok := actualObj.(interface{ UnmarshalYAML([]byte) error }); ok { // make sure it has UnmarshalYAML defined 530 if err = unmarshalObj.UnmarshalYAML(b); err != nil { 531 return err 532 } 533 } else { 534 return errors.New("unknown type with GetActualInstance but no unmarshalObj.UnmarshalYAML defined") 535 } 536 } else if err = yaml.Unmarshal(b, v); err != nil { // simple model 537 return err 538 } 539 540 return nil 541 } 542 return errors.New("undefined response type") 543 } 544 545 // Add a file to the multipart request 546 func addFile(w *multipart.Writer, fieldName, path string) error { 547 file, err := os.Open(filepath.Clean(path)) 548 if err != nil { 549 return err 550 } 551 err = file.Close() 552 if err != nil { 553 return err 554 } 555 556 part, err := w.CreateFormFile(fieldName, filepath.Base(path)) 557 if err != nil { 558 return err 559 } 560 _, err = io.Copy(part, file) 561 562 return err 563 } 564 565 // Prevent trying to import "fmt" 566 func reportError(format string, a ...interface{}) error { 567 return fmt.Errorf(format, a...) 568 } 569 570 // A wrapper for strict JSON decoding 571 func newStrictDecoder(data []byte) *json.Decoder { 572 dec := json.NewDecoder(bytes.NewBuffer(data)) 573 dec.DisallowUnknownFields() 574 return dec 575 } 576 577 // Set request body from an interface{} 578 func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { 579 if bodyBuf == nil { 580 bodyBuf = &bytes.Buffer{} 581 } 582 583 if reader, ok := body.(io.Reader); ok { 584 _, err = bodyBuf.ReadFrom(reader) 585 } else if fp, ok := body.(*os.File); ok { 586 _, err = bodyBuf.ReadFrom(fp) 587 } else if b, ok := body.([]byte); ok { 588 _, err = bodyBuf.Write(b) 589 } else if s, ok := body.(string); ok { 590 _, err = bodyBuf.WriteString(s) 591 } else if s, ok := body.(*string); ok { 592 _, err = bodyBuf.WriteString(*s) 593 } else if jsonCheck.MatchString(contentType) { 594 err = json.NewEncoder(bodyBuf).Encode(body) 595 } else if xmlCheck.MatchString(contentType) { 596 var bs []byte 597 bs, err = xml.Marshal(body) 598 if err == nil { 599 bodyBuf.Write(bs) 600 } 601 } else if yamlCheck.MatchString(contentType) { 602 var bs []byte 603 bs, err = yaml.Marshal(body) 604 if err == nil { 605 bodyBuf.Write(bs) 606 } 607 } 608 609 if err != nil { 610 return nil, err 611 } 612 613 if bodyBuf.Len() == 0 { 614 err = fmt.Errorf("invalid body type %s\n", contentType) 615 return nil, err 616 } 617 return bodyBuf, nil 618 } 619 620 // detectContentType method is used to figure out `Request.Body` content type for request header 621 func detectContentType(body interface{}) string { 622 contentType := "text/plain; charset=utf-8" 623 kind := reflect.TypeOf(body).Kind() 624 625 switch kind { 626 case reflect.Struct, reflect.Map, reflect.Ptr: 627 contentType = "application/json; charset=utf-8" 628 case reflect.String: 629 contentType = "text/plain; charset=utf-8" 630 default: 631 if b, ok := body.([]byte); ok { 632 contentType = http.DetectContentType(b) 633 } else if kind == reflect.Slice { 634 contentType = "application/json; charset=utf-8" 635 } 636 } 637 638 return contentType 639 } 640 641 // Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go 642 type cacheControl map[string]string 643 644 func parseCacheControl(headers http.Header) cacheControl { 645 cc := cacheControl{} 646 ccHeader := headers.Get("Cache-Control") 647 for _, part := range strings.Split(ccHeader, ",") { 648 part = strings.Trim(part, " ") 649 if part == "" { 650 continue 651 } 652 if strings.ContainsRune(part, '=') { 653 keyval := strings.Split(part, "=") 654 cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") 655 } else { 656 cc[part] = "" 657 } 658 } 659 return cc 660 } 661 662 // CacheExpires helper function to determine remaining time before repeating a request. 663 func CacheExpires(r *http.Response) time.Time { 664 // Figure out when the cache expires. 665 var expires time.Time 666 now, err := time.Parse(time.RFC1123, r.Header.Get("date")) 667 if err != nil { 668 return time.Now() 669 } 670 respCacheControl := parseCacheControl(r.Header) 671 672 if maxAge, ok := respCacheControl["max-age"]; ok { 673 lifetime, err := time.ParseDuration(maxAge + "s") 674 if err != nil { 675 expires = now 676 } else { 677 expires = now.Add(lifetime) 678 } 679 } else { 680 expiresHeader := r.Header.Get("Expires") 681 if expiresHeader != "" { 682 expires, err = time.Parse(time.RFC1123, expiresHeader) 683 if err != nil { 684 expires = now 685 } 686 } 687 } 688 return expires 689 } 690 691 func strlen(s string) int { 692 return utf8.RuneCountInString(s) 693 } 694 695 // GenericOpenAPIError Provides access to the body, error and model on returned errors. 696 type GenericOpenAPIError struct { 697 body []byte 698 error string 699 model interface{} 700 } 701 702 // Error returns non-empty string if there was an error. 703 func (e GenericOpenAPIError) Error() string { 704 return e.error 705 } 706 707 // Body returns the raw bytes of the response 708 func (e GenericOpenAPIError) Body() []byte { 709 return e.body 710 } 711 712 // Model returns the unpacked model of the error 713 func (e GenericOpenAPIError) Model() interface{} { 714 return e.model 715 } 716 717 // format error message using title and detail when model implements rfc7807 718 func formatErrorMessage(status string, v interface{}) string { 719 str := "" 720 metaValue := reflect.ValueOf(v).Elem() 721 722 if metaValue.Kind() == reflect.Struct { 723 field := metaValue.FieldByName("Title") 724 if field != (reflect.Value{}) { 725 str = fmt.Sprintf("%s", field.Interface()) 726 } 727 728 field = metaValue.FieldByName("Detail") 729 if field != (reflect.Value{}) { 730 str = fmt.Sprintf("%s (%s)", str, field.Interface()) 731 } 732 } 733 734 return strings.TrimSpace(fmt.Sprintf("%s %s", status, str)) 735 }