feat(cmd): put OCI commands behind a feature gate

This adds a new `gates` package used for interacting with feature gates. It also marks the OCI registry work as experimental, signalling to users that it is not a stable feature of Helm.

Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com>
pull/6185/head
Matthew Fisher 5 years ago
parent affd77558f
commit fe952445bd
No known key found for this signature in database
GPG Key ID: 92AA783CBAAE8E3B

@ -36,6 +36,8 @@ func newChartCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Use: "chart",
Short: "push, pull, tag, or remove Helm charts",
Long: chartHelp,
Hidden: !FeatureGateOCI.IsEnabled(),
PersistentPreRunE: checkOCIFeatureGate(),
}
cmd.AddCommand(
newChartListCmd(cfg, out),

@ -39,6 +39,7 @@ func newChartExportCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
Short: "export a chart to directory",
Long: chartExportDesc,
Args: require.MinimumNArgs(1),
Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0]
return action.NewChartExport(cfg).Run(out, ref)

@ -36,6 +36,7 @@ func newChartListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Aliases: []string{"ls"},
Short: "list all saved charts",
Long: chartListDesc,
Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error {
return action.NewChartList(cfg).Run(out)
},

@ -37,6 +37,7 @@ func newChartPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Short: "pull a chart from remote",
Long: chartPullDesc,
Args: require.MinimumNArgs(1),
Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0]
return action.NewChartPull(cfg).Run(out, ref)

@ -39,6 +39,7 @@ func newChartPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Short: "push a chart to remote",
Long: chartPushDesc,
Args: require.MinimumNArgs(1),
Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0]
return action.NewChartPush(cfg).Run(out, ref)

@ -41,6 +41,7 @@ func newChartRemoveCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
Short: "remove a chart",
Long: chartRemoveDesc,
Args: require.MinimumNArgs(1),
Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0]
return action.NewChartRemove(cfg).Run(out, ref)

@ -40,6 +40,7 @@ func newChartSaveCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Short: "save a chart directory",
Long: chartSaveDesc,
Args: require.MinimumNArgs(2),
Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error {
path := args[0]
ref := args[1]

@ -24,6 +24,7 @@ import (
"strings"
"sync"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/klog"
@ -33,11 +34,15 @@ import (
"helm.sh/helm/pkg/action"
"helm.sh/helm/pkg/cli"
"helm.sh/helm/pkg/gates"
"helm.sh/helm/pkg/kube"
"helm.sh/helm/pkg/storage"
"helm.sh/helm/pkg/storage/driver"
)
// FeatureGateOCI is the feature gate for checking if `helm chart` and `helm registry` commands should work
const FeatureGateOCI = gates.Gate("HELM_EXPERIMENTAL_OCI")
var (
settings cli.EnvSettings
config genericclioptions.RESTClientGetter
@ -134,3 +139,12 @@ func getNamespace() string {
func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(strings.ReplaceAll(name, "_", "-"))
}
func checkOCIFeatureGate() func(_ *cobra.Command, _ []string) error {
return func(_ *cobra.Command, _ []string) error {
if !FeatureGateOCI.IsEnabled() {
return FeatureGateOCI.Error()
}
return nil
}
}

@ -36,6 +36,8 @@ func newRegistryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Use: "registry",
Short: "login to or logout from a registry",
Long: registryHelp,
Hidden: !FeatureGateOCI.IsEnabled(),
PersistentPreRunE: checkOCIFeatureGate(),
}
cmd.AddCommand(
newRegistryLoginCmd(cfg, out),

@ -45,6 +45,7 @@ func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Comman
Short: "login to a registry",
Long: registryLoginDesc,
Args: require.MinimumNArgs(1),
Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error {
hostname := args[0]

@ -35,6 +35,7 @@ func newRegistryLogoutCmd(cfg *action.Configuration, out io.Writer) *cobra.Comma
Short: "logout from a registry",
Long: registryLogoutDesc,
Args: require.MinimumNArgs(1),
Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error {
hostname := args[0]
return action.NewRegistryLogout(cfg).Run(out, hostname)

@ -25,9 +25,9 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/cmd/helm/require"
"helm.sh/helm/internal/experimental/registry"
"helm.sh/helm/pkg/action"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/registry"
)
const (

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "helm.sh/helm/pkg/registry"
package registry // import "helm.sh/helm/internal/experimental/registry"
import (
"github.com/deislabs/oras/pkg/auth"

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "helm.sh/helm/pkg/registry"
package registry // import "helm.sh/helm/internal/experimental/registry"
import (
"bytes"

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "helm.sh/helm/pkg/registry"
package registry // import "helm.sh/helm/internal/experimental/registry"
import (
"context"

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "helm.sh/helm/pkg/registry"
package registry // import "helm.sh/helm/internal/experimental/registry"
const (
// HelmChartConfigMediaType is the reserved media type for the Helm chart manifest config

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "helm.sh/helm/pkg/registry"
package registry // import "helm.sh/helm/internal/experimental/registry"
import (
"errors"

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "helm.sh/helm/pkg/registry"
package registry // import "helm.sh/helm/internal/experimental/registry"
import (
"github.com/containerd/containerd/remotes"

@ -30,10 +30,10 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"helm.sh/helm/internal/experimental/registry"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/hooks"
"helm.sh/helm/pkg/kube"
"helm.sh/helm/pkg/registry"
"helm.sh/helm/pkg/release"
"helm.sh/helm/pkg/storage"
)

@ -25,10 +25,10 @@ import (
dockerauth "github.com/deislabs/oras/pkg/auth/docker"
fakeclientset "k8s.io/client-go/kubernetes/fake"
"helm.sh/helm/internal/experimental/registry"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/chartutil"
kubefake "helm.sh/helm/pkg/kube/fake"
"helm.sh/helm/pkg/registry"
"helm.sh/helm/pkg/release"
"helm.sh/helm/pkg/storage"
"helm.sh/helm/pkg/storage/driver"

@ -20,8 +20,8 @@ import (
"fmt"
"io"
"helm.sh/helm/internal/experimental/registry"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/registry"
)
// ChartExport performs a chart export operation.

@ -19,7 +19,7 @@ package action
import (
"io"
"helm.sh/helm/pkg/registry"
"helm.sh/helm/internal/experimental/registry"
)
// ChartPull performs a chart pull operation.

@ -19,7 +19,7 @@ package action
import (
"io"
"helm.sh/helm/pkg/registry"
"helm.sh/helm/internal/experimental/registry"
)
// ChartPush performs a chart push operation.

@ -19,7 +19,7 @@ package action
import (
"io"
"helm.sh/helm/pkg/registry"
"helm.sh/helm/internal/experimental/registry"
)
// ChartRemove performs a chart remove operation.

@ -19,8 +19,8 @@ package action
import (
"io"
"helm.sh/helm/internal/experimental/registry"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/registry"
)
// ChartSave performs a chart save operation.

@ -20,7 +20,7 @@ import (
"io/ioutil"
"testing"
"helm.sh/helm/pkg/registry"
"helm.sh/helm/internal/experimental/registry"
)
func chartSaveAction(t *testing.T) *ChartSave {

@ -0,0 +1,20 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*Package gates provides a general tool for working with experimental feature gates.
This provides convenience methods where the user can determine if certain experimental features are enabled.
*/
package gates

@ -0,0 +1,38 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gates
import (
"fmt"
"os"
)
// Gate is the name of the feature gate.
type Gate string
// String returns the string representation of this feature gate.
func (g Gate) String() string {
return string(g)
}
// IsEnabled determines whether a certain feature gate is enabled.
func (g Gate) IsEnabled() bool {
return os.Getenv(string(g)) != ""
}
func (g Gate) Error() error {
return fmt.Errorf("this feature has been marked as experimental and is not enabled by default. Please set $%s in your environment to use this feature", g.String())
}

@ -0,0 +1,47 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gates
import (
"os"
"testing"
)
const name string = "HELM_EXPERIMENTAL_FEATURE"
func TestIsEnabled(t *testing.T) {
os.Unsetenv(name)
g := Gate(name)
if g.IsEnabled() {
t.Errorf("feature gate shows as available, but the environment variable $%s was not set", name)
}
os.Setenv(name, "1")
if !g.IsEnabled() {
t.Errorf("feature gate shows as disabled, but the environment variable $%s was set", name)
}
}
func TestError(t *testing.T) {
os.Unsetenv(name)
g := Gate(name)
if g.Error().Error() != "this feature has been marked as experimental and is not enabled by default. Please set $HELM_EXPERIMENTAL_FEATURE in your environment to use this feature" {
t.Errorf("incorrect error message. Received %s", g.Error().Error())
}
}
Loading…
Cancel
Save