Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions platform/buildkite/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,9 @@ func ParseState(raw string) State {
}

// DecodeMetadataEnv recovers a JSON-encoded map[string]string from env[key].
// Buildkite echoes env vars back on the build object, so a caller that seeded
// a JSON-encoded map at Trigger time can recover it here at Status time
// without any local state. Returns an empty non-nil map when the key is
// absent. When the value is present but cannot be decoded, returns a nil map
// and the decode error for the caller to log or act on as it sees fit.
// Returns a non-nil map on success, including when the value is absent,
// empty, or JSON null. A value that cannot be decoded returns a nil map
// and the decode error.
func DecodeMetadataEnv(env map[string]string, key string) (map[string]string, error) {
meta := make(map[string]string)
raw, ok := env[key]
Expand All @@ -222,5 +220,8 @@ func DecodeMetadataEnv(env map[string]string, key string) (map[string]string, er
if err := json.Unmarshal([]byte(raw), &meta); err != nil {
return nil, fmt.Errorf("decode metadata env %q: %w", key, err)
}
if meta == nil {
meta = make(map[string]string)
}
return meta, nil
}
26 changes: 21 additions & 5 deletions platform/buildkite/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,27 @@ func TestDecodeMetadataEnv_PresentAndValid(t *testing.T) {
assert.Equal(t, map[string]string{"requester": "alice", "ticket": "SQ-42"}, got)
}

func TestDecodeMetadataEnv_Absent_ReturnsEmptyMap(t *testing.T) {
got, err := DecodeMetadataEnv(map[string]string{}, "SQ_METADATA")
require.NoError(t, err)
assert.Empty(t, got)
assert.NotNil(t, got)
func TestDecodeMetadataEnv_Empty_ReturnsWritableMap(t *testing.T) {
tests := []struct {
name string
env map[string]string
}{
{"absent", nil},
{"empty string", map[string]string{"SQ_METADATA": ""}},
{"empty object", map[string]string{"SQ_METADATA": "{}"}},
{"null", map[string]string{"SQ_METADATA": "null"}},
{"null with whitespace", map[string]string{"SQ_METADATA": " \nnull\t"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := DecodeMetadataEnv(tt.env, "SQ_METADATA")
require.NoError(t, err)
require.NotNil(t, got)
assert.Empty(t, got)
got["url"] = "https://buildkite.com/test-org/my-pipeline/builds/42"
assert.Len(t, got, 1)
})
}
}

func TestDecodeMetadataEnv_Malformed_ReturnsError(t *testing.T) {
Expand Down