diff --git a/internal/pkg/profile/loader.go b/internal/pkg/profile/loader.go index 881e6573..de44b897 100644 --- a/internal/pkg/profile/loader.go +++ b/internal/pkg/profile/loader.go @@ -175,6 +175,16 @@ func (l *Loader) LoadProfile(name string) (*Profile, error) { return nil, fmt.Errorf("profile path name does not match name in file. %q versus %q. Please rename file or name within the profile file to reconcile", name, c.Name) } + // Honor environment variables around org and project over whatever + // we load from the profile file. + if orgID, ok := os.LookupEnv(envVarHCPOrganizationID); ok && orgID != "" { + c.OrganizationID = orgID + } + + if projID, ok := os.LookupEnv(envVarHCPProjectID); ok && projID != "" { + c.ProjectID = projID + } + c.dir = l.profilesDir return &c, nil } @@ -218,8 +228,29 @@ func (l *Loader) DeleteProfile(name string) error { return nil } -// DefaultProfile returns the minimal default profile. +// These are pulled over from hcp-sdk-go. We honor the same env vars +// it does, but do it directly here. + +const ( + envVarHCPOrganizationID = "HCP_ORGANIZATION_ID" + envVarHCPProjectID = "HCP_PROJECT_ID" +) + +// DefaultProfile returns the minimal default profile. If environment +// variables related to organization and project are set, they are honored here. func (l *Loader) DefaultProfile() *Profile { + hcpOrganizationID, hcpOrganizationIDOK := os.LookupEnv(envVarHCPOrganizationID) + hcpProjectID, hcpProjectIDOK := os.LookupEnv(envVarHCPProjectID) + + if hcpOrganizationIDOK && hcpProjectIDOK { + return &Profile{ + Name: "default", + OrganizationID: hcpOrganizationID, + ProjectID: hcpProjectID, + dir: l.profilesDir, + } + } + return &Profile{ Name: "default", dir: l.profilesDir, diff --git a/internal/pkg/profile/loader_test.go b/internal/pkg/profile/loader_test.go index 269ae044..21b7e061 100644 --- a/internal/pkg/profile/loader_test.go +++ b/internal/pkg/profile/loader_test.go @@ -78,6 +78,7 @@ func TestLoader_GetActiveProfile(t *testing.T) { r.NoError(err) r.Equal(t.Name(), p.Name) }) + } func TestLoader_ListProfiles(t *testing.T) { @@ -208,6 +209,62 @@ project_id = "456"`, }) } +//nolint:paralleltest +func TestLoader_LoadProfileEnv(t *testing.T) { + + // These tests aren't parallel because they manipulate the environment + // and can't run concurrently. + + //nolint:paralleltest + t.Run("default profile, env set", func(t *testing.T) { + defer os.Unsetenv(envVarHCPOrganizationID) + defer os.Unsetenv(envVarHCPProjectID) + + os.Setenv(envVarHCPOrganizationID, "xyz") + os.Setenv(envVarHCPProjectID, "abc") + + r := require.New(t) + l, err := newLoader(t.TempDir()) + r.NoError(err) + prof := l.DefaultProfile() + + r.Equal("xyz", prof.OrganizationID) + r.Equal("abc", prof.ProjectID) + }) + + //nolint:paralleltest + t.Run("valid active profile, env set", func(t *testing.T) { + r := require.New(t) + l := TestLoader(t) + + defer os.Unsetenv(envVarHCPOrganizationID) + defer os.Unsetenv(envVarHCPProjectID) + + p, err := l.NewProfile("test") + r.NoError(err) + p.OrganizationID = "123" + p.ProjectID = "456" + r.NoError(p.Write()) + + os.Setenv(envVarHCPOrganizationID, "xyz") + + out, err := l.LoadProfile(p.Name) + r.NoError(err) + r.NotNil(out) + r.Equal("xyz", out.OrganizationID) + r.Equal(p.ProjectID, out.ProjectID) + + os.Setenv(envVarHCPProjectID, "abc") + + out, err = l.LoadProfile(p.Name) + r.NoError(err) + r.NotNil(out) + r.Equal("xyz", out.OrganizationID) + r.Equal("abc", out.ProjectID) + + }) +} + func TestLoader_LoadProfiles(t *testing.T) { t.Parallel()