Skip to content

Commit dbdfff8

Browse files
Merge pull request #199 from hdresearch/fix/persist-org-name
feat(auth): persist org_name and org_id from login/signup
2 parents 1ffdd37 + a93d6a9 commit dbdfff8

4 files changed

Lines changed: 110 additions & 1 deletion

File tree

cmd/login.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func loginWithGit() error {
188188
return err
189189
}
190190

191-
if err := auth.SaveAPIKey(keyResp.APIKey); err != nil {
191+
if err := auth.SaveAuth(keyResp.APIKey, keyResp.OrgName, keyResp.OrgID); err != nil {
192192
return fmt.Errorf("error saving API key: %w", err)
193193
}
194194

cmd/signup.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ func signupWithGit() error {
146146
config.APIKey = keyResp.APIKey
147147
config.Email = email
148148
config.SSHKeyPath = sshKeyPath
149+
config.OrgName = keyResp.OrgName
150+
config.OrgID = keyResp.OrgID
149151
if err := auth.SaveConfig(config); err != nil {
150152
return fmt.Errorf("error saving config: %w", err)
151153
}

internal/auth/auth.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ type Config struct {
1818
APIKey string `json:"apiKey"`
1919
Email string `json:"email,omitempty"`
2020
SSHKeyPath string `json:"sshKeyPath,omitempty"`
21+
// OrgName is the user's organization name (namespace).
22+
// Persisted from the login/signup API response so that callers can
23+
// compose canonical references (e.g. <org>/<repo>:<tag>) without
24+
// an extra API round-trip.
25+
OrgName string `json:"orgName,omitempty"`
26+
// OrgID is the user's organization UUID, persisted alongside OrgName.
27+
OrgID string `json:"orgID,omitempty"`
2128
}
2229

2330
// GetConfigPath returns the path to the .versrc file in the user's home directory
@@ -105,6 +112,38 @@ func SaveAPIKey(apiKey string) error {
105112
return SaveConfig(config)
106113
}
107114

115+
// SaveAuth persists the API key plus org identity to the config file in a
116+
// single write. Use this from the login/signup paths so that subsequent
117+
// commands can read the user's org name without an extra API call.
118+
func SaveAuth(apiKey, orgName, orgID string) error {
119+
config, err := LoadConfig()
120+
if err != nil {
121+
return err
122+
}
123+
124+
config.APIKey = apiKey
125+
if orgName != "" {
126+
config.OrgName = orgName
127+
}
128+
if orgID != "" {
129+
config.OrgID = orgID
130+
}
131+
return SaveConfig(config)
132+
}
133+
134+
// GetOrgName returns the user's org name, preferring the VERS_ORG env var
135+
// over the persisted config value. Empty string if neither is set.
136+
func GetOrgName() (string, error) {
137+
if orgName := os.Getenv("VERS_ORG"); orgName != "" {
138+
return orgName, nil
139+
}
140+
config, err := LoadConfig()
141+
if err != nil {
142+
return "", err
143+
}
144+
return config.OrgName, nil
145+
}
146+
108147
// HasAPIKey checks if an API key is present in environment variable or config file
109148
func HasAPIKey() (bool, error) {
110149
// First check environment variable

internal/auth/auth_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,71 @@ func TestGetVMDomain(t *testing.T) {
3333
})
3434
}
3535
}
36+
37+
func TestGetOrgName(t *testing.T) {
38+
// Save and restore HOME / VERS_ORG so this test is hermetic.
39+
origHome := os.Getenv("HOME")
40+
origOrg := os.Getenv("VERS_ORG")
41+
t.Cleanup(func() {
42+
os.Setenv("HOME", origHome)
43+
if origOrg == "" {
44+
os.Unsetenv("VERS_ORG")
45+
} else {
46+
os.Setenv("VERS_ORG", origOrg)
47+
}
48+
})
49+
50+
tmp := t.TempDir()
51+
os.Setenv("HOME", tmp)
52+
os.Unsetenv("VERS_ORG")
53+
54+
// 1. No config file, no env var → empty.
55+
got, err := GetOrgName()
56+
if err != nil {
57+
t.Fatalf("GetOrgName with no config: %v", err)
58+
}
59+
if got != "" {
60+
t.Errorf("expected empty, got %q", got)
61+
}
62+
63+
// 2. Persist via SaveAuth, read back.
64+
if err := SaveAuth("test-key", "acme", "org-uuid-1"); err != nil {
65+
t.Fatalf("SaveAuth: %v", err)
66+
}
67+
got, err = GetOrgName()
68+
if err != nil {
69+
t.Fatalf("GetOrgName after SaveAuth: %v", err)
70+
}
71+
if got != "acme" {
72+
t.Errorf("expected acme, got %q", got)
73+
}
74+
75+
// 3. Env var wins over persisted value.
76+
os.Setenv("VERS_ORG", "override-org")
77+
got, err = GetOrgName()
78+
if err != nil {
79+
t.Fatalf("GetOrgName with env override: %v", err)
80+
}
81+
if got != "override-org" {
82+
t.Errorf("expected override-org, got %q", got)
83+
}
84+
85+
// 4. Empty SaveAuth values don't clobber persisted ones.
86+
os.Unsetenv("VERS_ORG")
87+
if err := SaveAuth("new-key", "", ""); err != nil {
88+
t.Fatalf("SaveAuth empty org: %v", err)
89+
}
90+
cfg, err := LoadConfig()
91+
if err != nil {
92+
t.Fatalf("LoadConfig: %v", err)
93+
}
94+
if cfg.APIKey != "new-key" {
95+
t.Errorf("expected new-key, got %q", cfg.APIKey)
96+
}
97+
if cfg.OrgName != "acme" {
98+
t.Errorf("expected acme preserved, got %q", cfg.OrgName)
99+
}
100+
if cfg.OrgID != "org-uuid-1" {
101+
t.Errorf("expected org-uuid-1 preserved, got %q", cfg.OrgID)
102+
}
103+
}

0 commit comments

Comments
 (0)