github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/internal/commands/config_registries_test.go (about)

     1  package commands_test
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/heroku/color"
    11  	"github.com/sclevine/spec"
    12  	"github.com/sclevine/spec/report"
    13  	"github.com/spf13/cobra"
    14  
    15  	"github.com/buildpacks/pack/internal/commands"
    16  	"github.com/buildpacks/pack/internal/config"
    17  	"github.com/buildpacks/pack/pkg/logging"
    18  	h "github.com/buildpacks/pack/testhelpers"
    19  )
    20  
    21  func TestConfigRegistries(t *testing.T) {
    22  	color.Disable(true)
    23  	defer color.Disable(false)
    24  	spec.Run(t, "ConfigRegistriesCommand", testConfigRegistries, spec.Random(), spec.Report(report.Terminal{}))
    25  }
    26  
    27  func testConfigRegistries(t *testing.T, when spec.G, it spec.S) {
    28  	var (
    29  		cmd               *cobra.Command
    30  		logger            logging.Logger
    31  		cfgWithRegistries config.Config
    32  		outBuf            bytes.Buffer
    33  		tempPackHome      string
    34  		configPath        string
    35  		assert            = h.NewAssertionManager(t)
    36  	)
    37  
    38  	it.Before(func() {
    39  		var err error
    40  
    41  		logger = logging.NewLogWithWriters(&outBuf, &outBuf)
    42  		tempPackHome, err = os.MkdirTemp("", "pack-home")
    43  		assert.Nil(err)
    44  		configPath = filepath.Join(tempPackHome, "config.toml")
    45  
    46  		cmd = commands.ConfigRegistries(logger, config.Config{}, configPath)
    47  		cmd.SetOut(logging.GetWriterForLevel(logger, logging.InfoLevel))
    48  
    49  		cfgWithRegistries = config.Config{
    50  			DefaultRegistryName: "private registry",
    51  			Registries: []config.Registry{
    52  				{
    53  					Name: "public registry",
    54  					Type: "github",
    55  					URL:  "https://github.com/buildpacks/public-registry",
    56  				},
    57  				{
    58  					Name: "private registry",
    59  					Type: "github",
    60  					URL:  "https://github.com/buildpacks/private-registry",
    61  				},
    62  				{
    63  					Name: "personal registry",
    64  					Type: "github",
    65  					URL:  "https://github.com/buildpacks/personal-registry",
    66  				},
    67  			},
    68  		}
    69  	})
    70  
    71  	it.After(func() {
    72  		assert.Nil(os.RemoveAll(tempPackHome))
    73  	})
    74  
    75  	when("-h", func() {
    76  		it("prints help text", func() {
    77  			cmd.SetArgs([]string{"-h"})
    78  			assert.Nil(cmd.Execute())
    79  			output := outBuf.String()
    80  			assert.Contains(output, "Usage:")
    81  			for _, command := range []string{"add", "remove", "list", "default"} {
    82  				assert.Contains(output, command)
    83  			}
    84  		})
    85  	})
    86  
    87  	when("no args", func() {
    88  		it("calls list", func() {
    89  			logger = logging.NewLogWithWriters(&outBuf, &outBuf)
    90  			cfgWithRegistries = config.Config{
    91  				DefaultRegistryName: "private registry",
    92  				Registries: []config.Registry{
    93  					{
    94  						Name: "public registry",
    95  						Type: "github",
    96  						URL:  "https://github.com/buildpacks/public-registry",
    97  					},
    98  					{
    99  						Name: "private registry",
   100  						Type: "github",
   101  						URL:  "https://github.com/buildpacks/private-registry",
   102  					},
   103  					{
   104  						Name: "personal registry",
   105  						Type: "github",
   106  						URL:  "https://github.com/buildpacks/personal-registry",
   107  					},
   108  				},
   109  			}
   110  			cmd = commands.ConfigRegistries(logger, cfgWithRegistries, configPath)
   111  			cmd.SetArgs([]string{})
   112  
   113  			assert.Nil(cmd.Execute())
   114  			assert.Contains(outBuf.String(), "public registry")
   115  			assert.Contains(outBuf.String(), "* private registry")
   116  			assert.Contains(outBuf.String(), "personal registry")
   117  		})
   118  	})
   119  
   120  	when("list", func() {
   121  		var args = []string{"list"}
   122  		it.Before(func() {
   123  			logger = logging.NewLogWithWriters(&outBuf, &outBuf)
   124  			cmd = commands.ConfigRegistries(logger, cfgWithRegistries, configPath)
   125  			cmd.SetArgs(args)
   126  		})
   127  
   128  		it("should list all registries", func() {
   129  			assert.Nil(cmd.Execute())
   130  
   131  			assert.Contains(outBuf.String(), "public registry")
   132  			assert.Contains(outBuf.String(), "* private registry")
   133  			assert.Contains(outBuf.String(), "personal registry")
   134  		})
   135  
   136  		it("should list registries in verbose mode", func() {
   137  			logger = logging.NewLogWithWriters(&outBuf, &outBuf, logging.WithVerbose())
   138  			cmd = commands.ConfigRegistries(logger, cfgWithRegistries, configPath)
   139  			cmd.SetArgs(args)
   140  			assert.Nil(cmd.Execute())
   141  
   142  			assert.Contains(outBuf.String(), "public registry")
   143  			assert.Contains(outBuf.String(), "https://github.com/buildpacks/public-registry")
   144  
   145  			assert.Contains(outBuf.String(), "* private registry")
   146  			assert.Contains(outBuf.String(), "https://github.com/buildpacks/private-registry")
   147  
   148  			assert.Contains(outBuf.String(), "personal registry")
   149  			assert.Contains(outBuf.String(), "https://github.com/buildpacks/personal-registry")
   150  
   151  			assert.Contains(outBuf.String(), "official")
   152  			assert.Contains(outBuf.String(), "https://github.com/buildpacks/registry-index")
   153  		})
   154  
   155  		it("should indicate official as the default registry by default", func() {
   156  			cfgWithRegistries.DefaultRegistryName = ""
   157  			cmd = commands.ConfigRegistries(logger, cfgWithRegistries, configPath)
   158  			cmd.SetArgs(args)
   159  
   160  			assert.Nil(cmd.Execute())
   161  
   162  			assert.Contains(outBuf.String(), "* official")
   163  			assert.Contains(outBuf.String(), "public registry")
   164  			assert.Contains(outBuf.String(), "private registry")
   165  			assert.Contains(outBuf.String(), "personal registry")
   166  		})
   167  
   168  		it("should use official when no registries are defined", func() {
   169  			cmd = commands.ConfigRegistries(logger, config.Config{}, configPath)
   170  			cmd.SetArgs(args)
   171  
   172  			assert.Nil(cmd.Execute())
   173  
   174  			assert.Contains(outBuf.String(), "* official")
   175  		})
   176  	})
   177  
   178  	when("add", func() {
   179  		var (
   180  			args = []string{"add", "bp", "https://github.com/buildpacks/registry-index/"}
   181  		)
   182  
   183  		when("add buildpack registry", func() {
   184  			it("adds to registry list", func() {
   185  				cmd.SetArgs(args)
   186  				assert.Succeeds(cmd.Execute())
   187  
   188  				cfg, err := config.Read(configPath)
   189  				assert.Nil(err)
   190  				assert.Equal(len(cfg.Registries), 1)
   191  				assert.Equal(cfg.Registries[0].Name, "bp")
   192  				assert.Equal(cfg.Registries[0].Type, "github")
   193  				assert.Equal(cfg.Registries[0].URL, "https://github.com/buildpacks/registry-index/")
   194  				assert.Equal(cfg.DefaultRegistryName, "")
   195  			})
   196  		})
   197  
   198  		when("default is true", func() {
   199  			it("sets newly added registry as the default", func() {
   200  				cmd.SetArgs(append(args, "--default"))
   201  				assert.Succeeds(cmd.Execute())
   202  
   203  				cfg, err := config.Read(configPath)
   204  				assert.Nil(err)
   205  				assert.Equal(len(cfg.Registries), 1)
   206  				assert.Equal(cfg.Registries[0].Name, "bp")
   207  				assert.Equal(cfg.DefaultRegistryName, "bp")
   208  			})
   209  		})
   210  
   211  		when("validation", func() {
   212  			it("fails with missing args", func() {
   213  				cmd.SetOut(io.Discard)
   214  				cmd.SetArgs([]string{"add"})
   215  				err := cmd.Execute()
   216  				assert.ErrorContains(err, "accepts 2 arg")
   217  			})
   218  
   219  			it("should validate type", func() {
   220  				cmd.SetArgs(append(args, "--type=bogus"))
   221  				assert.Error(cmd.Execute())
   222  
   223  				output := outBuf.String()
   224  				assert.Contains(output, "'bogus' is not a valid type. Supported types are: 'git', 'github'.")
   225  			})
   226  
   227  			it("should throw error when registry already exists", func() {
   228  				command := commands.ConfigRegistries(logger, config.Config{
   229  					Registries: []config.Registry{
   230  						{
   231  							Name: "bp",
   232  							Type: "github",
   233  							URL:  "https://github.com/buildpacks/registry-index/",
   234  						},
   235  					},
   236  				}, configPath)
   237  				command.SetArgs(args)
   238  				assert.Error(command.Execute())
   239  
   240  				output := outBuf.String()
   241  				assert.Contains(output, "Buildpack registry 'bp' already exists.")
   242  			})
   243  
   244  			it("should throw error when registry name is official", func() {
   245  				cmd.SetOut(logging.GetWriterForLevel(logger, logging.InfoLevel))
   246  				cmd.SetErr(&outBuf)
   247  				cmd.SetArgs([]string{"add", "official", "https://github.com/buildpacks/registry-index/", "--type=github"})
   248  
   249  				assert.Error(cmd.Execute())
   250  
   251  				output := outBuf.String()
   252  				assert.Contains(output, "'official' is a reserved registry, please provide a different name")
   253  			})
   254  
   255  			it("returns clear error if fails to write", func() {
   256  				assert.Nil(os.WriteFile(configPath, []byte("something"), 0001))
   257  				cmd.SetArgs(args)
   258  				assert.ErrorContains(cmd.Execute(), "writing config to")
   259  			})
   260  		})
   261  	})
   262  
   263  	when("remove", func() {
   264  		it.Before(func() {
   265  			cmd = commands.ConfigRegistries(logger, cfgWithRegistries, configPath)
   266  		})
   267  
   268  		it("should remove the registry", func() {
   269  			cmd.SetArgs([]string{"remove", "public registry"})
   270  			assert.Succeeds(cmd.Execute())
   271  
   272  			newCfg, err := config.Read(configPath)
   273  			assert.Nil(err)
   274  
   275  			assert.Equal(newCfg, config.Config{
   276  				DefaultRegistryName: "private registry",
   277  				Registries: []config.Registry{
   278  					{
   279  						Name: "personal registry",
   280  						Type: "github",
   281  						URL:  "https://github.com/buildpacks/personal-registry",
   282  					},
   283  					{
   284  						Name: "private registry",
   285  						Type: "github",
   286  						URL:  "https://github.com/buildpacks/private-registry",
   287  					},
   288  				},
   289  			})
   290  		})
   291  
   292  		it("should remove the registry and matching default registry name", func() {
   293  			cmd.SetArgs([]string{"remove", "private registry"})
   294  			assert.Succeeds(cmd.Execute())
   295  
   296  			newCfg, err := config.Read(configPath)
   297  			assert.Nil(err)
   298  
   299  			assert.Equal(newCfg, config.Config{
   300  				DefaultRegistryName: config.OfficialRegistryName,
   301  				Registries: []config.Registry{
   302  					{
   303  						Name: "public registry",
   304  						Type: "github",
   305  						URL:  "https://github.com/buildpacks/public-registry",
   306  					},
   307  					{
   308  						Name: "personal registry",
   309  						Type: "github",
   310  						URL:  "https://github.com/buildpacks/personal-registry",
   311  					},
   312  				},
   313  			})
   314  		})
   315  
   316  		it("should return error when registry does NOT already exist", func() {
   317  			cmd.SetArgs([]string{"remove", "missing-registry"})
   318  			assert.Error(cmd.Execute())
   319  
   320  			output := outBuf.String()
   321  			assert.Contains(output, "registry 'missing-registry' does not exist")
   322  		})
   323  
   324  		it("should throw error when registry name is official", func() {
   325  			cmd.SetArgs([]string{"remove", "official"})
   326  			assert.Error(cmd.Execute())
   327  
   328  			output := outBuf.String()
   329  			assert.Contains(output, "'official' is a reserved registry name, please provide a different registry")
   330  		})
   331  
   332  		it("returns clear error if fails to write", func() {
   333  			assert.Nil(os.WriteFile(configPath, []byte("something"), 0001))
   334  			cmd.SetArgs([]string{"remove", "public registry"})
   335  			assert.ErrorContains(cmd.Execute(), "writing config to")
   336  		})
   337  	})
   338  }