cmd/hub/api/component.go (325 lines of code) (raw):

// Copyright (c) 2022 EPAM Systems, Inc. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. //go:build api package api import ( "encoding/json" "fmt" "io" "log" "net/url" "os" "strings" "github.com/epam/hubctl/cmd/hub/config" "github.com/epam/hubctl/cmd/hub/util" ) const componentsResource = "hub/api/v1/components" func Components(selector string, onlyCustomComponents, jsonFormat bool) { components, err := componentsBy(selector, onlyCustomComponents) if err != nil { log.Fatalf("Unable to query for Component(s): %v", err) } if len(components) == 0 { if jsonFormat { log.Print("No Components") } else { fmt.Print("No Components\n") } } else { if jsonFormat { var toMarshal interface{} if len(components) == 1 { toMarshal = &components[0] } else { toMarshal = components } out, err := json.MarshalIndent(toMarshal, "", " ") if err != nil { log.Fatalf("Error marshalling JSON response for output: %v", err) } os.Stdout.Write(out) os.Stdout.Write([]byte("\n")) } else { errors := make([]error, 0) for _, component := range components { errors = formatComponentEntity(&component, errors) } if len(errors) > 0 { fmt.Print("Errors encountered:\n") for _, err := range errors { fmt.Printf("\t%v\n", err) } } } } } func formatComponentEntity(component *Component, errors []error) []error { fmt.Printf("\n\t%s\n", formatComponentTitle(component)) if component.Description != "" { fmt.Printf("\t\tDescription: %s\n", strings.Trim(component.Description, "\r\n ")) } if len(component.Tags) > 0 { fmt.Printf("\t\tTags: %s\n", strings.Join(component.Tags, ", ")) } if component.Category != "" { fmt.Printf("\t\tCategory: %s\n", component.Category) } if component.License != "" { fmt.Printf("\t\tLicense: %s\n", component.License) } if component.Icon != "" { fmt.Printf("\t\tIcon: %s\n", util.Wrap(component.Icon)) } if component.Template != nil { fmt.Printf("\t\tTemplate: %s\n", formatTemplateRef(component.Template)) } if component.Git != nil { fmt.Printf("\t\tGit: %s\n", formatComponentGitRef(component.Git)) } if component.Version != "" { fmt.Printf("\t\tVersion: %s\n", component.Version) } if component.Maturity != "" { fmt.Printf("\t\tMaturity: %s\n", component.Maturity) } if len(component.Requires) > 0 { fmt.Printf("\t\tRequires: %s\n", strings.Join(component.Requires, ", ")) } if len(component.Provides) > 0 { fmt.Printf("\t\tProvides: %s\n", strings.Join(component.Provides, ", ")) } if len(component.TeamsPermissions) > 0 { formatted := formatTeams(component.TeamsPermissions) fmt.Printf("\t\tTeams: %s\n", formatted) } return errors } func formatComponentTitle(component *Component) string { brief := "" if component.Brief != "" { brief = " - " + component.Brief } id := "" if component.Id != "" { brief = fmt.Sprintf(" [%s]", component.Id) } return fmt.Sprintf("%s%s%s", component.QName, id, brief) } func formatComponentGitRef(ref *ComponentGitRef) string { subDir := "" if ref.SubDir != "" { subDir = "/" + ref.SubDir } return fmt.Sprintf("%s%s", ref.Remote, subDir) } func formatComponent(component *Component) { errors := formatComponentEntity(component, make([]error, 0)) if len(errors) > 0 { fmt.Print("Errors encountered formatting response:\n") for _, err := range errors { fmt.Printf("\t%v\n", err) } } } func componentBy(selector string) (*Component, error) { if !util.IsUint(selector) { return componentByName(selector) } return componentById(selector) } func componentsBy(selector string, onlyCustomComponents bool) ([]Component, error) { if !util.IsUint(selector) { return componentsByName(selector, onlyCustomComponents) } component, err := componentById(selector) if err != nil { return nil, err } if component != nil { return []Component{*component}, nil } return nil, nil } func componentById(id string) (*Component, error) { path := fmt.Sprintf("%s/%s", componentsResource, url.PathEscape(id)) var jsResp Component code, err := get(hubApi(), path, &jsResp) if code == 404 { return nil, nil } if err != nil { return nil, fmt.Errorf("Error querying HubCTL Components: %v", err) } if code != 200 { return nil, fmt.Errorf("Got %d HTTP querying HubCTL Components, expected 200 HTTP", code) } return &jsResp, nil } func componentByName(name string) (*Component, error) { components, err := componentsByName(name, false) if err != nil { return nil, fmt.Errorf("Unable to query for Component `%s`: %v", name, err) } if len(components) == 0 { return nil, fmt.Errorf("No Component `%s` found", name) } if len(components) > 1 { return nil, fmt.Errorf("More than one Component returned by name `%s`", name) } component := components[0] return &component, nil } func componentsByName(name string, onlyCustomComponents bool) ([]Component, error) { path := componentsResource var filters []string if name != "" { filters = append(filters, "qname="+url.QueryEscape(name)) } if onlyCustomComponents { filters = append(filters, "kind=custom") } if len(filters) > 0 { path += "?" + strings.Join(filters, "&") } var jsResp []Component code, err := get(hubApi(), path, &jsResp) if code == 404 { return nil, nil } if err != nil { return nil, fmt.Errorf("Error querying HubCTL Components: %v", err) } if code != 200 { return nil, fmt.Errorf("Got %d HTTP querying HubCTL Components, expected 200 HTTP", code) } return jsResp, nil } func CreateComponent(req ComponentRequest) { component, err := createComponent(req) if err != nil { log.Fatalf("Unable to create HubCTL Component: %v", err) } formatComponent(component) } func createComponent(req ComponentRequest) (*Component, error) { if req.Template != "" && !util.IsUint(req.Template) { template, err := templateByName(req.Template) if err != nil { return nil, err } req.Template = template.Id } var jsResp Component code, err := post(hubApi(), componentsResource, &req, &jsResp) if err != nil { return nil, err } if code != 200 && code != 201 { return nil, fmt.Errorf("Got %d HTTP creating HubCTL Component, expected [200, 201] HTTP", code) } return &jsResp, nil } func RawCreateComponent(body io.Reader) { component, err := rawCreateComponent(body) if err != nil { log.Fatalf("Unable to create HubCTL Component: %v", err) } formatComponent(component) } func rawCreateComponent(body io.Reader) (*Component, error) { var jsResp Component code, err := post2(hubApi(), componentsResource, body, &jsResp) if err != nil { return nil, err } if code != 200 && code != 201 { return nil, fmt.Errorf("Got %d HTTP creating HubCTL Component, expected [200, 201] HTTP", code) } return &jsResp, nil } func DeleteComponent(selector string) { err := deleteComponent(selector) if err != nil { log.Fatalf("Unable to delete HubCTL Component: %v", err) } } func deleteComponent(selector string) error { component, err := componentBy(selector) id := "" if err != nil { str := err.Error() if util.IsUint(selector) && (strings.Contains(str, "json: cannot unmarshal") || strings.Contains(str, "cannot parse") || config.Force) { util.Warn("%v", err) id = selector } else { return err } } else if component == nil { return error404 } else { id = component.Id } force := "" if config.Force { force = "?force=true" } path := fmt.Sprintf("%s/%s%s", componentsResource, url.PathEscape(id), force) code, err := delete(hubApi(), path) if err != nil { return err } if code != 202 && code != 204 { return fmt.Errorf("Got %d HTTP deleting HubCTL Component, expected [202, 204] HTTP", code) } return nil } func PatchComponent(selector string, change ComponentPatch) { component, err := patchComponent(selector, change) if err != nil { log.Fatalf("Unable to patch HubCTL Component: %v", err) } formatComponent(component) } func patchComponent(selector string, change ComponentPatch) (*Component, error) { component, err := componentBy(selector) if err != nil { return nil, err } if component == nil { return nil, error404 } path := fmt.Sprintf("%s/%s", componentsResource, url.PathEscape(component.Id)) var jsResp Component code, err := patch(hubApi(), path, &change, &jsResp) if err != nil { return nil, err } if code != 200 { return nil, fmt.Errorf("Got %d HTTP patching HubCTL Component, expected 200 HTTP", code) } return &jsResp, nil } func RawPatchComponent(selector string, body io.Reader) { component, err := rawPatchComponent(selector, body) if err != nil { log.Fatalf("Unable to patch HubCTL Component: %v", err) } formatComponent(component) } func rawPatchComponent(selector string, body io.Reader) (*Component, error) { component, err := componentBy(selector) if err != nil { return nil, err } if component == nil { return nil, error404 } path := fmt.Sprintf("%s/%s", componentsResource, url.PathEscape(component.Id)) var jsResp Component code, err := patch2(hubApi(), path, body, &jsResp) if err != nil { return nil, err } if code != 200 { return nil, fmt.Errorf("Got %d HTTP patching HubCTL Component, expected 200 HTTP", code) } return &jsResp, nil }