/* Copyright The Helm Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package monocular import ( "encoding/json" "fmt" "net/http" "net/url" "path" "time" "helm.sh/helm/v3/internal/version" "helm.sh/helm/v3/pkg/chart" ) // SearchPath is the url path to the search API in monocular. const SearchPath = "api/chartsvc/v1/charts/search" // The structs below represent the structure of the response from the monocular // search API. The structs were not imported from monocular because monocular // imports from Helm v2 (avoiding circular version dependency) and the mappings // are slightly different (monocular search results do not directly reflect // the struct definitions). // SearchResult represents an individual chart result type SearchResult struct { ID string `json:"id"` ArtifactHub ArtifactHub `json:"artifactHub"` Type string `json:"type"` Attributes Chart `json:"attributes"` Links Links `json:"links"` Relationships Relationships `json:"relationships"` } // ArtifactHub represents data specific to Artifact Hub instances type ArtifactHub struct { PackageURL string `json:"packageUrl"` } // Chart is the attributes for the chart type Chart struct { Name string `json:"name"` Repo Repo `json:"repo"` Description string `json:"description"` Home string `json:"home"` Keywords []string `json:"keywords"` Maintainers []chart.Maintainer `json:"maintainers"` Sources []string `json:"sources"` Icon string `json:"icon"` } // Repo contains the name in monocular the url for the repository type Repo struct { Name string `json:"name"` URL string `json:"url"` } // Links provides a set of links relative to the chartsvc base type Links struct { Self string `json:"self"` } // Relationships provides information on the latest version of the chart type Relationships struct { LatestChartVersion LatestChartVersion `json:"latestChartVersion"` } // LatestChartVersion provides the details on the latest version of the chart type LatestChartVersion struct { Data ChartVersion `json:"data"` Links Links `json:"links"` } // ChartVersion provides the specific data on the chart version type ChartVersion struct { Version string `json:"version"` AppVersion string `json:"app_version"` Created time.Time `json:"created"` Digest string `json:"digest"` Urls []string `json:"urls"` Readme string `json:"readme"` Values string `json:"values"` } // Search performs a search against the monocular search API func (c *Client) Search(term string) ([]SearchResult, error) { // Create the URL to the search endpoint // Note, this is currently an internal API for the Hub. This should be // formatted without showing how monocular operates. p, err := url.Parse(c.BaseURL) if err != nil { return nil, err } // Set the path to the monocular API endpoint for search p.Path = path.Join(p.Path, SearchPath) p.RawQuery = "q=" + url.QueryEscape(term) // Create request req, err := http.NewRequest(http.MethodGet, p.String(), nil) if err != nil { return nil, err } // Set the user agent so that monocular can identify where the request // is coming from req.Header.Set("User-Agent", version.GetUserAgent()) res, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer res.Body.Close() if res.StatusCode != 200 { return nil, fmt.Errorf("failed to fetch %s : %s", p.String(), res.Status) } result := &searchResponse{} json.NewDecoder(res.Body).Decode(result) return result.Data, nil } type searchResponse struct { Data []SearchResult `json:"data"` }