diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 20f7247a..08fa6209 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: set -x apt-get -y update && apt-get -y install git cd / - go get -u github.com/golang/mock/mockgen@v1.4.4 + go get -u github.com/golang/mock/mockgen@v1.5.0 cd - go env go generate ./... diff --git a/client.go b/client.go index 12486c90..86761f35 100644 --- a/client.go +++ b/client.go @@ -16,6 +16,7 @@ import ( "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v3/pkg/getter" + "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v3/pkg/storage/driver" apiextensionsV1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -211,6 +212,22 @@ func (c *HelmClient) InstallOrUpgradeChart(ctx context.Context, spec *ChartSpec) return c.install(spec) } +// ListDeployedReleases lists all deployed releases. +// Namespace and other context is provided via the Options struct when instantiating a client. +func (c *HelmClient) ListDeployedReleases() ([]*release.Release, error) { + return c.listDeployedReleases() +} + +// GetReleaseValues returns the (optionally, all computed) values for the specified release. +func (c *HelmClient) GetReleaseValues(name string, allValues bool) (map[string]interface{}, error) { + return c.getReleaseValues(name, allValues) +} + +// GetRelease returns a release specified by name. +func (c *HelmClient) GetRelease(name string) (*release.Release, error) { + return c.getRelease(name) +} + // DeleteChartFromCache deletes the provided chart from the client's cache func (c *HelmClient) DeleteChartFromCache(spec *ChartSpec) error { return c.deleteChartFromCache(spec) @@ -577,6 +594,28 @@ func (c *HelmClient) chartIsInstalled(release string) (bool, error) { return true, nil } +func (c *HelmClient) listDeployedReleases() ([]*release.Release, error) { + listClient := action.NewList(c.ActionConfig) + + listClient.StateMask = action.ListDeployed + + return listClient.Run() +} + +func (c *HelmClient) getReleaseValues(name string, allValues bool) (map[string]interface{}, error) { + getReleaseValuesClient := action.NewGetValues(c.ActionConfig) + + getReleaseValuesClient.AllValues = allValues + + return getReleaseValuesClient.Run(name) +} + +func (c *HelmClient) getRelease(name string) (*release.Release, error) { + getReleaseClient := action.NewGet(c.ActionConfig) + + return getReleaseClient.Run(name) +} + // mergeInstallOptions merges values of the provided chart to helm install options used by the client func mergeInstallOptions(chartSpec *ChartSpec, installOptions *action.Install) { installOptions.DisableHooks = chartSpec.DisableHooks diff --git a/client_test.go b/client_test.go index d6ddcf65..381faf7d 100644 --- a/client_test.go +++ b/client_test.go @@ -137,3 +137,21 @@ func ExampleHelmClient_UninstallRelease() { panic(err) } } + +func ExampleHelmClient_ListDeployedReleases() { + if _, err := helmClient.ListDeployedReleases(); err != nil { + panic(err) + } +} + +func ExampleHelmClient_GetReleaseValues() { + if _, err := helmClient.GetReleaseValues("etcd-operator", true); err != nil { + panic(err) + } +} + +func ExampleHelmClient_GetRelease() { + if _, err := helmClient.GetRelease("etcd-operator"); err != nil { + panic(err) + } +} diff --git a/go.sum b/go.sum index ea3a5dac..7c187b5e 100644 --- a/go.sum +++ b/go.sum @@ -786,8 +786,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -830,8 +828,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/interface.go b/interface.go index 8a91b9f5..1292018a 100644 --- a/interface.go +++ b/interface.go @@ -3,6 +3,7 @@ package helmclient import ( "context" + "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/repo" ) @@ -12,6 +13,9 @@ type Client interface { AddOrUpdateChartRepo(entry repo.Entry) error UpdateChartRepos() error InstallOrUpgradeChart(ctx context.Context, spec *ChartSpec) error + ListDeployedReleases() ([]*release.Release, error) + GetRelease(name string) (*release.Release, error) + GetReleaseValues(name string, allValues bool) (map[string]interface{}, error) DeleteChartFromCache(spec *ChartSpec) error UninstallRelease(spec *ChartSpec) error TemplateChart(spec *ChartSpec) ([]byte, error) diff --git a/mock/interface.go b/mock/interface.go index 9421d342..12141286 100644 --- a/mock/interface.go +++ b/mock/interface.go @@ -6,36 +6,38 @@ package mockhelmclient import ( context "context" + reflect "reflect" + gomock "github.com/golang/mock/gomock" helmclient "github.com/mittwald/go-helm-client" + release "helm.sh/helm/v3/pkg/release" repo "helm.sh/helm/v3/pkg/repo" - reflect "reflect" ) -// MockClient is a mock of Client interface +// MockClient is a mock of Client interface. type MockClient struct { ctrl *gomock.Controller recorder *MockClientMockRecorder } -// MockClientMockRecorder is the mock recorder for MockClient +// MockClientMockRecorder is the mock recorder for MockClient. type MockClientMockRecorder struct { mock *MockClient } -// NewMockClient creates a new mock instance +// NewMockClient creates a new mock instance. func NewMockClient(ctrl *gomock.Controller) *MockClient { mock := &MockClient{ctrl: ctrl} mock.recorder = &MockClientMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockClient) EXPECT() *MockClientMockRecorder { return m.recorder } -// AddOrUpdateChartRepo mocks base method +// AddOrUpdateChartRepo mocks base method. func (m *MockClient) AddOrUpdateChartRepo(entry repo.Entry) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddOrUpdateChartRepo", entry) @@ -43,27 +45,57 @@ func (m *MockClient) AddOrUpdateChartRepo(entry repo.Entry) error { return ret0 } -// AddOrUpdateChartRepo indicates an expected call of AddOrUpdateChartRepo +// AddOrUpdateChartRepo indicates an expected call of AddOrUpdateChartRepo. func (mr *MockClientMockRecorder) AddOrUpdateChartRepo(entry interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOrUpdateChartRepo", reflect.TypeOf((*MockClient)(nil).AddOrUpdateChartRepo), entry) } -// UpdateChartRepos mocks base method -func (m *MockClient) UpdateChartRepos() error { +// DeleteChartFromCache mocks base method. +func (m *MockClient) DeleteChartFromCache(spec *helmclient.ChartSpec) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateChartRepos") + ret := m.ctrl.Call(m, "DeleteChartFromCache", spec) ret0, _ := ret[0].(error) return ret0 } -// UpdateChartRepos indicates an expected call of UpdateChartRepos -func (mr *MockClientMockRecorder) UpdateChartRepos() *gomock.Call { +// DeleteChartFromCache indicates an expected call of DeleteChartFromCache. +func (mr *MockClientMockRecorder) DeleteChartFromCache(spec interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChartRepos", reflect.TypeOf((*MockClient)(nil).UpdateChartRepos)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChartFromCache", reflect.TypeOf((*MockClient)(nil).DeleteChartFromCache), spec) +} + +// GetRelease mocks base method. +func (m *MockClient) GetRelease(name string) (*release.Release, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRelease", name) + ret0, _ := ret[0].(*release.Release) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// InstallOrUpgradeChart mocks base method +// GetRelease indicates an expected call of GetRelease. +func (mr *MockClientMockRecorder) GetRelease(name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRelease", reflect.TypeOf((*MockClient)(nil).GetRelease), name) +} + +// GetReleaseValues mocks base method. +func (m *MockClient) GetReleaseValues(name string, allValues bool) (map[string]interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetReleaseValues", name, allValues) + ret0, _ := ret[0].(map[string]interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetReleaseValues indicates an expected call of GetReleaseValues. +func (mr *MockClientMockRecorder) GetReleaseValues(name, allValues interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReleaseValues", reflect.TypeOf((*MockClient)(nil).GetReleaseValues), name, allValues) +} + +// InstallOrUpgradeChart mocks base method. func (m *MockClient) InstallOrUpgradeChart(ctx context.Context, spec *helmclient.ChartSpec) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "InstallOrUpgradeChart", ctx, spec) @@ -71,41 +103,42 @@ func (m *MockClient) InstallOrUpgradeChart(ctx context.Context, spec *helmclient return ret0 } -// InstallOrUpgradeChart indicates an expected call of InstallOrUpgradeChart +// InstallOrUpgradeChart indicates an expected call of InstallOrUpgradeChart. func (mr *MockClientMockRecorder) InstallOrUpgradeChart(ctx, spec interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallOrUpgradeChart", reflect.TypeOf((*MockClient)(nil).InstallOrUpgradeChart), ctx, spec) } -// DeleteChartFromCache mocks base method -func (m *MockClient) DeleteChartFromCache(spec *helmclient.ChartSpec) error { +// LintChart mocks base method. +func (m *MockClient) LintChart(spec *helmclient.ChartSpec) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteChartFromCache", spec) + ret := m.ctrl.Call(m, "LintChart", spec) ret0, _ := ret[0].(error) return ret0 } -// DeleteChartFromCache indicates an expected call of DeleteChartFromCache -func (mr *MockClientMockRecorder) DeleteChartFromCache(spec interface{}) *gomock.Call { +// LintChart indicates an expected call of LintChart. +func (mr *MockClientMockRecorder) LintChart(spec interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChartFromCache", reflect.TypeOf((*MockClient)(nil).DeleteChartFromCache), spec) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LintChart", reflect.TypeOf((*MockClient)(nil).LintChart), spec) } -// UninstallRelease mocks base method -func (m *MockClient) UninstallRelease(spec *helmclient.ChartSpec) error { +// ListDeployedReleases mocks base method. +func (m *MockClient) ListDeployedReleases() ([]*release.Release, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UninstallRelease", spec) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "ListDeployedReleases") + ret0, _ := ret[0].([]*release.Release) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// UninstallRelease indicates an expected call of UninstallRelease -func (mr *MockClientMockRecorder) UninstallRelease(spec interface{}) *gomock.Call { +// ListDeployedReleases indicates an expected call of ListDeployedReleases. +func (mr *MockClientMockRecorder) ListDeployedReleases() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallRelease", reflect.TypeOf((*MockClient)(nil).UninstallRelease), spec) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedReleases", reflect.TypeOf((*MockClient)(nil).ListDeployedReleases)) } -// TemplateChart mocks base method +// TemplateChart mocks base method. func (m *MockClient) TemplateChart(spec *helmclient.ChartSpec) ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TemplateChart", spec) @@ -114,22 +147,36 @@ func (m *MockClient) TemplateChart(spec *helmclient.ChartSpec) ([]byte, error) { return ret0, ret1 } -// TemplateChart indicates an expected call of TemplateChart +// TemplateChart indicates an expected call of TemplateChart. func (mr *MockClientMockRecorder) TemplateChart(spec interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateChart", reflect.TypeOf((*MockClient)(nil).TemplateChart), spec) } -// LintChart mocks base method -func (m *MockClient) LintChart(spec *helmclient.ChartSpec) error { +// UninstallRelease mocks base method. +func (m *MockClient) UninstallRelease(spec *helmclient.ChartSpec) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LintChart", spec) + ret := m.ctrl.Call(m, "UninstallRelease", spec) ret0, _ := ret[0].(error) return ret0 } -// LintChart indicates an expected call of LintChart -func (mr *MockClientMockRecorder) LintChart(spec interface{}) *gomock.Call { +// UninstallRelease indicates an expected call of UninstallRelease. +func (mr *MockClientMockRecorder) UninstallRelease(spec interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LintChart", reflect.TypeOf((*MockClient)(nil).LintChart), spec) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallRelease", reflect.TypeOf((*MockClient)(nil).UninstallRelease), spec) +} + +// UpdateChartRepos mocks base method. +func (m *MockClient) UpdateChartRepos() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateChartRepos") + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateChartRepos indicates an expected call of UpdateChartRepos. +func (mr *MockClientMockRecorder) UpdateChartRepos() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChartRepos", reflect.TypeOf((*MockClient)(nil).UpdateChartRepos)) } diff --git a/mock/mock_test.go b/mock/mock_test.go index 6aebbc3a..092e2209 100644 --- a/mock/mock_test.go +++ b/mock/mock_test.go @@ -4,19 +4,58 @@ import ( "testing" "github.com/golang/mock/gomock" + "helm.sh/helm/v3/pkg/release" ) -func TestUpdateChartRepos(t *testing.T) { +var mockedRelease = release.Release{Name: "test"} + +// TestHelmClientInterfaces performs checks on the clients interface functions. +func TestHelmClientInterfaces(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockClient := NewMockClient(ctrl) t.Run("UpdateChartRepos", func(t *testing.T) { - mockClient.EXPECT().UpdateChartRepos() + mockClient.EXPECT().UpdateChartRepos().Return(nil) err := mockClient.UpdateChartRepos() if err != nil { panic(err) } }) + + t.Run("ListReleases", func(t *testing.T) { + mockClient.EXPECT().ListDeployedReleases().Return([]*release.Release{&mockedRelease}, nil) + r, err := mockClient.ListDeployedReleases() + if err != nil { + panic(err) + } + if r == nil || len(r) == 0 { + panic(err) + } + }) + + t.Run("GetRelease", func(t *testing.T) { + mockClient.EXPECT().GetRelease(mockedRelease.Name).Return(&release.Release{Name: mockedRelease.Name}, nil) + r, err := mockClient.GetRelease(mockedRelease.Name) + if err != nil { + panic(err) + } + if r == nil { + panic(err) + } + }) + + t.Run("GetReleaseValues", func(t *testing.T) { + m := make(map[string]interface{}) + mockClient.EXPECT().GetReleaseValues(mockedRelease.Name, true). + Return(m, nil) + rv, err := mockClient.GetReleaseValues(mockedRelease.Name, true) + if err != nil { + panic(err) + } + if rv == nil { + panic(err) + } + }) } diff --git a/types.go b/types.go index 9f990071..1f7ee776 100644 --- a/types.go +++ b/types.go @@ -4,7 +4,6 @@ import ( "time" "helm.sh/helm/v3/pkg/getter" - "k8s.io/client-go/rest" "helm.sh/helm/v3/pkg/action"