Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ endif
all: gen build test

gen:
go tool gen-commands -input ./temporalcloudcli/commands.yml -pkg temporalcloudcli > ./temporalcloudcli/commands.gen.go
gen-commands -input ./temporalcloudcli/commands.yml -pkg temporalcloudcli > ./temporalcloudcli/commands.gen.go

build:
go build ./cmd/temporal-cloud
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
github.com/temporalio/cli/cliext v0.0.0-20260107234359-aa925d353b8e
github.com/temporalio/cli/cliext v0.0.0-20260112210410-f2d230be226c
github.com/temporalio/ui-server/v2 v2.42.1
go.temporal.io/api v1.59.0
go.temporal.io/cloud-sdk v0.6.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/temporalio/cli v1.5.2-0.20251212213638-36bff7182259 h1:HB3j4k3hgg9fINQhIOnR5PDlbrHeuVFLuExDIs5RlOk=
github.com/temporalio/cli v1.5.2-0.20251212213638-36bff7182259/go.mod h1:8lfULNGZ1Y2sobXSpY+2qQ4vgR4hYLuTLpqnCIl9Au4=
github.com/temporalio/cli/cliext v0.0.0-20260107234359-aa925d353b8e h1:Aud45gx+HInyiTidP6N+LmG7yaayY3QYWN7hJlocNJQ=
github.com/temporalio/cli/cliext v0.0.0-20260107234359-aa925d353b8e/go.mod h1:A9EHuWgszyY1o70CwnJXLkgqfoGKKHXjkKlpE2fj3Uc=
github.com/temporalio/cli/cliext v0.0.0-20260112210410-f2d230be226c h1:E+NxnXPj6XeDN8uUTI3veXYt7PVqfZOrOMh7kRkAEI4=
github.com/temporalio/cli/cliext v0.0.0-20260112210410-f2d230be226c/go.mod h1:A9EHuWgszyY1o70CwnJXLkgqfoGKKHXjkKlpE2fj3Uc=
github.com/temporalio/ui-server/v2 v2.42.1 h1:ajeOxqCnUiCRQQhQYLxaT7wUgF/slqZJtdW4pLjVqCs=
github.com/temporalio/ui-server/v2 v2.42.1/go.mod h1:lKTnn50t8yQvcrarxAOjX33YcfkomkiNB5BH06wQwEE=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
Expand Down
100 changes: 74 additions & 26 deletions temporalcloudcli/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,80 @@ import (
"context"
"errors"
"fmt"
"log/slog"

"github.com/temporalio/cli/cliext"
"go.temporal.io/cloud-sdk/cloudclient"
"go.temporal.io/sdk/contrib/envconfig"
"go.temporal.io/sdk/log"
)

func (c *CloudCommand) GetAPIKey(ctx context.Context) (string, error) {
loadClientOauthRes, err := cliext.LoadClientOAuth(cliext.LoadClientOAuthOptions{})
type CloudOptions struct {
ApiKey string
Server string
cliext.CommonOptions
Logger log.Logger
}

type CloudOptionsBuilder struct {
// CommonOptions contains common CLI options including profile config.
CommonOptions cliext.CommonOptions
// ClientOptions contains the client configuration from flags.
ClientOptions ClientOptions
// EnvLookup is the environment variable lookup function.
// If nil, environment variables are not used for profile loading.
EnvLookup envconfig.EnvLookup
// Logger is the slog logger to use for the client. If set, it will be
// wrapped with the SDK's structured logger adapter.
Logger *slog.Logger
}

func (b *CloudOptionsBuilder) Build(ctx context.Context) (*CloudOptions, error) {
cfg := b.ClientOptions
common := b.CommonOptions

// Load a client config profile if configured
var profile envconfig.ClientConfigProfile
if !common.DisableConfigFile || !common.DisableConfigEnv {
var err error
profile, err = envconfig.LoadClientConfigProfile(envconfig.LoadClientConfigProfileOptions{
ConfigFilePath: common.ConfigFile,
ConfigFileProfile: common.Profile,
DisableFile: common.DisableConfigFile,
DisableEnv: common.DisableConfigEnv,
EnvLookup: b.EnvLookup,
})
if err != nil {
return nil, fmt.Errorf("failed loading client config: %w", err)
}
}

cloudOpts := &CloudOptions{}

// Set logger if provided.
if b.Logger != nil {
cloudOpts.Logger = log.NewStructuredLogger(b.Logger)
}

// Set API key on profile if provided
if cfg.ApiKey != "" {
cloudOpts.ApiKey = cfg.ApiKey
} else if profile.APIKey != "" {
cloudOpts.ApiKey = profile.APIKey
}

if cfg.Server != "" {
cloudOpts.Server = cfg.Server
}

return cloudOpts, nil
}

func (c *CloudOptions) GetAPIKey(ctx context.Context) (string, error) {
loadClientOauthRes, err := cliext.LoadClientOAuth(cliext.LoadClientOAuthOptions{
ConfigFilePath: c.ConfigFile,
ProfileName: c.Profile,
EnvLookup: envconfig.EnvLookupOS,
})
if err != nil {
return "", fmt.Errorf("failed to load login configuration: %w, please run `temporal cloud login --reset`", err)
}
Expand All @@ -30,32 +97,13 @@ func (c *CloudCommand) GetAPIKey(ctx context.Context) (string, error) {
if refreshed {
loadClientOauthRes.OAuth.Token = token
if err := cliext.StoreClientOAuth(cliext.StoreClientOAuthOptions{
OAuth: loadClientOauthRes.OAuth,
OAuth: loadClientOauthRes.OAuth,
ConfigFilePath: c.ConfigFile,
ProfileName: c.Profile,
EnvLookup: envconfig.EnvLookupOS,
}); err != nil {
return "", fmt.Errorf("failed to write config file: %w", err)
}
}
return token.AccessToken, nil
}

func newCloudClient(cctx *CommandContext) (*cloudclient.Client, error) {
opts := cloudclient.Options{
UserAgent: fmt.Sprintf("temporalio-cloud-cli/%s", VersionString()),
}
if cctx.RootCommand.Server != "" {
opts.HostPort = cctx.RootCommand.Server
}
if cctx.RootCommand.ApiKey != "" {
// an explicit api key was provided, use it
opts.APIKey = cctx.RootCommand.ApiKey
} else {
// fallaback to the oauth based sso token provider
opts.APIKeyReader = cctx.RootCommand
}

cloudClient, err := cloudclient.New(opts)
if err != nil {
return nil, err
}
return cloudClient, nil
}
Loading