github.com/jmcelwain/helm@v3.0.0-beta.3+incompatible/cmd/helm/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 main
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  
    23  	"github.com/gosuri/uitable"
    24  	"github.com/spf13/cobra"
    25  
    26  	"helm.sh/helm/cmd/helm/require"
    27  	"helm.sh/helm/pkg/action"
    28  	"helm.sh/helm/pkg/chart"
    29  	"helm.sh/helm/pkg/release"
    30  	"helm.sh/helm/pkg/releaseutil"
    31  )
    32  
    33  var historyHelp = `
    34  History prints historical revisions for a given release.
    35  
    36  A default maximum of 256 revisions will be returned. Setting '--max'
    37  configures the maximum length of the revision list returned.
    38  
    39  The historical release set is printed as a formatted table, e.g:
    40  
    41      $ helm history angry-bird --max=4
    42      REVISION    UPDATED                     STATUS          CHART             APP VERSION     DESCRIPTION
    43      1           Mon Oct 3 10:15:13 2016     superseded      alpine-0.1.0      1.0             Initial install
    44      2           Mon Oct 3 10:15:13 2016     superseded      alpine-0.1.0      1.0             Upgraded successfully
    45      3           Mon Oct 3 10:15:13 2016     superseded      alpine-0.1.0      1.0             Rolled back to 2
    46      4           Mon Oct 3 10:15:13 2016     deployed        alpine-0.1.0      1.0             Upgraded successfully
    47  `
    48  
    49  func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
    50  	client := action.NewHistory(cfg)
    51  
    52  	cmd := &cobra.Command{
    53  		Use:     "history RELEASE_NAME",
    54  		Long:    historyHelp,
    55  		Short:   "fetch release history",
    56  		Aliases: []string{"hist"},
    57  		Args:    require.ExactArgs(1),
    58  		RunE: func(cmd *cobra.Command, args []string) error {
    59  			history, err := getHistory(client, args[0])
    60  			if err != nil {
    61  				return err
    62  			}
    63  			fmt.Fprintln(out, history)
    64  			return nil
    65  		},
    66  	}
    67  
    68  	f := cmd.Flags()
    69  	f.StringVarP(&client.OutputFormat, "output", "o", action.Table.String(), "prints the output in the specified format (json|table|yaml)")
    70  	f.IntVar(&client.Max, "max", 256, "maximum number of revision to include in history")
    71  
    72  	return cmd
    73  }
    74  
    75  type releaseInfo struct {
    76  	Revision    int    `json:"revision"`
    77  	Updated     string `json:"updated"`
    78  	Status      string `json:"status"`
    79  	Chart       string `json:"chart"`
    80  	AppVersion  string `json:"app_version"`
    81  	Description string `json:"description"`
    82  }
    83  
    84  type releaseHistory []releaseInfo
    85  
    86  func marshalHistory(format action.OutputFormat, hist releaseHistory) (byt []byte, err error) {
    87  	switch format {
    88  	case action.YAML, action.JSON:
    89  		byt, err = format.Marshal(hist)
    90  	case action.Table:
    91  		byt, err = format.MarshalTable(func(tbl *uitable.Table) {
    92  			tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "DESCRIPTION")
    93  			for i := 0; i <= len(hist)-1; i++ {
    94  				r := hist[i]
    95  				tbl.AddRow(r.Revision, r.Updated, r.Status, r.Chart, r.AppVersion, r.Description)
    96  			}
    97  		})
    98  	default:
    99  		err = action.ErrInvalidFormatType
   100  	}
   101  	return
   102  }
   103  
   104  func getHistory(client *action.History, name string) (string, error) {
   105  	hist, err := client.Run(name)
   106  	if err != nil {
   107  		return "", err
   108  	}
   109  
   110  	releaseutil.Reverse(hist, releaseutil.SortByRevision)
   111  
   112  	var rels []*release.Release
   113  	for i := 0; i < min(len(hist), client.Max); i++ {
   114  		rels = append(rels, hist[i])
   115  	}
   116  
   117  	if len(rels) == 0 {
   118  		return "", nil
   119  	}
   120  
   121  	releaseHistory := getReleaseHistory(rels)
   122  
   123  	outputFormat, err := action.ParseOutputFormat(client.OutputFormat)
   124  	if err != nil {
   125  		return "", err
   126  	}
   127  	history, formattingError := marshalHistory(outputFormat, releaseHistory)
   128  	if formattingError != nil {
   129  		return "", formattingError
   130  	}
   131  
   132  	return string(history), nil
   133  }
   134  
   135  func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
   136  	for i := len(rls) - 1; i >= 0; i-- {
   137  		r := rls[i]
   138  		c := formatChartname(r.Chart)
   139  		s := r.Info.Status.String()
   140  		v := r.Version
   141  		d := r.Info.Description
   142  		a := formatAppVersion(r.Chart)
   143  
   144  		rInfo := releaseInfo{
   145  			Revision:    v,
   146  			Status:      s,
   147  			Chart:       c,
   148  			AppVersion:  a,
   149  			Description: d,
   150  		}
   151  		if !r.Info.LastDeployed.IsZero() {
   152  			rInfo.Updated = r.Info.LastDeployed.String()
   153  
   154  		}
   155  		history = append(history, rInfo)
   156  	}
   157  
   158  	return history
   159  }
   160  
   161  func formatChartname(c *chart.Chart) string {
   162  	if c == nil || c.Metadata == nil {
   163  		// This is an edge case that has happened in prod, though we don't
   164  		// know how: https://github.com/helm/helm/issues/1347
   165  		return "MISSING"
   166  	}
   167  	return fmt.Sprintf("%s-%s", c.Name(), c.Metadata.Version)
   168  }
   169  
   170  func formatAppVersion(c *chart.Chart) string {
   171  	if c == nil || c.Metadata == nil {
   172  		// This is an edge case that has happened in prod, though we don't
   173  		// know how: https://github.com/helm/helm/issues/1347
   174  		return "MISSING"
   175  	}
   176  	return c.AppVersion()
   177  }
   178  
   179  func min(x, y int) int {
   180  	if x < y {
   181  		return x
   182  	}
   183  	return y
   184  }