author Tariq Ibrahim <tariq181290@gmail.com> 1564010566 -0700
committer Art Begolli <artbegolli@gmail.com> 1565554705 +0100

feat(helm-search): json output for helm search

Signed-off-by: Tariq Ibrahim <tariq181290@gmail.com>

Fix broken link in docs/related.md

Looks like this hackernoon link is now broken, probably from when they moved off of Medium.

Signed-off-by: Pete Hodgson <git@thepete.net>

cleanup: error message typos in sql.go

Signed-off-by: ethan <guangming.wang@daocloud.io>

feat(): initial json output functionality

Signed-off-by: Art Begolli <artbegolli@gmail.com>

feat(): adding unit test for json flag

Signed-off-by: Art Begolli <artbegolli@gmail.com>

feat(): updating array to json

Signed-off-by: Art Begolli <artbegolli@gmail.com>

feat(): adding error handling

feat(): fix failing test

chore(): fix linting issues
pull/6096/head
Tariq Ibrahim 6 years ago committed by Art Begolli
parent 7ab62324eb
commit 91a7eca06e

@ -17,6 +17,7 @@ limitations under the License.
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"io" "io"
"strings" "strings"
@ -48,6 +49,18 @@ type searchCmd struct {
regexp bool regexp bool
version string version string
colWidth uint colWidth uint
output string
}
type resultEntry struct {
Name string `json:"name"`
ChartVersion string `json:"chartVersion"`
AppVersion string `json:"appVersion"`
Description string `json:"description"`
}
type results struct {
SearchResults []resultEntry `json:"searchResults"`
} }
func newSearchCmd(out io.Writer) *cobra.Command { func newSearchCmd(out io.Writer) *cobra.Command {
@ -68,6 +81,7 @@ func newSearchCmd(out io.Writer) *cobra.Command {
f.BoolVarP(&sc.versions, "versions", "l", false, "Show the long listing, with each version of each chart on its own line") f.BoolVarP(&sc.versions, "versions", "l", false, "Show the long listing, with each version of each chart on its own line")
f.StringVarP(&sc.version, "version", "v", "", "Search using semantic versioning constraints") f.StringVarP(&sc.version, "version", "v", "", "Search using semantic versioning constraints")
f.UintVar(&sc.colWidth, "col-width", 60, "Specifies the max column width of output") f.UintVar(&sc.colWidth, "col-width", 60, "Specifies the max column width of output")
f.StringVarP(&sc.output, "output", "o", "", "Show the output in specified format")
return cmd return cmd
} }
@ -95,6 +109,16 @@ func (s *searchCmd) run(args []string) error {
return err return err
} }
if s.output == "json" {
formattedResults, err := s.formatSearchResultsJSON(data, s.colWidth)
if err != nil {
return err
}
fmt.Fprintln(s.out, formattedResults)
return nil
}
fmt.Fprintln(s.out, s.formatSearchResults(data, s.colWidth)) fmt.Fprintln(s.out, s.formatSearchResults(data, s.colWidth))
return nil return nil
@ -141,6 +165,30 @@ func (s *searchCmd) formatSearchResults(res []*search.Result, colWidth uint) str
return table.String() return table.String()
} }
func (s *searchCmd) formatSearchResultsJSON(res []*search.Result, colWidth uint) (string, error) {
var resultJSON []resultEntry
if len(res) == 0 {
return "No results found", nil
}
for _, r := range res {
resultRow := resultEntry{
Name: r.Name,
ChartVersion: r.Chart.Version,
AppVersion: r.Chart.AppVersion,
Description: r.Chart.Description,
}
resultJSON = append(resultJSON, resultRow)
}
jsonSearchResults, err := json.MarshalIndent(results{SearchResults: resultJSON}, "", " ")
if err != nil {
return "", err
}
return string(jsonSearchResults), nil
}
func (s *searchCmd) buildIndex() (*search.Index, error) { func (s *searchCmd) buildIndex() (*search.Index, error) {
// Load the repositories.yaml // Load the repositories.yaml
rf, err := repo.LoadRepositoriesFile(s.helmhome.RepositoryFile()) rf, err := repo.LoadRepositoriesFile(s.helmhome.RepositoryFile())

@ -84,6 +84,12 @@ func TestSearchCmd(t *testing.T) {
flags: []string{"--regexp"}, flags: []string{"--regexp"},
err: true, err: true,
}, },
{
name: "search for 'alpine', expect two matches in json",
args: []string{"alpine"},
flags: []string{"--output", "json"},
expected: "{\n \"searchResults\": \\[\n {\n \"name\": \"testing/alpine\",\n \"chartVersion\": \"0.2.0\",\n \"appVersion\": \"2.3.4\",\n \"description\": \"Deploy a basic Alpine Linux pod\"\n }\n \\]\n}",
},
} }
cleanup := resetEnv() cleanup := resetEnv()

@ -14,7 +14,7 @@ or [pull request](https://github.com/helm/helm/pulls).
- [GitLab, Consumer Driven Contracts, Helm and Kubernetes](https://medium.com/@enxebre/gitlab-consumer-driven-contracts-helm-and-kubernetes-b7235a60a1cb#.xwp1y4tgi) - [GitLab, Consumer Driven Contracts, Helm and Kubernetes](https://medium.com/@enxebre/gitlab-consumer-driven-contracts-helm-and-kubernetes-b7235a60a1cb#.xwp1y4tgi)
- [Honestbee's Helm Chart Conventions](https://gist.github.com/so0k/f927a4b60003cedd101a0911757c605a) - [Honestbee's Helm Chart Conventions](https://gist.github.com/so0k/f927a4b60003cedd101a0911757c605a)
- [Releasing backward-incompatible changes: Kubernetes, Jenkins, Prometheus Operator, Helm and Traefik](https://medium.com/@enxebre/releasing-backward-incompatible-changes-kubernetes-jenkins-plugin-prometheus-operator-helm-self-6263ca61a1b1#.e0c7elxhq) - [Releasing backward-incompatible changes: Kubernetes, Jenkins, Prometheus Operator, Helm and Traefik](https://medium.com/@enxebre/releasing-backward-incompatible-changes-kubernetes-jenkins-plugin-prometheus-operator-helm-self-6263ca61a1b1#.e0c7elxhq)
- [The Missing CI/CD Kubernetes Component: Helm package manager](https://hackernoon.com/the-missing-ci-cd-kubernetes-component-helm-package-manager-1fe002aac680#.691sk2zhu) - [The Missing CI/CD Kubernetes Component: Helm package manager](https://medium.com/@gajus/the-missing-ci-cd-kubernetes-component-helm-package-manager-1fe002aac680)
- [Using Helm to Deploy to Kubernetes](https://daemonza.github.io/2017/02/20/using-helm-to-deploy-to-kubernetes/) - [Using Helm to Deploy to Kubernetes](https://daemonza.github.io/2017/02/20/using-helm-to-deploy-to-kubernetes/)
- [Writing a Helm Chart](https://www.influxdata.com/packaged-kubernetes-deployments-writing-helm-chart/) - [Writing a Helm Chart](https://www.influxdata.com/packaged-kubernetes-deployments-writing-helm-chart/)
- [A basic walk through Kubernetes Helm](https://github.com/muffin87/helm-tutorial) - [A basic walk through Kubernetes Helm](https://github.com/muffin87/helm-tutorial)

@ -314,7 +314,14 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
return buf.String(), nil return buf.String(), nil
} }
// Deprecated; use UpdateWithOptions instead // Update reads the current configuration and a target configuration from io.reader
// and creates resources that don't already exist, updates resources that have been modified
// in the target configuration and deletes resources from the current configuration that are
// not present in the target configuration.
//
// Namespace will set the namespaces.
//
// Deprecated: use UpdateWithOptions instead.
func (c *Client) Update(namespace string, originalReader, targetReader io.Reader, force bool, recreate bool, timeout int64, shouldWait bool) error { func (c *Client) Update(namespace string, originalReader, targetReader io.Reader, force bool, recreate bool, timeout int64, shouldWait bool) error {
return c.UpdateWithOptions(namespace, originalReader, targetReader, UpdateOptions{ return c.UpdateWithOptions(namespace, originalReader, targetReader, UpdateOptions{
Force: force, Force: force,
@ -334,12 +341,13 @@ type UpdateOptions struct {
CleanupOnFail bool CleanupOnFail bool
} }
// UpdateWithOptions reads in the current configuration and a target configuration from io.reader // UpdateWithOptions reads the current configuration and a target configuration from io.reader
// and creates resources that don't already exists, updates resources that have been modified // and creates resources that don't already exist, updates resources that have been modified
// in the target configuration and deletes resources from the current configuration that are // in the target configuration and deletes resources from the current configuration that are
// not present in the target configuration. // not present in the target configuration.
// //
// Namespace will set the namespaces. // Namespace will set the namespaces. UpdateOptions provides additional parameters to control
// update behavior.
func (c *Client) UpdateWithOptions(namespace string, originalReader, targetReader io.Reader, opts UpdateOptions) error { func (c *Client) UpdateWithOptions(namespace string, originalReader, targetReader io.Reader, opts UpdateOptions) error {
original, err := c.BuildUnstructured(namespace, originalReader) original, err := c.BuildUnstructured(namespace, originalReader)
if err != nil { if err != nil {
@ -552,7 +560,7 @@ func (c *Client) WatchUntilReady(namespace string, reader io.Reader, timeout int
return perform(infos, c.watchTimeout(time.Duration(timeout)*time.Second)) return perform(infos, c.watchTimeout(time.Duration(timeout)*time.Second))
} }
// WatchUntilCRDEstablished polls the given CRD until it reaches the established // WaitUntilCRDEstablished polls the given CRD until it reaches the established
// state. A CRD needs to reach the established state before CRs can be created. // state. A CRD needs to reach the established state before CRs can be created.
// //
// If a naming conflict condition is found, this function will return an error. // If a naming conflict condition is found, this function will return an error.

@ -558,7 +558,7 @@ func TestWaitUntilCRDEstablished(t *testing.T) {
} else { } else {
crd = crdWithConditions crd = crdWithConditions
} }
requestCount += 1 requestCount++
return newResponse(200, &crd) return newResponse(200, &crd)
}), }),
} }

@ -51,7 +51,7 @@ func Chartfile(linter *support.Linter) {
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNameDirMatch(linter.ChartDir, chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNameDirMatch(linter.ChartDir, chartFile))
// Chart metadata // Chart metadata
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartApiVersion(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartAPIVersion(chartFile))
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartVersion(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartVersion(chartFile))
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartEngine(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartEngine(chartFile))
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartMaintainer(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartMaintainer(chartFile))
@ -97,7 +97,7 @@ func validateChartNameDirMatch(chartDir string, cf *chart.Metadata) error {
return nil return nil
} }
func validateChartApiVersion(cf *chart.Metadata) error { func validateChartAPIVersion(cf *chart.Metadata) error {
if cf.ApiVersion == "" { if cf.ApiVersion == "" {
return errors.New("apiVersion is required") return errors.New("apiVersion is required")
} }

@ -199,7 +199,7 @@ func (s *SQL) Query(labels map[string]string) ([]*rspb.Release, error) {
sqlFilter[dbField] = val sqlFilter[dbField] = val
} else { } else {
s.Log("unknown label %s", key) s.Log("unknown label %s", key)
return nil, fmt.Errorf("unknow label %s", key) return nil, fmt.Errorf("unknown label %s", key)
} }
} }
sort.Strings(sqlFilterKeys) sort.Strings(sqlFilterKeys)

@ -255,6 +255,7 @@ func (p *PrintingKubeClient) WaitAndGetCompletedPodPhase(namespace string, reade
return v1.PodUnknown, err return v1.PodUnknown, err
} }
// WaitUntilCRDEstablished implements KubeClient WaitUntilCRDEstablished.
func (p *PrintingKubeClient) WaitUntilCRDEstablished(reader io.Reader, timeout time.Duration) error { func (p *PrintingKubeClient) WaitUntilCRDEstablished(reader io.Reader, timeout time.Duration) error {
_, err := io.Copy(p.Out, reader) _, err := io.Copy(p.Out, reader)
return err return err

Loading…
Cancel
Save