mirror of https://github.com/databricks/cli.git
Include [DEFAULT] section header when writing ~/.databrickscfg (#464)
## Changes The ini library omits the default section header and in doing so breaks compatibility with Python's config parser. It raises: ``` Error: MissingSectionHeaderError: File contains no section headers. ``` This commit makes sure the DEFAULT section header is included. If the config file doesn't include a DEFAULT section itself, we include a comment describing its purpose. ## Tests New tests pass. Manually confirmed the DEFAULT section header is included. --------- Co-authored-by: PaulCornellDB <paul.cornell@databricks.com>
This commit is contained in:
parent
f219a0da5a
commit
a17876480a
|
@ -13,6 +13,8 @@ import (
|
|||
|
||||
const fileMode = 0o600
|
||||
|
||||
const defaultComment = "The profile defined in the DEFAULT section is to be used as a fallback when no profile is explicitly specified."
|
||||
|
||||
func loadOrCreateConfigFile(filename string) (*config.File, error) {
|
||||
if filename == "" {
|
||||
filename = "~/.databrickscfg"
|
||||
|
@ -104,6 +106,12 @@ func SaveToProfile(ctx context.Context, cfg *config.Config) error {
|
|||
key.SetValue(attr.GetString(cfg))
|
||||
}
|
||||
|
||||
// Add a comment to the default section if it's empty.
|
||||
section = configFile.Section(ini.DefaultSection)
|
||||
if len(section.Keys()) == 0 && section.Comment == "" {
|
||||
section.Comment = defaultComment
|
||||
}
|
||||
|
||||
orig, backupErr := os.ReadFile(configFile.Path())
|
||||
if len(orig) > 0 && backupErr == nil {
|
||||
log.Infof(ctx, "Backing up in %s.bak", configFile.Path())
|
||||
|
@ -120,3 +128,9 @@ func SaveToProfile(ctx context.Context, cfg *config.Config) error {
|
|||
}
|
||||
return configFile.SaveTo(configFile.Path())
|
||||
}
|
||||
|
||||
func init() {
|
||||
// We document databrickscfg files with a [DEFAULT] header and wish to keep it that way.
|
||||
// This, however, does mean we emit a [DEFAULT] section even if it's empty.
|
||||
ini.DefaultHeader = true
|
||||
}
|
||||
|
|
|
@ -2,11 +2,13 @@ package databrickscfg
|
|||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/databricks/databricks-sdk-go/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLoadOrCreate(t *testing.T) {
|
||||
|
@ -129,7 +131,7 @@ func TestSaveToProfile_ErrorOnMatch(t *testing.T) {
|
|||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestSaveToProfile_NewFile(t *testing.T) {
|
||||
func TestSaveToProfile_NewFileWithoutDefault(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
path := filepath.Join(t.TempDir(), "databrickscfg")
|
||||
|
||||
|
@ -141,6 +143,39 @@ func TestSaveToProfile_NewFile(t *testing.T) {
|
|||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NoFileExists(t, path+".bak")
|
||||
|
||||
contents, err := os.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t,
|
||||
`; The profile defined in the DEFAULT section is to be used as a fallback when no profile is explicitly specified.
|
||||
[DEFAULT]
|
||||
|
||||
[abc]
|
||||
host = https://foo
|
||||
token = xyz
|
||||
`, string(contents))
|
||||
}
|
||||
|
||||
func TestSaveToProfile_NewFileWithDefault(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
path := filepath.Join(t.TempDir(), "databrickscfg")
|
||||
|
||||
err := SaveToProfile(ctx, &config.Config{
|
||||
ConfigFile: path,
|
||||
Profile: "DEFAULT",
|
||||
Host: "https://foo",
|
||||
Token: "xyz",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NoFileExists(t, path+".bak")
|
||||
|
||||
contents, err := os.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t,
|
||||
`[DEFAULT]
|
||||
host = https://foo
|
||||
token = xyz
|
||||
`, string(contents))
|
||||
}
|
||||
|
||||
func TestSaveToProfile_ClearingPreviousProfile(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue