Skip to content

Commit 57c22fe

Browse files
committed
Introduce porter.NewWith, deprecate porter.New
Signed-off-by: robinbraemer <[email protected]>
1 parent 5fed9dc commit 57c22fe

9 files changed

+154
-40
lines changed

cmd/porter/bundle_test.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import (
99
"get.porter.sh/porter/pkg"
1010
"get.porter.sh/porter/tests"
1111

12-
"get.porter.sh/porter/pkg/porter"
1312
"github.com/spf13/cobra"
1413
"github.com/stretchr/testify/assert"
1514
"github.com/stretchr/testify/require"
15+
16+
"get.porter.sh/porter/pkg/porter"
1617
)
1718

1819
func TestValidateInstallCommand(t *testing.T) {
@@ -30,7 +31,7 @@ func TestValidateInstallCommand(t *testing.T) {
3031
for _, tc := range testcases {
3132
t.Run(tc.name, func(t *testing.T) {
3233
var outBuf bytes.Buffer
33-
p := buildRootCommand()
34+
p := buildRootCommand(t)
3435
p.SetOut(&outBuf)
3536
p.SetErr(&outBuf)
3637
osargs := strings.Split(tc.args, " ")
@@ -69,7 +70,7 @@ func TestValidateUninstallCommand(t *testing.T) {
6970
for _, tc := range testcases {
7071
t.Run(tc.name, func(t *testing.T) {
7172
var outBuf bytes.Buffer
72-
p := buildRootCommand()
73+
p := buildRootCommand(t)
7374
p.SetOut(&outBuf)
7475
p.SetErr(&outBuf)
7576
osargs := strings.Split(tc.args, " ")
@@ -105,7 +106,7 @@ func TestValidateInvokeCommand(t *testing.T) {
105106

106107
for _, tc := range testcases {
107108
t.Run(tc.name, func(t *testing.T) {
108-
p := buildRootCommand()
109+
p := buildRootCommand(t)
109110
osargs := strings.Split(tc.args, " ")
110111
cmd, args, err := p.Find(osargs)
111112
require.NoError(t, err)
@@ -136,7 +137,7 @@ func TestValidateInstallationListCommand(t *testing.T) {
136137

137138
for _, tc := range testcases {
138139
t.Run(tc.name, func(t *testing.T) {
139-
p := buildRootCommand()
140+
p := buildRootCommand(t)
140141
osargs := strings.Split(tc.args, " ")
141142
cmd, args, err := p.Find(osargs)
142143
require.NoError(t, err)

cmd/porter/completion_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import (
55
"os"
66
"testing"
77

8-
"get.porter.sh/porter/pkg/porter"
98
"github.com/stretchr/testify/assert"
109
"github.com/stretchr/testify/require"
10+
11+
"get.porter.sh/porter/pkg/porter"
1112
)
1213

1314
func TestCompletion(t *testing.T) {
14-
p := buildRootCommand()
15+
p := buildRootCommand(t)
1516

1617
// Capture the output of the command.
1718
var out bytes.Buffer

cmd/porter/main.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ import (
1010
"strconv"
1111
"strings"
1212

13-
"get.porter.sh/porter/pkg/cli"
14-
"get.porter.sh/porter/pkg/config"
15-
"get.porter.sh/porter/pkg/porter"
1613
"github.com/spf13/cobra"
1714
"github.com/spf13/pflag"
1815
"go.opentelemetry.io/otel/attribute"
1916
"go.opentelemetry.io/otel/trace"
17+
18+
"get.porter.sh/porter/pkg/cli"
19+
"get.porter.sh/porter/pkg/config"
20+
"get.porter.sh/porter/pkg/porter"
2021
)
2122

2223
var includeDocsCommand = false
@@ -35,7 +36,12 @@ const (
3536

3637
func main() {
3738
run := func() int {
38-
p := porter.New()
39+
p, err := porter.NewWith(porter.Options{})
40+
if err != nil {
41+
fmt.Fprintln(os.Stderr, err.Error())
42+
os.Exit(cli.ExitCodeErr)
43+
}
44+
3945
ctx, cancel := handleInterrupt(context.Background(), p)
4046
defer cancel()
4147

@@ -158,10 +164,6 @@ func getCalledCommand(cmd *cobra.Command) (*cobra.Command, string, string) {
158164
return calledCommand, calledCommandStr, formattedCommand
159165
}
160166

161-
func buildRootCommand() *cobra.Command {
162-
return buildRootCommandFrom(porter.New())
163-
}
164-
165167
func buildRootCommandFrom(p *porter.Porter) *cobra.Command {
166168
var printVersion bool
167169

cmd/porter/main_test.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@ import (
66
"strings"
77
"testing"
88

9+
"github.com/spf13/cobra"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
913
"get.porter.sh/porter/pkg"
1014
"get.porter.sh/porter/pkg/config"
1115
"get.porter.sh/porter/pkg/experimental"
1216
"get.porter.sh/porter/pkg/porter"
13-
"github.com/stretchr/testify/assert"
14-
"github.com/stretchr/testify/require"
1517
)
1618

19+
func buildRootCommand(t *testing.T) *cobra.Command {
20+
p, err := porter.NewWith(porter.Options{})
21+
require.NoError(t, err)
22+
return buildRootCommandFrom(p)
23+
}
24+
1725
func TestCommandWiring(t *testing.T) {
1826
testcases := []string{
1927
"build",
@@ -39,7 +47,7 @@ func TestCommandWiring(t *testing.T) {
3947
t.Run(tc, func(t *testing.T) {
4048
osargs := strings.Split(tc, " ")
4149

42-
rootCmd := buildRootCommand()
50+
rootCmd := buildRootCommand(t)
4351
cmd, _, err := rootCmd.Find(osargs)
4452
assert.NoError(t, err)
4553
assert.Equal(t, osargs[len(osargs)-1], cmd.Name())
@@ -50,7 +58,7 @@ func TestCommandWiring(t *testing.T) {
5058
func TestHelp(t *testing.T) {
5159
t.Run("no args", func(t *testing.T) {
5260
var output bytes.Buffer
53-
rootCmd := buildRootCommand()
61+
rootCmd := buildRootCommand(t)
5462
rootCmd.SetArgs([]string{})
5563
rootCmd.SetOut(&output)
5664

@@ -61,7 +69,7 @@ func TestHelp(t *testing.T) {
6169

6270
t.Run("help", func(t *testing.T) {
6371
var output bytes.Buffer
64-
rootCmd := buildRootCommand()
72+
rootCmd := buildRootCommand(t)
6573
rootCmd.SetArgs([]string{"help"})
6674
rootCmd.SetOut(&output)
6775

@@ -72,7 +80,7 @@ func TestHelp(t *testing.T) {
7280

7381
t.Run("--help", func(t *testing.T) {
7482
var output bytes.Buffer
75-
rootCmd := buildRootCommand()
83+
rootCmd := buildRootCommand(t)
7684
rootCmd.SetArgs([]string{"--help"})
7785
rootCmd.SetOut(&output)
7886

cmd/porter/version_test.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ import (
55
"os"
66
"testing"
77

8-
"get.porter.sh/porter/pkg"
98
"github.com/stretchr/testify/assert"
109
"github.com/stretchr/testify/require"
10+
11+
"get.porter.sh/porter/pkg"
1112
)
1213

1314
func TestVersion(t *testing.T) {
1415
pkg.Version = "v1.0.0"
1516
pkg.Commit = "abc123"
1617

1718
t.Run("command", func(t *testing.T) {
18-
p := buildRootCommand()
19+
p := buildRootCommand(t)
1920

2021
// Capture output
2122
var out bytes.Buffer
@@ -30,7 +31,7 @@ func TestVersion(t *testing.T) {
3031
})
3132

3233
t.Run("flag", func(t *testing.T) {
33-
p := buildRootCommand()
34+
p := buildRootCommand(t)
3435

3536
// Capture output
3637
var out bytes.Buffer

pkg/porter/helpers.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import (
1111
"testing"
1212
"time"
1313

14+
"github.com/cnabio/cnab-go/bundle"
15+
"github.com/stretchr/testify/require"
16+
1417
"get.porter.sh/porter/pkg/build"
1518
"get.porter.sh/porter/pkg/cache"
1619
"get.porter.sh/porter/pkg/cnab"
@@ -26,8 +29,6 @@ import (
2629
"get.porter.sh/porter/pkg/storage"
2730
"get.porter.sh/porter/pkg/tracing"
2831
"get.porter.sh/porter/pkg/yaml"
29-
"github.com/cnabio/cnab-go/bundle"
30-
"github.com/stretchr/testify/require"
3132
)
3233

3334
type TestPorter struct {
@@ -123,8 +124,10 @@ func (p *TestPorter) SetupIntegrationTest() context.Context {
123124
p.CreateBundleDir()
124125

125126
// Write out a storage schema so that we don't trigger a migration check
126-
err := p.Storage.WriteSchema(ctx)
127-
require.NoError(t, err, "failed to set the storage schema")
127+
if p.Storage != nil {
128+
err := p.Storage.WriteSchema(ctx)
129+
require.NoError(t, err, "failed to set the storage schema")
130+
}
128131

129132
// Load test credentials, with KUBECONFIG replaced properly
130133
kubeconfig := filepath.Join(p.RepoRoot, "kind.config")

pkg/porter/porter.go

+103-11
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"net/url"
78
"strings"
89
"sync"
910

11+
"github.com/hashicorp/go-multierror"
12+
"gorm.io/driver/postgres"
13+
"gorm.io/gorm"
14+
1015
"get.porter.sh/porter/pkg/build"
1116
"get.porter.sh/porter/pkg/build/buildkit"
1217
"get.porter.sh/porter/pkg/cache"
@@ -22,9 +27,9 @@ import (
2227
"get.porter.sh/porter/pkg/storage"
2328
"get.porter.sh/porter/pkg/storage/migrations"
2429
storageplugin "get.porter.sh/porter/pkg/storage/pluginstore"
30+
"get.porter.sh/porter/pkg/storage/sql"
2531
"get.porter.sh/porter/pkg/templates"
2632
"get.porter.sh/porter/pkg/tracing"
27-
"github.com/hashicorp/go-multierror"
2833
)
2934

3035
// Porter is the logic behind the porter client.
@@ -47,22 +52,63 @@ type Porter struct {
4752
Plugins plugins.PluginProvider
4853
CNAB cnabprovider.CNABProvider
4954
Secrets secrets.Store
50-
Storage storage.Provider
5155
Signer signing.Signer
56+
57+
// Deprecated: Use the individual storage providers in the Porter struct instead
58+
// This is only here for backwards compatibility where MongoDB was the only storage provider.
59+
Storage storage.Provider
60+
}
61+
62+
// Options for configuring a new Porter client passed to NewWith.
63+
type Options struct {
64+
Config *config.Config // Optional. Defaults to a config.New.
65+
SecretStorage secrets.Store // Optional. Defaults to a secrets.NewPluginAdapter(secretsplugin.NewStore).
66+
Signer signing.Signer // Optional. Defaults to a signing.NewPluginAdapter(signingplugin.NewSigner).
67+
}
68+
69+
// NewWith creates a new Porter client with useful defaults that can be overridden with the provided options.
70+
func NewWith(opt Options) (*Porter, error) {
71+
if opt.Config == nil {
72+
opt.Config = config.New()
73+
}
74+
if opt.SecretStorage == nil {
75+
opt.SecretStorage = secrets.NewPluginAdapter(secretsplugin.NewStore(opt.Config))
76+
}
77+
if opt.Signer == nil {
78+
opt.Signer = signing.NewPluginAdapter(signingplugin.NewSigner(opt.Config))
79+
}
80+
81+
if p, ok := sql.IsPostgresStorage(opt.Config); ok {
82+
po, err := newWithSQL(opt.Config, p, opt.SecretStorage, opt.Signer)
83+
if err != nil {
84+
return nil, err
85+
}
86+
return po, nil
87+
}
88+
89+
storage := storage.NewPluginAdapter(storageplugin.NewStore(opt.Config))
90+
return newFor(opt.Config, storage, opt.SecretStorage, opt.Signer), nil
5291
}
5392

5493
// New porter client, initialized with useful defaults.
94+
//
95+
// Deprecated: Use NewWith instead. New does not support SQL storage backends.
5596
func New() *Porter {
5697
c := config.New()
57-
storage := storage.NewPluginAdapter(storageplugin.NewStore(c))
98+
5899
secretStorage := secrets.NewPluginAdapter(secretsplugin.NewStore(c))
59100
signer := signing.NewPluginAdapter(signingplugin.NewSigner(c))
60-
return NewFor(c, storage, secretStorage, signer)
61-
}
62101

63-
func NewFor(c *config.Config, store storage.Store, secretStorage secrets.Store, signer signing.Signer) *Porter {
64-
cache := cache.New(c)
102+
storage := storage.NewPluginAdapter(storageplugin.NewStore(c))
103+
return newFor(c, storage, secretStorage, signer)
104+
}
65105

106+
func newFor(
107+
c *config.Config,
108+
store storage.Store,
109+
secretStorage secrets.Store,
110+
signer signing.Signer,
111+
) *Porter {
66112
storageManager := migrations.NewManager(c, store)
67113
installationStorage := storage.NewInstallationStore(storageManager)
68114
credStorage := storage.NewCredentialStore(storageManager, secretStorage)
@@ -71,9 +117,53 @@ func NewFor(c *config.Config, store storage.Store, secretStorage secrets.Store,
71117

72118
storageManager.Initialize(sanitizerService) // we have a bit of a dependency problem here that it would be great to figure out eventually
73119

120+
return newWith(c, installationStorage, credStorage, paramStorage, secretStorage, signer, sanitizerService, storageManager)
121+
}
122+
123+
func newWithSQL(
124+
c *config.Config,
125+
p config.StoragePlugin,
126+
secretStorage secrets.Store,
127+
signer signing.Signer,
128+
) (*Porter, error) {
129+
pc, err := sql.UnmarshalPluginConfig(p.GetConfig())
130+
if err != nil {
131+
return nil, fmt.Errorf("could not unmarshal plugin config: %s", err)
132+
}
133+
if pc.URL == "" {
134+
return nil, errors.New("no URL provided in plugin config")
135+
}
136+
_, err = url.Parse(pc.URL)
137+
if err != nil {
138+
return nil, fmt.Errorf("invalid URL provided in plugin config: %s", err)
139+
}
140+
db, err := gorm.Open(postgres.Open(pc.URL))
141+
if err != nil {
142+
return nil, fmt.Errorf("could not open database: %s", err)
143+
}
144+
145+
installationStorage := storage.NewInstallationStoreSQL(db)
146+
credStorage := storage.NewCredentialStoreSQL(db, secretStorage)
147+
paramStorage := storage.NewParameterStoreSQL(db, secretStorage)
148+
sanitizerService := storage.NewSanitizer(paramStorage, secretStorage)
149+
150+
return newWith(c, installationStorage, credStorage, paramStorage, secretStorage, signer, sanitizerService, nil), nil
151+
}
152+
153+
func newWith(
154+
c *config.Config,
155+
installationStorage storage.InstallationProvider,
156+
credStorage storage.CredentialSetProvider,
157+
paramStorage storage.ParameterSetProvider,
158+
secretStorage secrets.Store,
159+
signer signing.Signer,
160+
sanitizerService *storage.Sanitizer,
161+
storageManager storage.Provider,
162+
) *Porter {
163+
74164
return &Porter{
75165
Config: c,
76-
Cache: cache,
166+
Cache: cache.New(c),
77167
Storage: storageManager,
78168
Installations: installationStorage,
79169
Credentials: credStorage,
@@ -129,9 +219,11 @@ func (p *Porter) Close() error {
129219
bigErr = multierror.Append(bigErr, err)
130220
}
131221

132-
err = p.Storage.Close()
133-
if err != nil {
134-
bigErr = multierror.Append(bigErr, err)
222+
if p.Storage != nil {
223+
err = p.Storage.Close()
224+
if err != nil {
225+
bigErr = multierror.Append(bigErr, err)
226+
}
135227
}
136228

137229
err = p.Config.Close()

0 commit comments

Comments
 (0)