Skip to content

Commit c47084e

Browse files
committed
feat(be): add tag db for config fields
1 parent e1ae480 commit c47084e

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

util/config.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ type ConfigType struct {
328328
Debugging *DebuggingConfig `json:"debugging,omitempty"`
329329

330330
HA *HAConfig `json:"ha,omitempty"`
331+
332+
// SubscriptionKey is a subscription key or token that can be set via config.
333+
// When this is set, subscription activation from the web interface is disabled.
334+
SubscriptionKey string `json:"subscription_key,omitempty" db:"-" env:"SEMAPHORE_SUBSCRIPTION_KEY"`
331335
}
332336

333337
func NewConfigType() *ConfigType {
@@ -591,6 +595,13 @@ func assignMapToStructRecursive(m map[string]any, structValue reflect.Value) err
591595

592596
for i := 0; i < structType.NumField(); i++ {
593597
field := structType.Field(i)
598+
599+
// Skip fields with db:"-" tag
600+
dbTag := field.Tag.Get("db")
601+
if dbTag == "-" {
602+
continue
603+
}
604+
594605
jsonTag := field.Tag.Get("json")
595606
if jsonTag == "" {
596607
jsonTag = field.Name

util/config_assign_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,86 @@ func TestAssignMapToStruct_MapPrimitiveConversions(t *testing.T) {
162162
}
163163
}
164164

165+
func TestAssignMapToStruct_SkipsDbMinusTag(t *testing.T) {
166+
type Sample struct {
167+
Name string `json:"name"`
168+
Password string `json:"password" db:"-"`
169+
Age int `json:"age"`
170+
Secret string `json:"secret" db:"-"`
171+
}
172+
173+
t.Run("fields with db:- tag should not be assigned", func(t *testing.T) {
174+
s := Sample{
175+
Name: "original",
176+
Password: "original_password",
177+
Age: 25,
178+
Secret: "original_secret",
179+
}
180+
181+
m := map[string]any{
182+
"name": "updated",
183+
"password": "new_password",
184+
"age": 30,
185+
"secret": "new_secret",
186+
}
187+
188+
if err := AssignMapToStruct(m, &s); err != nil {
189+
t.Fatalf("unexpected error: %v", err)
190+
}
191+
192+
// Fields without db:"-" should be updated
193+
if s.Name != "updated" {
194+
t.Errorf("expected Name to be 'updated', got '%s'", s.Name)
195+
}
196+
if s.Age != 30 {
197+
t.Errorf("expected Age to be 30, got %d", s.Age)
198+
}
199+
200+
// Fields with db:"-" should retain original values
201+
if s.Password != "original_password" {
202+
t.Errorf("expected Password to remain 'original_password', got '%s'", s.Password)
203+
}
204+
if s.Secret != "original_secret" {
205+
t.Errorf("expected Secret to remain 'original_secret', got '%s'", s.Secret)
206+
}
207+
})
208+
209+
t.Run("nested struct with db:- tag fields", func(t *testing.T) {
210+
type Inner struct {
211+
Public string `json:"public"`
212+
Private string `json:"private" db:"-"`
213+
}
214+
type Outer struct {
215+
Inner Inner `json:"inner"`
216+
}
217+
218+
o := Outer{
219+
Inner: Inner{
220+
Public: "original_public",
221+
Private: "original_private",
222+
},
223+
}
224+
225+
m := map[string]any{
226+
"inner": map[string]any{
227+
"public": "updated_public",
228+
"private": "updated_private",
229+
},
230+
}
231+
232+
if err := AssignMapToStruct(m, &o); err != nil {
233+
t.Fatalf("unexpected error: %v", err)
234+
}
235+
236+
if o.Inner.Public != "updated_public" {
237+
t.Errorf("expected Inner.Public to be 'updated_public', got '%s'", o.Inner.Public)
238+
}
239+
if o.Inner.Private != "original_private" {
240+
t.Errorf("expected Inner.Private to remain 'original_private', got '%s'", o.Inner.Private)
241+
}
242+
})
243+
}
244+
165245
func TestSetConfigValue_SliceAndMap(t *testing.T) {
166246
// This ensures setConfigValue (used by defaults/env) is compatible with slice/map JSON
167247
type X struct {

0 commit comments

Comments
 (0)