github.com/umeshredd/helm@v3.0.0-alpha.1+incompatible/pkg/action/history.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package action
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  
    23  	"github.com/ghodss/yaml"
    24  	"github.com/gosuri/uitable"
    25  	"github.com/pkg/errors"
    26  
    27  	"helm.sh/helm/pkg/chart"
    28  	"helm.sh/helm/pkg/release"
    29  	"helm.sh/helm/pkg/releaseutil"
    30  )
    31  
    32  type releaseInfo struct {
    33  	Revision    int    `json:"revision"`
    34  	Updated     string `json:"updated"`
    35  	Status      string `json:"status"`
    36  	Chart       string `json:"chart"`
    37  	AppVersion  string `json:"app_version"`
    38  	Description string `json:"description"`
    39  }
    40  
    41  type releaseHistory []releaseInfo
    42  
    43  type OutputFormat string
    44  
    45  const (
    46  	Table OutputFormat = "table"
    47  	JSON  OutputFormat = "json"
    48  	YAML  OutputFormat = "yaml"
    49  )
    50  
    51  var ErrInvalidFormatType = errors.New("invalid format type")
    52  
    53  func (o OutputFormat) String() string {
    54  	return string(o)
    55  }
    56  
    57  func ParseOutputFormat(s string) (out OutputFormat, err error) {
    58  	switch s {
    59  	case Table.String():
    60  		out, err = Table, nil
    61  	case JSON.String():
    62  		out, err = JSON, nil
    63  	case YAML.String():
    64  		out, err = YAML, nil
    65  	default:
    66  		out, err = "", ErrInvalidFormatType
    67  	}
    68  	return
    69  }
    70  
    71  func (o OutputFormat) MarshalHistory(hist releaseHistory) (byt []byte, err error) {
    72  	switch o {
    73  	case YAML:
    74  		byt, err = yaml.Marshal(hist)
    75  	case JSON:
    76  		byt, err = json.Marshal(hist)
    77  	case Table:
    78  		byt = formatAsTable(hist)
    79  	default:
    80  		err = ErrInvalidFormatType
    81  	}
    82  	return
    83  }
    84  
    85  // History is the action for checking the release's ledger.
    86  //
    87  // It provides the implementation of 'helm history'.
    88  type History struct {
    89  	cfg *Configuration
    90  
    91  	Max          int
    92  	OutputFormat string
    93  }
    94  
    95  // NewHistory creates a new History object with the given configuration.
    96  func NewHistory(cfg *Configuration) *History {
    97  	return &History{
    98  		cfg: cfg,
    99  	}
   100  }
   101  
   102  // Run executes 'helm history' against the given release.
   103  func (h *History) Run(name string) (string, error) {
   104  	if err := validateReleaseName(name); err != nil {
   105  		return "", errors.Errorf("getHistory: Release name is invalid: %s", name)
   106  	}
   107  
   108  	h.cfg.Log("getting history for release %s", name)
   109  	hist, err := h.cfg.Releases.History(name)
   110  	if err != nil {
   111  		return "", err
   112  	}
   113  
   114  	releaseutil.Reverse(hist, releaseutil.SortByRevision)
   115  
   116  	var rels []*release.Release
   117  	for i := 0; i < min(len(hist), h.Max); i++ {
   118  		rels = append(rels, hist[i])
   119  	}
   120  
   121  	if len(rels) == 0 {
   122  		return "", nil
   123  	}
   124  
   125  	releaseHistory := getReleaseHistory(rels)
   126  
   127  	outputFormat, err := ParseOutputFormat(h.OutputFormat)
   128  	if err != nil {
   129  		return "", err
   130  	}
   131  	history, formattingError := outputFormat.MarshalHistory(releaseHistory)
   132  	if formattingError != nil {
   133  		return "", formattingError
   134  	}
   135  
   136  	return string(history), nil
   137  }
   138  
   139  func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
   140  	for i := len(rls) - 1; i >= 0; i-- {
   141  		r := rls[i]
   142  		c := formatChartname(r.Chart)
   143  		s := r.Info.Status.String()
   144  		v := r.Version
   145  		d := r.Info.Description
   146  		a := formatAppVersion(r.Chart)
   147  
   148  		rInfo := releaseInfo{
   149  			Revision:    v,
   150  			Status:      s,
   151  			Chart:       c,
   152  			AppVersion:  a,
   153  			Description: d,
   154  		}
   155  		if !r.Info.LastDeployed.IsZero() {
   156  			rInfo.Updated = r.Info.LastDeployed.String()
   157  
   158  		}
   159  		history = append(history, rInfo)
   160  	}
   161  
   162  	return history
   163  }
   164  
   165  func formatAsTable(releases releaseHistory) []byte {
   166  	tbl := uitable.New()
   167  
   168  	tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "DESCRIPTION")
   169  	for i := 0; i <= len(releases)-1; i++ {
   170  		r := releases[i]
   171  		tbl.AddRow(r.Revision, r.Updated, r.Status, r.Chart, r.AppVersion, r.Description)
   172  	}
   173  	return tbl.Bytes()
   174  }
   175  
   176  func formatChartname(c *chart.Chart) string {
   177  	if c == nil || c.Metadata == nil {
   178  		// This is an edge case that has happened in prod, though we don't
   179  		// know how: https://github.com/helm/helm/issues/1347
   180  		return "MISSING"
   181  	}
   182  	return fmt.Sprintf("%s-%s", c.Name(), c.Metadata.Version)
   183  }
   184  
   185  func formatAppVersion(c *chart.Chart) string {
   186  	if c == nil || c.Metadata == nil {
   187  		// This is an edge case that has happened in prod, though we don't
   188  		// know how: https://github.com/helm/helm/issues/1347
   189  		return "MISSING"
   190  	}
   191  	return c.AppVersion()
   192  }