Skip to content

Commit 2231cdb

Browse files
committed
Extract config and profile helpers
1 parent 959f910 commit 2231cdb

File tree

8 files changed

+441
-101
lines changed

8 files changed

+441
-101
lines changed

cliext/config.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package cliext
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
8+
"go.temporal.io/sdk/contrib/envconfig"
9+
)
10+
11+
// LoadConfigOptions contains options for loading configuration.
12+
type LoadConfigOptions struct {
13+
// ConfigFilePath is the path to the configuration file.
14+
// If empty, TEMPORAL_CONFIG_FILE env var is checked, then the default path is used.
15+
ConfigFilePath string
16+
17+
// EnvLookup is used for environment variable lookups.
18+
// If nil, os.LookupEnv is used.
19+
EnvLookup EnvLookup
20+
}
21+
22+
// LoadConfigResult contains the result of loading configuration.
23+
type LoadConfigResult struct {
24+
// Config is the loaded configuration.
25+
Config *envconfig.ClientConfig
26+
27+
// ConfigFilePath is the resolved path to the configuration file that was loaded.
28+
// This may differ from the input if TEMPORAL_CONFIG_FILE env var was used.
29+
ConfigFilePath string
30+
}
31+
32+
// LoadConfig loads the client configuration from the specified file or default location.
33+
// If ConfigFilePath is empty, the TEMPORAL_CONFIG_FILE environment variable is checked.
34+
func LoadConfig(options LoadConfigOptions) (LoadConfigResult, error) {
35+
envLookup := options.EnvLookup
36+
if envLookup == nil {
37+
envLookup = EnvLookupOS
38+
}
39+
configFilePath := options.ConfigFilePath
40+
if configFilePath == "" {
41+
configFilePath, _ = envLookup.LookupEnv("TEMPORAL_CONFIG_FILE")
42+
}
43+
clientConfig, err := envconfig.LoadClientConfig(envconfig.LoadClientConfigOptions{
44+
ConfigFilePath: configFilePath,
45+
EnvLookup: envLookup,
46+
})
47+
if err != nil {
48+
return LoadConfigResult{}, err
49+
}
50+
return LoadConfigResult{
51+
Config: &clientConfig,
52+
ConfigFilePath: configFilePath,
53+
}, nil
54+
}
55+
56+
// WriteConfig writes the configuration to the specified file or default location.
57+
// If configFilePath is empty, the default path will be used.
58+
func WriteConfig(config *envconfig.ClientConfig, configFilePath string) error {
59+
// Get file
60+
if configFilePath == "" {
61+
var err error
62+
if configFilePath, err = envconfig.DefaultConfigFilePath(); err != nil {
63+
return err
64+
}
65+
}
66+
67+
// Convert to TOML
68+
b, err := config.ToTOML(envconfig.ClientConfigToTOMLOptions{})
69+
if err != nil {
70+
return fmt.Errorf("failed building TOML: %w", err)
71+
}
72+
73+
// Write to file, making dirs as needed
74+
if err := os.MkdirAll(filepath.Dir(configFilePath), 0700); err != nil {
75+
return fmt.Errorf("failed making config file parent dirs: %w", err)
76+
}
77+
if err := os.WriteFile(configFilePath, b, 0600); err != nil {
78+
return fmt.Errorf("failed writing config file: %w", err)
79+
}
80+
return nil
81+
}

cliext/env.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package cliext
2+
3+
import "os"
4+
5+
// EnvLookupOS is the default EnvLookup implementation.
6+
var EnvLookupOS EnvLookup = envLookupOS{}
7+
8+
type EnvLookup interface {
9+
LookupEnv(key string) (string, bool)
10+
Environ() []string
11+
}
12+
13+
type envLookupOS struct{}
14+
15+
func (envLookupOS) LookupEnv(key string) (string, bool) {
16+
return os.LookupEnv(key)
17+
}
18+
19+
func (envLookupOS) Environ() []string {
20+
return os.Environ()
21+
}

cliext/go.mod

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module github.com/temporalio/cli/cliext
2+
3+
go 1.25.0
4+
5+
require go.temporal.io/sdk/contrib/envconfig v0.1.0
6+
7+
require (
8+
github.com/BurntSushi/toml v1.4.0 // indirect
9+
github.com/davecgh/go-spew v1.1.1 // indirect
10+
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
11+
github.com/gogo/protobuf v1.3.2 // indirect
12+
github.com/golang/mock v1.6.0 // indirect
13+
github.com/google/uuid v1.6.0 // indirect
14+
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
15+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
16+
github.com/nexus-rpc/sdk-go v0.3.0 // indirect
17+
github.com/pborman/uuid v1.2.1 // indirect
18+
github.com/pmezard/go-difflib v1.0.0 // indirect
19+
github.com/robfig/cron v1.2.0 // indirect
20+
github.com/stretchr/objx v0.5.2 // indirect
21+
github.com/stretchr/testify v1.10.0 // indirect
22+
go.temporal.io/api v1.44.1 // indirect
23+
go.temporal.io/sdk v1.32.1 // indirect
24+
golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect
25+
golang.org/x/net v0.28.0 // indirect
26+
golang.org/x/sync v0.8.0 // indirect
27+
golang.org/x/sys v0.24.0 // indirect
28+
golang.org/x/text v0.17.0 // indirect
29+
golang.org/x/time v0.3.0 // indirect
30+
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
31+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
32+
google.golang.org/grpc v1.66.0 // indirect
33+
google.golang.org/protobuf v1.34.2 // indirect
34+
gopkg.in/yaml.v3 v3.0.1 // indirect
35+
)

cliext/go.sum

Lines changed: 183 additions & 0 deletions
Large diffs are not rendered by default.

cliext/profile.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package cliext
2+
3+
import (
4+
"fmt"
5+
6+
"go.temporal.io/sdk/contrib/envconfig"
7+
)
8+
9+
// LoadProfileOptions contains options for loading a profile.
10+
type LoadProfileOptions struct {
11+
// ConfigFilePath is the path to the configuration file.
12+
// If empty, TEMPORAL_CONFIG_FILE env var is checked, then the default path is used.
13+
ConfigFilePath string
14+
15+
// ProfileName is the name of the profile to load.
16+
// If empty, TEMPORAL_PROFILE env var is checked, then the default profile is used.
17+
ProfileName string
18+
19+
// CreateIfMissing creates an empty profile if it doesn't exist.
20+
CreateIfMissing bool
21+
22+
// EnvLookup is used for environment variable lookups.
23+
// If nil, os.LookupEnv is used.
24+
EnvLookup EnvLookup
25+
}
26+
27+
// LoadProfileResult contains the result of loading a profile.
28+
type LoadProfileResult struct {
29+
// Config is the loaded configuration.
30+
Config *envconfig.ClientConfig
31+
32+
// ConfigFilePath is the resolved path to the configuration file.
33+
ConfigFilePath string
34+
35+
// Profile is the loaded profile.
36+
Profile *envconfig.ClientConfigProfile
37+
38+
// ProfileName is the resolved profile name.
39+
ProfileName string
40+
}
41+
42+
// LoadProfile loads a specific profile from the configuration.
43+
func LoadProfile(opts LoadProfileOptions) (LoadProfileResult, error) {
44+
envLookup := opts.EnvLookup
45+
if envLookup == nil {
46+
envLookup = EnvLookupOS
47+
}
48+
49+
configResult, err := LoadConfig(LoadConfigOptions{
50+
ConfigFilePath: opts.ConfigFilePath,
51+
EnvLookup: envLookup,
52+
})
53+
if err != nil {
54+
return LoadProfileResult{}, err
55+
}
56+
57+
profileName := opts.ProfileName
58+
if profileName == "" {
59+
profileName, _ = envLookup.LookupEnv("TEMPORAL_PROFILE")
60+
}
61+
if profileName == "" {
62+
profileName = envconfig.DefaultConfigFileProfile
63+
}
64+
65+
profile := configResult.Config.Profiles[profileName]
66+
if profile == nil {
67+
if !opts.CreateIfMissing {
68+
return LoadProfileResult{}, fmt.Errorf("profile %q not found", profileName)
69+
}
70+
profile = &envconfig.ClientConfigProfile{}
71+
configResult.Config.Profiles[profileName] = profile
72+
}
73+
return LoadProfileResult{
74+
Config: configResult.Config,
75+
Profile: profile,
76+
ConfigFilePath: configResult.ConfigFilePath,
77+
ProfileName: profileName,
78+
}, nil
79+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ require (
1515
github.com/spf13/cobra v1.9.1
1616
github.com/spf13/pflag v1.0.6
1717
github.com/stretchr/testify v1.10.0
18+
github.com/temporalio/cli/cliext v0.0.0
1819
github.com/temporalio/ui-server/v2 v2.42.1
1920
go.temporal.io/api v1.53.0
2021
go.temporal.io/sdk v1.37.0
@@ -176,3 +177,5 @@ require (
176177
modernc.org/strutil v1.2.1 // indirect
177178
modernc.org/token v1.1.0 // indirect
178179
)
180+
181+
replace github.com/temporalio/cli/cliext => ./cliext

0 commit comments

Comments
 (0)