2018-05-14 12:23:21 -04:00
/ *
2018-08-24 15:03:55 -04:00
Copyright The Helm Authors .
2018-05-14 12:23:21 -04:00
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 .
* /
2025-02-24 10:11:54 -05:00
package cmd // import "helm.sh/helm/v4/pkg/cmd"
2018-05-14 12:23:21 -04:00
import (
2020-04-13 11:40:38 -04:00
"context"
2019-10-10 15:49:18 -04:00
"fmt"
2018-05-14 12:23:21 -04:00
"io"
2020-04-11 14:06:56 -04:00
"log"
2025-04-10 09:06:03 -04:00
"log/slog"
2024-02-05 08:54:21 -05:00
"net/http"
2020-10-19 16:37:32 -04:00
"os"
2019-10-10 15:49:18 -04:00
"strings"
2018-05-14 12:23:21 -04:00
2025-07-11 15:52:40 -04:00
"github.com/fatih/color"
2018-05-14 12:23:21 -04:00
"github.com/spf13/cobra"
2025-03-03 12:26:21 -05:00
"sigs.k8s.io/yaml"
2018-05-14 12:23:21 -04:00
2019-12-31 08:54:20 -05:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020-02-14 21:03:26 -05:00
"k8s.io/client-go/tools/clientcmd"
2019-12-31 08:54:20 -05:00
2025-04-10 10:01:12 -04:00
"helm.sh/helm/v4/internal/logging"
2024-12-26 16:33:51 -05:00
"helm.sh/helm/v4/internal/tlsutil"
"helm.sh/helm/v4/pkg/action"
2025-02-24 10:11:54 -05:00
"helm.sh/helm/v4/pkg/cli"
2025-03-03 12:26:21 -05:00
kubefake "helm.sh/helm/v4/pkg/kube/fake"
2024-12-26 16:33:51 -05:00
"helm.sh/helm/v4/pkg/registry"
2025-10-08 17:57:55 -04:00
ri "helm.sh/helm/v4/pkg/release"
2025-03-03 12:26:21 -05:00
release "helm.sh/helm/v4/pkg/release/v1"
2025-08-31 09:04:48 -04:00
"helm.sh/helm/v4/pkg/repo/v1"
2025-03-03 12:26:21 -05:00
"helm.sh/helm/v4/pkg/storage/driver"
2018-05-14 12:23:21 -04:00
)
var globalUsage = ` The Kubernetes package manager
2019-08-27 17:04:19 -04:00
Common actions for Helm :
2018-05-14 12:23:21 -04:00
- helm search : search for charts
2019-10-28 16:28:36 -04:00
- helm pull : download a chart to your local directory to view
2018-05-14 12:23:21 -04:00
- helm install : upload the chart to Kubernetes
- helm list : list releases of charts
2019-10-28 16:28:36 -04:00
Environment variables :
2023-08-31 03:46:28 -04:00
| Name | Description |
| -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- |
| $ HELM_CACHE_HOME | set an alternative location for storing cached files . |
| $ HELM_CONFIG_HOME | set an alternative location for storing Helm configuration . |
| $ HELM_DATA_HOME | set an alternative location for storing Helm data . |
| $ HELM_DEBUG | indicate whether or not Helm is running in Debug mode |
| $ HELM_DRIVER | set the backend storage driver . Values are : configmap , secret , memory , sql . |
| $ HELM_DRIVER_SQL_CONNECTION_STRING | set the connection string the SQL storage driver should use . |
| $ HELM_MAX_HISTORY | set the maximum number of helm release history . |
| $ HELM_NAMESPACE | set the namespace used for the helm operations . |
| $ HELM_NO_PLUGINS | disable plugins . Set HELM_NO_PLUGINS = 1 to disable plugins . |
| $ HELM_PLUGINS | set the path to the plugins directory |
| $ HELM_REGISTRY_CONFIG | set the path to the registry config file . |
| $ HELM_REPOSITORY_CACHE | set the path to the repository cache directory |
| $ HELM_REPOSITORY_CONFIG | set the path to the repositories file . |
| $ KUBECONFIG | set an alternative Kubernetes configuration file ( default "~/.kube/config" ) |
| $ HELM_KUBEAPISERVER | set the Kubernetes API Server Endpoint for authentication |
| $ HELM_KUBECAFILE | set the Kubernetes certificate authority file . |
| $ HELM_KUBEASGROUPS | set the Groups to use for impersonation using a comma - separated list . |
| $ HELM_KUBEASUSER | set the Username to impersonate for the operation . |
| $ HELM_KUBECONTEXT | set the name of the kubeconfig context . |
| $ HELM_KUBETOKEN | set the Bearer KubeToken used for authentication . |
| $ HELM_KUBEINSECURE_SKIP_TLS_VERIFY | indicate if the Kubernetes API server ' s certificate validation should be skipped ( insecure ) |
| $ HELM_KUBETLS_SERVER_NAME | set the server name used to validate the Kubernetes API server certificate |
| $ HELM_BURST_LIMIT | set the default burst limit in the case the server contains many CRDs ( default 100 , - 1 to disable ) |
| $ HELM_QPS | set the Queries Per Second in cases where a high number of calls exceed the option for higher burst values |
2025-07-11 16:08:32 -04:00
| $ HELM_COLOR | set color output mode . Allowed values : never , always , auto ( default : never ) |
2025-07-11 15:52:40 -04:00
| $ NO_COLOR | set to any non - empty value to disable all colored output ( overrides $ HELM_COLOR ) |
2019-08-30 14:29:28 -04:00
2020-04-23 14:50:31 -04:00
Helm stores cache , configuration , and data based on the following configuration order :
2019-08-30 14:29:28 -04:00
2020-04-23 14:50:31 -04:00
- If a HELM_ * _HOME environment variable is set , it will be used
- Otherwise , on systems supporting the XDG base directory specification , the XDG variables will be used
- When no other location is set a default location will be used based on the operating system
2019-08-30 14:29:28 -04:00
By default , the default directories depend on the Operating System . The defaults are listed below :
| Operating System | Cache Path | Configuration Path | Data Path |
2020-04-29 03:14:22 -04:00
| -- -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- -- -- -- -- -- - | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- -- -- -- -- - |
2019-08-30 14:29:28 -04:00
| Linux | $ HOME / . cache / helm | $ HOME / . config / helm | $ HOME / . local / share / helm |
| macOS | $ HOME / Library / Caches / helm | $ HOME / Library / Preferences / helm | $ HOME / Library / helm |
| Windows | % TEMP % \ helm | % APPDATA % \ helm | % APPDATA % \ helm |
2018-05-14 12:23:21 -04:00
`
2025-02-24 10:11:54 -05:00
var settings = cli . New ( )
2025-07-01 15:04:30 -04:00
func NewRootCmd ( out io . Writer , args [ ] string , logSetup func ( bool ) ) ( * cobra . Command , error ) {
2025-10-21 17:48:51 -04:00
actionConfig := action . NewConfiguration ( )
2025-07-01 15:04:30 -04:00
cmd , err := newRootCmdWithConfig ( actionConfig , out , args , logSetup )
2025-03-03 13:43:03 -05:00
if err != nil {
return nil , err
}
cobra . OnInitialize ( func ( ) {
helmDriver := os . Getenv ( "HELM_DRIVER" )
2025-04-10 09:06:03 -04:00
if err := actionConfig . Init ( settings . RESTClientGetter ( ) , settings . Namespace ( ) , helmDriver ) ; err != nil {
2025-03-03 13:43:03 -05:00
log . Fatal ( err )
}
if helmDriver == "memory" {
loadReleasesInMemory ( actionConfig )
}
actionConfig . SetHookOutputFunc ( hookOutputWriter )
} )
return cmd , nil
}
2025-07-01 15:04:30 -04:00
// SetupLogging sets up Helm logging used by the Helm client.
// This function is passed to the NewRootCmd function to enable logging. Any other
// application that uses the NewRootCmd function to setup all the Helm commands may
// use this function to setup logging or their own. Using a custom logging setup function
// enables applications using Helm commands to integrate with their existing logging
// system.
// The debug argument is the value if Helm is set for debugging (i.e. --debug flag)
func SetupLogging ( debug bool ) {
logger := logging . NewLogger ( func ( ) bool { return debug } )
slog . SetDefault ( logger )
}
2025-07-11 15:52:40 -04:00
// configureColorOutput configures the color output based on the ColorMode setting
func configureColorOutput ( settings * cli . EnvSettings ) {
switch settings . ColorMode {
case "never" :
color . NoColor = true
case "always" :
color . NoColor = false
case "auto" :
// Let fatih/color handle automatic detection
// It will check if output is a terminal and NO_COLOR env var
// We don't need to do anything here
}
}
2025-07-01 15:04:30 -04:00
func newRootCmdWithConfig ( actionConfig * action . Configuration , out io . Writer , args [ ] string , logSetup func ( bool ) ) ( * cobra . Command , error ) {
2018-05-14 12:23:21 -04:00
cmd := & cobra . Command {
2020-04-11 14:06:56 -04:00
Use : "helm" ,
Short : "The Helm package manager for Kubernetes." ,
Long : globalUsage ,
SilenceUsage : true ,
2024-12-11 10:20:45 -05:00
PersistentPreRun : func ( _ * cobra . Command , _ [ ] string ) {
2024-12-11 10:17:30 -05:00
if err := startProfiling ( ) ; err != nil {
2024-11-25 06:20:22 -05:00
log . Printf ( "Warning: Failed to start profiling: %v" , err )
}
} ,
2024-12-11 10:20:45 -05:00
PersistentPostRun : func ( _ * cobra . Command , _ [ ] string ) {
2024-12-11 10:17:30 -05:00
if err := stopProfiling ( ) ; err != nil {
2024-11-25 06:20:22 -05:00
log . Printf ( "Warning: Failed to stop profiling: %v" , err )
}
} ,
2018-05-14 12:23:21 -04:00
}
2025-03-03 12:26:21 -05:00
2018-05-14 12:23:21 -04:00
flags := cmd . PersistentFlags ( )
settings . AddFlags ( flags )
2020-05-06 16:43:17 -04:00
addKlogFlags ( flags )
2018-05-14 12:23:21 -04:00
2025-07-01 15:04:30 -04:00
// We can safely ignore any errors that flags.Parse encounters since
// those errors will be caught later during the call to cmd.Execution.
// This call is required to gather configuration information prior to
// execution.
2025-09-10 15:26:02 -04:00
flags . ParseErrorsAllowlist . UnknownFlags = true
2025-07-01 15:04:30 -04:00
flags . Parse ( args )
logSetup ( settings . Debug )
2025-07-11 16:19:16 -04:00
2025-11-21 17:45:22 -05:00
// newRootCmdWithConfig is only called from NewRootCmd. NewRootCmd sets up
// NewConfiguration without a custom logger. So, the slog default is used. logSetup
// can change the default logger to the one in the logger package. This happens for
// the Helm client. This means the actionConfig logger is different from the slog
// default logger. If they are different we sync the actionConfig logger to the slog
// current default one.
if actionConfig . Logger ( ) != slog . Default ( ) {
actionConfig . SetLogger ( slog . Default ( ) . Handler ( ) )
}
2025-07-11 15:52:40 -04:00
// Validate color mode setting
switch settings . ColorMode {
case "never" , "auto" , "always" :
// Valid color mode
default :
return nil , fmt . Errorf ( "invalid color mode %q: must be one of: never, auto, always" , settings . ColorMode )
}
2025-07-11 16:19:16 -04:00
2025-07-11 15:52:40 -04:00
// Configure color output based on ColorMode setting
configureColorOutput ( settings )
// Setup shell completion for the color flag
_ = cmd . RegisterFlagCompletionFunc ( "color" , func ( _ * cobra . Command , _ [ ] string , _ string ) ( [ ] string , cobra . ShellCompDirective ) {
return [ ] string { "never" , "auto" , "always" } , cobra . ShellCompDirectiveNoFileComp
} )
2025-07-11 16:19:16 -04:00
2025-07-11 15:52:40 -04:00
// Setup shell completion for the colour flag
_ = cmd . RegisterFlagCompletionFunc ( "colour" , func ( _ * cobra . Command , _ [ ] string , _ string ) ( [ ] string , cobra . ShellCompDirective ) {
return [ ] string { "never" , "auto" , "always" } , cobra . ShellCompDirectiveNoFileComp
} )
2025-04-10 09:06:03 -04:00
2019-12-31 08:54:20 -05:00
// Setup shell completion for the namespace flag
2024-03-11 17:13:34 -04:00
err := cmd . RegisterFlagCompletionFunc ( "namespace" , func ( _ * cobra . Command , _ [ ] string , _ string ) ( [ ] string , cobra . ShellCompDirective ) {
2019-12-31 08:54:20 -05:00
if client , err := actionConfig . KubernetesClientSet ( ) ; err == nil {
2021-03-15 21:11:57 -04:00
// Choose a long enough timeout that the user notices something is not working
2019-12-31 08:54:20 -05:00
// but short enough that the user is not made to wait very long
to := int64 ( 3 )
2020-04-11 14:06:56 -04:00
cobra . CompDebugln ( fmt . Sprintf ( "About to call kube client for namespaces with timeout of: %d" , to ) , settings . Debug )
2019-12-31 08:54:20 -05:00
nsNames := [ ] string { }
2020-04-13 11:40:38 -04:00
if namespaces , err := client . CoreV1 ( ) . Namespaces ( ) . List ( context . Background ( ) , metav1 . ListOptions { TimeoutSeconds : & to } ) ; err == nil {
2019-12-31 08:54:20 -05:00
for _ , ns := range namespaces . Items {
2021-12-31 10:49:49 -05:00
nsNames = append ( nsNames , ns . Name )
2019-12-31 08:54:20 -05:00
}
2020-04-11 14:06:56 -04:00
return nsNames , cobra . ShellCompDirectiveNoFileComp
2019-12-31 08:54:20 -05:00
}
}
2020-04-11 14:06:56 -04:00
return nil , cobra . ShellCompDirectiveDefault
2019-12-31 08:54:20 -05:00
} )
2020-04-11 14:06:56 -04:00
if err != nil {
log . Fatal ( err )
}
2020-02-14 21:03:26 -05:00
// Setup shell completion for the kube-context flag
2024-03-11 17:13:34 -04:00
err = cmd . RegisterFlagCompletionFunc ( "kube-context" , func ( _ * cobra . Command , _ [ ] string , _ string ) ( [ ] string , cobra . ShellCompDirective ) {
2020-04-11 14:06:56 -04:00
cobra . CompDebugln ( "About to get the different kube-contexts" , settings . Debug )
2020-02-14 21:03:26 -05:00
loadingRules := clientcmd . NewDefaultClientConfigLoadingRules ( )
if len ( settings . KubeConfig ) > 0 {
loadingRules = & clientcmd . ClientConfigLoadingRules { ExplicitPath : settings . KubeConfig }
}
if config , err := clientcmd . NewNonInteractiveDeferredLoadingClientConfig (
loadingRules ,
& clientcmd . ConfigOverrides { } ) . RawConfig ( ) ; err == nil {
2020-08-27 21:39:40 -04:00
comps := [ ] string { }
for name , context := range config . Contexts {
2021-12-31 10:49:49 -05:00
comps = append ( comps , fmt . Sprintf ( "%s\t%s" , name , context . Cluster ) )
2020-02-14 21:03:26 -05:00
}
2020-08-27 21:39:40 -04:00
return comps , cobra . ShellCompDirectiveNoFileComp
2020-02-14 21:03:26 -05:00
}
2020-04-11 14:06:56 -04:00
return nil , cobra . ShellCompDirectiveNoFileComp
2020-02-14 21:03:26 -05:00
} )
2020-04-11 14:06:56 -04:00
if err != nil {
log . Fatal ( err )
}
2024-02-05 08:54:21 -05:00
registryClient , err := newDefaultRegistryClient ( false , "" , "" )
2020-10-01 17:37:44 -04:00
if err != nil {
return nil , err
}
actionConfig . RegistryClient = registryClient
2019-08-12 16:17:18 -04:00
// Add subcommands
2018-05-14 12:23:21 -04:00
cmd . AddCommand (
2020-05-17 21:25:19 -04:00
// chart commands
newCreateCmd ( out ) ,
2020-10-01 17:37:44 -04:00
newDependencyCmd ( actionConfig , out ) ,
newPullCmd ( actionConfig , out ) ,
2022-01-12 21:26:41 -05:00
newShowCmd ( actionConfig , out ) ,
2020-05-17 21:25:19 -04:00
newLintCmd ( out ) ,
2024-10-22 12:56:58 -04:00
newPackageCmd ( out ) ,
2020-05-17 21:25:19 -04:00
newRepoCmd ( out ) ,
newSearchCmd ( out ) ,
newVerifyCmd ( out ) ,
// release commands
newGetCmd ( actionConfig , out ) ,
newHistoryCmd ( actionConfig , out ) ,
newInstallCmd ( actionConfig , out ) ,
newListCmd ( actionConfig , out ) ,
newReleaseTestCmd ( actionConfig , out ) ,
newRollbackCmd ( actionConfig , out ) ,
newStatusCmd ( actionConfig , out ) ,
newTemplateCmd ( actionConfig , out ) ,
newUninstallCmd ( actionConfig , out ) ,
newUpgradeCmd ( actionConfig , out ) ,
2018-05-14 12:23:21 -04:00
newCompletionCmd ( out ) ,
2019-08-17 01:43:24 -04:00
newEnvCmd ( out ) ,
2018-05-14 12:23:21 -04:00
newPluginCmd ( out ) ,
newVersionCmd ( out ) ,
// Hidden documentation generator command: 'helm docs'
newDocsCmd ( out ) ,
)
2019-08-12 16:17:18 -04:00
cmd . AddCommand (
newRegistryCmd ( actionConfig , out ) ,
2021-06-08 01:45:40 -04:00
newPushCmd ( actionConfig , out ) ,
2019-08-12 16:17:18 -04:00
)
2025-08-22 16:12:49 -04:00
// Find and add CLI plugins
loadCLIPlugins ( cmd , out )
2018-05-14 12:23:21 -04:00
2020-10-19 16:37:32 -04:00
// Check for expired repositories
checkForExpiredRepos ( settings . RepositoryConfig )
2020-01-08 14:03:06 -05:00
return cmd , nil
2018-05-14 12:23:21 -04:00
}
2020-10-19 16:37:32 -04:00
2025-03-03 12:26:21 -05:00
// This function loads releases into the memory storage if the
// environment variable is properly set.
func loadReleasesInMemory ( actionConfig * action . Configuration ) {
filePaths := strings . Split ( os . Getenv ( "HELM_MEMORY_DRIVER_DATA" ) , ":" )
if len ( filePaths ) == 0 {
return
}
store := actionConfig . Releases
mem , ok := store . Driver . ( * driver . Memory )
if ! ok {
// For an unexpected reason we are not dealing with the memory storage driver.
return
}
actionConfig . KubeClient = & kubefake . PrintingKubeClient { Out : io . Discard }
for _ , path := range filePaths {
b , err := os . ReadFile ( path )
if err != nil {
log . Fatal ( "Unable to read memory driver data" , err )
}
releases := [ ] * release . Release { }
if err := yaml . Unmarshal ( b , & releases ) ; err != nil {
log . Fatal ( "Unable to unmarshal memory driver data: " , err )
}
for _ , rel := range releases {
if err := store . Create ( rel ) ; err != nil {
log . Fatal ( err )
}
}
}
// Must reset namespace to the proper one
mem . SetNamespace ( settings . Namespace ( ) )
}
// hookOutputWriter provides the writer for writing hook logs.
func hookOutputWriter ( _ , _ , _ string ) io . Writer {
return log . Writer ( )
}
2020-10-19 16:37:32 -04:00
func checkForExpiredRepos ( repofile string ) {
expiredRepos := [ ] struct {
name string
old string
new string
} {
{
name : "stable" ,
old : "kubernetes-charts.storage.googleapis.com" ,
new : "https://charts.helm.sh/stable" ,
} ,
{
name : "incubator" ,
old : "kubernetes-charts-incubator.storage.googleapis.com" ,
new : "https://charts.helm.sh/incubator" ,
} ,
}
// parse repo file.
2024-09-04 23:51:39 -04:00
// Ignore the error because it is okay for a repo file to be unparsable at this
2020-10-19 16:37:32 -04:00
// stage. Later checks will trap the error and respond accordingly.
repoFile , err := repo . LoadFile ( repofile )
if err != nil {
return
}
for _ , exp := range expiredRepos {
r := repoFile . Get ( exp . name )
if r == nil {
return
}
if url := r . URL ; strings . Contains ( url , exp . old ) {
fmt . Fprintf (
os . Stderr ,
2020-11-05 16:06:18 -05:00
"WARNING: %q is deprecated for %q and will be deleted Nov. 13, 2020.\nWARNING: You should switch to %q via:\nWARNING: helm repo add %q %q --force-update\n" ,
2020-10-19 16:37:32 -04:00
exp . old ,
exp . name ,
exp . new ,
2020-11-05 16:06:18 -05:00
exp . name ,
exp . new ,
2020-10-19 16:37:32 -04:00
)
}
}
}
2022-06-21 07:30:41 -04:00
2024-02-05 08:54:21 -05:00
func newRegistryClient (
2025-11-03 22:33:42 -05:00
certFile , keyFile , caFile string , insecureSkipTLSVerify , plainHTTP bool , username , password string ,
2024-02-05 08:54:21 -05:00
) ( * registry . Client , error ) {
2025-11-03 22:33:42 -05:00
if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSVerify {
registryClient , err := newRegistryClientWithTLS ( certFile , keyFile , caFile , insecureSkipTLSVerify , username , password )
2022-12-19 16:52:20 -05:00
if err != nil {
return nil , err
}
return registryClient , nil
}
2024-02-05 08:54:21 -05:00
registryClient , err := newDefaultRegistryClient ( plainHTTP , username , password )
2022-12-19 16:52:20 -05:00
if err != nil {
return nil , err
}
return registryClient , nil
}
2024-02-05 08:54:21 -05:00
func newDefaultRegistryClient ( plainHTTP bool , username , password string ) ( * registry . Client , error ) {
2023-06-07 02:24:02 -04:00
opts := [ ] registry . ClientOption {
2022-06-21 07:30:41 -04:00
registry . ClientOptDebug ( settings . Debug ) ,
registry . ClientOptEnableCache ( true ) ,
registry . ClientOptWriter ( os . Stderr ) ,
registry . ClientOptCredentialsFile ( settings . RegistryConfig ) ,
2024-02-05 08:54:21 -05:00
registry . ClientOptBasicAuth ( username , password ) ,
2023-06-07 02:24:02 -04:00
}
if plainHTTP {
opts = append ( opts , registry . ClientOptPlainHTTP ( ) )
}
// Create a new registry client
registryClient , err := registry . NewClient ( opts ... )
2022-06-21 07:30:41 -04:00
if err != nil {
return nil , err
}
return registryClient , nil
}
2022-12-19 16:52:20 -05:00
2024-02-05 08:54:21 -05:00
func newRegistryClientWithTLS (
2025-11-03 22:33:42 -05:00
certFile , keyFile , caFile string , insecureSkipTLSVerify bool , username , password string ,
2024-02-05 08:54:21 -05:00
) ( * registry . Client , error ) {
2024-12-15 00:24:30 -05:00
tlsConf , err := tlsutil . NewTLSConfig (
2025-11-03 22:33:42 -05:00
tlsutil . WithInsecureSkipVerify ( insecureSkipTLSVerify ) ,
2024-12-15 00:24:30 -05:00
tlsutil . WithCertKeyPairFiles ( certFile , keyFile ) ,
tlsutil . WithCAFile ( caFile ) ,
)
2024-02-05 08:54:21 -05:00
if err != nil {
return nil , fmt . Errorf ( "can't create TLS config for client: %w" , err )
}
2022-12-19 16:52:20 -05:00
// Create a new registry client
2024-02-05 08:54:21 -05:00
registryClient , err := registry . NewClient (
registry . ClientOptDebug ( settings . Debug ) ,
registry . ClientOptEnableCache ( true ) ,
registry . ClientOptWriter ( os . Stderr ) ,
registry . ClientOptCredentialsFile ( settings . RegistryConfig ) ,
registry . ClientOptHTTPClient ( & http . Client {
Transport : & http . Transport {
TLSClientConfig : tlsConf ,
2025-02-26 12:16:39 -05:00
Proxy : http . ProxyFromEnvironment ,
2024-02-05 08:54:21 -05:00
} ,
} ) ,
registry . ClientOptBasicAuth ( username , password ) ,
2022-12-19 16:52:20 -05:00
)
if err != nil {
return nil , err
}
return registryClient , nil
}
2025-08-22 18:06:09 -04:00
type CommandError struct {
error
ExitCode int
}
2025-10-08 17:57:55 -04:00
// releaserToV1Release is a helper function to convert a v1 release passed by interface
// into the type object.
func releaserToV1Release ( rel ri . Releaser ) ( * release . Release , error ) {
switch r := rel . ( type ) {
case release . Release :
return & r , nil
case * release . Release :
return r , nil
case nil :
return nil , nil
default :
return nil , fmt . Errorf ( "unsupported release type: %T" , rel )
}
}
func releaseListToV1List ( ls [ ] ri . Releaser ) ( [ ] * release . Release , error ) {
rls := make ( [ ] * release . Release , 0 , len ( ls ) )
for _ , val := range ls {
rel , err := releaserToV1Release ( val )
if err != nil {
return nil , err
}
rls = append ( rls , rel )
}
return rls , nil
}