Skip to content

Commit

Permalink
Add cache settings block to pipeline.CommandStep (#33)
Browse files Browse the repository at this point in the history
* Add cache settings block to pipeline.CommandStep

* Update step_command_cache_test.go

Co-authored-by: Josh Deprez <[email protected]>

---------

Co-authored-by: Josh Deprez <[email protected]>
  • Loading branch information
moskyb and DrJosh9000 committed Apr 9, 2024
1 parent 44c3854 commit 1c8eae3
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 0 deletions.
1 change: 1 addition & 0 deletions step_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type CommandStep struct {
Env map[string]string `yaml:"env,omitempty"`
Signature *Signature `yaml:"signature,omitempty"`
Matrix *Matrix `yaml:"matrix,omitempty"`
Cache *Cache `yaml:"cache,omitempty"`

// RemainingFields stores any other top-level mapping items so they at least
// survive an unmarshal-marshal round-trip.
Expand Down
50 changes: 50 additions & 0 deletions step_command_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package pipeline

import (
"fmt"

"github.com/buildkite/go-pipeline/ordered"
)

var _ ordered.Unmarshaler = (*Cache)(nil)

var (
errUnsupportedCacheType = fmt.Errorf("unsupported type for cache")
)

// Cache models the cache settings for a given step
type Cache struct {
Paths []string `json:"paths" yaml:"paths"`

RemainingFields map[string]any `yaml:",inline"`
}

// UnmarshalOrdered unmarshals from the following types:
// - string: a single path
// - []string: multiple paths
// - ordered.Map: a map containing paths, among potentially other things
func (c *Cache) UnmarshalOrdered(o any) error {
switch v := o.(type) {
case string:
c.Paths = []string{v}

case []any:
s := make([]string, 0, len(v))
if err := ordered.Unmarshal(v, &s); err != nil {
return err
}

c.Paths = s

case *ordered.MapSA:
type wrappedCache Cache
if err := ordered.Unmarshal(o, (*wrappedCache)(c)); err != nil {
return err
}

default:
return fmt.Errorf("%w: %T", errUnsupportedCacheType, v)
}

return nil
}
91 changes: 91 additions & 0 deletions step_command_cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package pipeline

import (
"errors"
"testing"

"github.com/buildkite/go-pipeline/ordered"
"github.com/google/go-cmp/cmp"
)

func TestCacheUnmarshalOrdered(t *testing.T) {
t.Parallel()

cases := []struct {
name string
input any
want Cache
wantErr error
}{
{
name: "single path",
input: "path/to/cache",
want: Cache{Paths: []string{"path/to/cache"}},
},
{
name: "array of paths",
input: []any{"path/to/cache", "another/path"},
want: Cache{Paths: []string{"path/to/cache", "another/path"}},
},
{
name: "full cache settings block",
input: ordered.MapFromItems(
ordered.TupleSA{Key: "paths", Value: []any{"path/to/cache", "another/path"}},
),
want: Cache{Paths: []string{"path/to/cache", "another/path"}},
},
{
name: "full cache settings block with extra fields",
input: ordered.MapFromItems(
ordered.TupleSA{Key: "paths", Value: []any{"path/to/cache", "another/path"}},
ordered.TupleSA{Key: "extra", Value: "field"},
),
want: Cache{
Paths: []string{"path/to/cache", "another/path"},
RemainingFields: map[string]any{"extra": "field"},
},
},
{
name: "multi-type list of scalar paths get normalised to strings",
input: []any{"path/to/cache", 42, true}, // 42 and true are valid directory paths, so we should keep them as strings
want: Cache{Paths: []string{"path/to/cache", "42", "true"}},
},
{
name: "non-scalar elements in an array",
input: []any{"path/to/cache", []int{1, 2, 3}, map[string]any{"hi": "there"}},
wantErr: ordered.ErrUnsupportedSrc,
},
{
name: "invalid typed scalar",
input: 42,
wantErr: errUnsupportedCacheType,
},
{
name: "invalid map",
input: ordered.MapFromItems(
ordered.TupleSA{
Key: "paths",
Value: ordered.MapFromItems( // nested map, not allowed
ordered.TupleSA{Key: "path", Value: "path/to/cache"},
),
},
),
wantErr: ordered.ErrIncompatibleTypes,
},
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

var c Cache
if err := c.UnmarshalOrdered(tc.input); !errors.Is(err, tc.wantErr) {
t.Fatalf("Cache.UnmarshalOrdered(%v) = %v, want: %v", tc.input, err, tc.wantErr)
}

if diff := cmp.Diff(c, tc.want); diff != "" {
t.Errorf("Cache diff after UnmarshalOrdered (-got +want):\n%s", diff)
}
})
}
}

0 comments on commit 1c8eae3

Please sign in to comment.