compare-revisions.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package cmd
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. api "github.com/porter-dev/porter/api/client"
  7. "github.com/porter-dev/porter/api/types"
  8. "github.com/spf13/cobra"
  9. )
  10. var compareRevisionsCmd = &cobra.Command{
  11. Use: "compare-revisions",
  12. Short: "Compare two revisions of a release. Arguments must be in the form: porter compare-revisions <release-name> <base-revision-number> <changed-revision-number>",
  13. Run: func(cmd *cobra.Command, args []string) {
  14. err := checkLoginAndRun(args, runCompareRevisions)
  15. if err != nil {
  16. os.Exit(1)
  17. }
  18. },
  19. }
  20. func init() {
  21. rootCmd.AddCommand(compareRevisionsCmd)
  22. }
  23. func runCompareRevisions(_ *types.GetAuthenticatedUserResponse, client *api.Client, args []string) error {
  24. _, err := exec.LookPath("helm")
  25. if err != nil {
  26. return fmt.Errorf("error finding helm: %w", err)
  27. }
  28. _, err = exec.LookPath("colordiff")
  29. if err != nil {
  30. return fmt.Errorf("error finding colordiff: %w", err)
  31. }
  32. tmpFile, err := downloadTempKubeconfig(client)
  33. if err != nil {
  34. return err
  35. }
  36. defer func() {
  37. os.Remove(tmpFile)
  38. }()
  39. if len(args) != 3 {
  40. return fmt.Errorf("arguments must be in the form: porter compare-revisions <release-name> <base-revision-number> <changed-revision-number>")
  41. }
  42. os.Setenv("KUBECONFIG", tmpFile)
  43. baseConfig, err := exec.Command("helm", []string{"get", "values", args[0], "--revision", args[1]}...).Output()
  44. if err != nil {
  45. return fmt.Errorf("error retrieving revision %s for release with name %s: %w", args[0], args[1], err)
  46. }
  47. changedConfig, err := exec.Command("helm", []string{"get", "values", args[0], "--revision", args[2]}...).Output()
  48. if err != nil {
  49. return fmt.Errorf("error retrieving revision %s for release with name %s: %w", args[0], args[2], err)
  50. }
  51. baseTmpFile, err := createTempFile("base-config", baseConfig)
  52. if err != nil {
  53. return fmt.Errorf("error creating base temp file: %w", err)
  54. }
  55. defer baseTmpFile.Close()
  56. defer os.Remove(baseTmpFile.Name())
  57. changedTmpFile, err := createTempFile("changed-config", changedConfig)
  58. if err != nil {
  59. return fmt.Errorf("error creating changed temp file: %w", err)
  60. }
  61. defer changedTmpFile.Close()
  62. defer os.Remove(changedTmpFile.Name())
  63. cmd := exec.Command("colordiff", baseTmpFile.Name(), changedTmpFile.Name(), "-y")
  64. cmd.Stdout = os.Stdout
  65. cmd.Stderr = os.Stderr
  66. err = cmd.Run()
  67. // colordiff returns exit status 1 if there are differences
  68. if err != nil && err.Error() != "exit status 1" {
  69. return fmt.Errorf("error running diff: %w", err)
  70. }
  71. return nil
  72. }
  73. func createTempFile(prefix string, config []byte) (*os.File, error) {
  74. tmpFile, err := os.CreateTemp("", prefix)
  75. if err != nil {
  76. return nil, fmt.Errorf("error creating temp file: %w", err)
  77. }
  78. if err := os.WriteFile(tmpFile.Name(), config, 0644); err != nil {
  79. return nil, fmt.Errorf("error writing to temp file: %w", err)
  80. }
  81. return tmpFile, nil
  82. }