Skip to content

Commit 7d089f6

Browse files
danrowdennotnmeyer
andauthored
feat: Add --prop for contact properties (#50)
Co-authored-by: Nate Meyer <672246+notnmeyer@users.noreply.github.com>
1 parent 05b38c9 commit 7d089f6

4 files changed

Lines changed: 63 additions & 11 deletions

File tree

cmd/contacts.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func addContactFieldFlags(cmd *cobra.Command) {
2727
cmd.Flags().StringP("subscribed", "s", "", `Subscribed status ("true" or "false")`)
2828
cmd.Flags().String("user-group", "", "User group")
2929
cmd.Flags().StringArray("list", nil, "Mailing list subscription as id=true|false (repeatable)")
30+
cmd.Flags().StringArray("prop", nil, "Contact property as KEY=value (repeatable)")
3031
cmd.Flags().String("contact-props", "", "Path to a JSON file of contact properties")
3132
}
3233

@@ -70,6 +71,12 @@ func contactFieldParamsFromCmd(cmd *cobra.Command) (contactFieldParams, error) {
7071
}
7172
params.ContactProperties = contactProps
7273
}
74+
propPairs, _ := cmd.Flags().GetStringArray("prop")
75+
props, err := cmdutil.ParseKeyValuePairs("prop", propPairs, params.ContactProperties)
76+
if err != nil {
77+
return params, err
78+
}
79+
params.ContactProperties = props
7380

7481
return params, nil
7582
}

cmd/contacts_create_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,37 @@ func TestContactFieldParamsFromCmd(t *testing.T) {
110110
}
111111
})
112112

113+
t.Run("valid --prop", func(t *testing.T) {
114+
cmd := newFieldCmd(t)
115+
cmd.Flags().Set("prop", "plan=pro")
116+
cmd.Flags().Set("prop", "score=42")
117+
params, err := contactFieldParamsFromCmd(cmd)
118+
if err != nil {
119+
t.Fatalf("unexpected error: %v", err)
120+
}
121+
if params.ContactProperties["plan"] != "pro" || params.ContactProperties["score"] != "42" {
122+
t.Errorf("unexpected contact properties: %v", params.ContactProperties)
123+
}
124+
})
125+
126+
t.Run("prop overrides contact-props file", func(t *testing.T) {
127+
f := filepath.Join(t.TempDir(), "props.json")
128+
os.WriteFile(f, []byte(`{"plan":"starter","region":"us"}`), 0644)
129+
cmd := newFieldCmd(t)
130+
cmd.Flags().Set("contact-props", f)
131+
cmd.Flags().Set("prop", "plan=pro")
132+
params, err := contactFieldParamsFromCmd(cmd)
133+
if err != nil {
134+
t.Fatalf("unexpected error: %v", err)
135+
}
136+
if params.ContactProperties["plan"] != "pro" {
137+
t.Errorf("expected plan=pro, got %v", params.ContactProperties["plan"])
138+
}
139+
if params.ContactProperties["region"] != "us" {
140+
t.Errorf("expected region=us, got %v", params.ContactProperties["region"])
141+
}
142+
})
143+
113144
t.Run("nonexistent --contact-props returns error", func(t *testing.T) {
114145
cmd := newFieldCmd(t)
115146
cmd.Flags().Set("contact-props", "/nonexistent/path.json")
@@ -118,6 +149,15 @@ func TestContactFieldParamsFromCmd(t *testing.T) {
118149
t.Fatal("expected error, got nil")
119150
}
120151
})
152+
153+
t.Run("invalid --prop returns error", func(t *testing.T) {
154+
cmd := newFieldCmd(t)
155+
cmd.Flags().Set("prop", "missingequals")
156+
_, err := contactFieldParamsFromCmd(cmd)
157+
if err == nil {
158+
t.Fatal("expected error, got nil")
159+
}
160+
})
121161
}
122162

123163
func TestRunContactsCreate(t *testing.T) {

cmd/transactional.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,7 @@ func parseDataVars(vars []string, jsonFile string) (map[string]any, error) {
2323
return nil, err
2424
}
2525
}
26-
for _, pair := range vars {
27-
idx := strings.IndexByte(pair, '=')
28-
if idx < 0 {
29-
return nil, fmt.Errorf("--var %q: expected KEY=value", pair)
30-
}
31-
if m == nil {
32-
m = make(map[string]any)
33-
}
34-
m[pair[:idx]] = pair[idx+1:]
35-
}
36-
return m, nil
26+
return cmdutil.ParseKeyValuePairs("var", vars, m)
3727
}
3828

3929
func attachmentFromPath(path string) (api.Attachment, error) {

internal/cmdutil/parse.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,23 @@ import (
44
"encoding/json"
55
"fmt"
66
"os"
7+
"strings"
78
)
89

10+
func ParseKeyValuePairs(flag string, pairs []string, dst map[string]any) (map[string]any, error) {
11+
for _, pair := range pairs {
12+
idx := strings.IndexByte(pair, '=')
13+
if idx < 0 {
14+
return nil, fmt.Errorf("--%s %q: expected KEY=value", flag, pair)
15+
}
16+
if dst == nil {
17+
dst = make(map[string]any)
18+
}
19+
dst[pair[:idx]] = pair[idx+1:]
20+
}
21+
return dst, nil
22+
}
23+
924
func ParseJSONFile(flag, path string) (map[string]any, error) {
1025
data, err := os.ReadFile(path)
1126
if err != nil {

0 commit comments

Comments
 (0)