Skip to content
Merged
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
5 changes: 5 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ inputs:
description: AWS region for the S3 bucket.
required: false
default: us-west-2
key-prefix:
description: >
Optional path prefix prepended to all S3 object keys. Useful for
namespacing objects within a shared bucket.
required: false
ref:
description: >
Git ref used to search for a base bundle. On pull_request restores, the
Expand Down
2 changes: 2 additions & 0 deletions action/src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ function backendArgs() {
if (bucket) {
args.push("--bucket", bucket);
if (region) args.push("--region", region);
const keyPrefix = core.getInput("key-prefix");
if (keyPrefix) args.push("--key-prefix", keyPrefix);
Comment thread
joshfriend marked this conversation as resolved.
} else {
// Default to GitHub Actions cache when no explicit backend is configured.
args.push("--github-actions");
Expand Down
5 changes: 5 additions & 0 deletions cmd/gradle-cache/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type CLI struct {
type backendFlags struct {
Bucket string `help:"S3 bucket name."`
Region string `help:"AWS region." default:"us-west-2" env:"AWS_REGION"`
KeyPrefix string `help:"Optional path prefix prepended to all S3 object keys." name:"key-prefix"`
CachewURL string `help:"Cachew server URL (e.g. http://localhost:8080). Mutually exclusive with --bucket." name:"cachew-url"`
GithubActions bool `help:"Use the GitHub Actions Cache backend." name:"github-actions"`
}
Expand Down Expand Up @@ -82,6 +83,7 @@ func (c *RestoreCmd) Run(ctx context.Context, metrics gradlecache.MetricsClient)
Bucket: c.Bucket,
Region: c.Region,
CachewURL: c.CachewURL,
KeyPrefix: c.KeyPrefix,
CacheKey: c.CacheKey,
GitDir: c.GitDir,
Ref: c.Ref,
Expand Down Expand Up @@ -113,6 +115,7 @@ func (c *RestoreDeltaCmd) Run(ctx context.Context, metrics gradlecache.MetricsCl
Bucket: c.Bucket,
Region: c.Region,
CachewURL: c.CachewURL,
KeyPrefix: c.KeyPrefix,
CacheKey: c.CacheKey,
Branch: c.Branch,
GradleUserHome: c.GradleUserHome,
Expand Down Expand Up @@ -141,6 +144,7 @@ func (c *SaveCmd) Run(ctx context.Context, metrics gradlecache.MetricsClient) er
Bucket: c.Bucket,
Region: c.Region,
CachewURL: c.CachewURL,
KeyPrefix: c.KeyPrefix,
CacheKey: c.CacheKey,
Commit: c.Commit,
GitDir: c.GitDir,
Expand Down Expand Up @@ -169,6 +173,7 @@ func (c *SaveDeltaCmd) Run(ctx context.Context, metrics gradlecache.MetricsClien
Bucket: c.Bucket,
Region: c.Region,
CachewURL: c.CachewURL,
KeyPrefix: c.KeyPrefix,
CacheKey: c.CacheKey,
Branch: c.Branch,
GradleUserHome: c.GradleUserHome,
Expand Down
2 changes: 2 additions & 0 deletions dist/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33589,6 +33589,8 @@ function backendArgs() {
if (bucket) {
args.push("--bucket", bucket);
if (region) args.push("--region", region);
const keyPrefix = core.getInput("key-prefix");
if (keyPrefix) args.push("--key-prefix", keyPrefix);
} else {
// Default to GitHub Actions cache when no explicit backend is configured.
args.push("--github-actions");
Expand Down
2 changes: 2 additions & 0 deletions dist/post/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33589,6 +33589,8 @@ function backendArgs() {
if (bucket) {
args.push("--bucket", bucket);
if (region) args.push("--region", region);
const keyPrefix = core.getInput("key-prefix");
if (keyPrefix) args.push("--key-prefix", keyPrefix);
} else {
// Default to GitHub Actions cache when no explicit backend is configured.
args.push("--github-actions");
Expand Down
2 changes: 2 additions & 0 deletions dist/pre/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33589,6 +33589,8 @@ function backendArgs() {
if (bucket) {
args.push("--bucket", bucket);
if (region) args.push("--region", region);
const keyPrefix = core.getInput("key-prefix");
if (keyPrefix) args.push("--key-prefix", keyPrefix);
} else {
// Default to GitHub Actions cache when no explicit backend is configured.
args.push("--github-actions");
Expand Down
4 changes: 2 additions & 2 deletions gradlecache/gradlecache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func TestS3Key(t *testing.T) {
},
}
for _, tt := range tests {
if got := s3Key(tt.commit, tt.cacheKey, tt.bundleFile); got != tt.want {
if got := s3Key("", tt.commit, tt.cacheKey, tt.bundleFile); got != tt.want {
t.Errorf("s3Key(%q, %q, %q) = %q, want %q",
tt.commit, tt.cacheKey, tt.bundleFile, got, tt.want)
}
Expand Down Expand Up @@ -1460,7 +1460,7 @@ func TestS3BundleStoreRoundTrip(t *testing.T) {
cacheKey := "apos-beta"
payload := []byte("bundle contents")

legacyKey := "test-bucket/" + s3Key(commit, cacheKey, bundleFilename(cacheKey))
legacyKey := "test-bucket/" + s3Key("", commit, cacheKey, bundleFilename(cacheKey))
fs.mu.Lock()
fs.objects[legacyKey] = payload
fs.mu.Unlock()
Expand Down
4 changes: 3 additions & 1 deletion gradlecache/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ type RestoreConfig struct {
Region string
// CachewURL is the cachew server URL. Mutually exclusive with Bucket.
CachewURL string
// KeyPrefix is an optional path prefix prepended to all S3 object keys.
KeyPrefix string
// CacheKey is the bundle identifier (e.g. "my-project:assembleRelease").
CacheKey string
// GitDir is the path to the git repository for history walking. Defaults to ".".
Expand Down Expand Up @@ -296,7 +298,7 @@ func Restore(ctx context.Context, cfg RestoreConfig) error {
}
log := cfg.Logger

store, err := newStore(cfg.Bucket, cfg.Region, cfg.CachewURL)
store, err := newStore(cfg.Bucket, cfg.Region, cfg.CachewURL, cfg.KeyPrefix)
if err != nil {
return err
}
Expand Down
9 changes: 6 additions & 3 deletions gradlecache/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type RestoreDeltaConfig struct {
Bucket string
Region string
CachewURL string
KeyPrefix string
CacheKey string
Branch string
GradleUserHome string
Expand Down Expand Up @@ -63,7 +64,7 @@ func RestoreDelta(ctx context.Context, cfg RestoreDeltaConfig) error {
return errors.Errorf("caches directory not found at %s — run restore first: %w", cachesDir, err)
}

store, err := newStore(cfg.Bucket, cfg.Region, cfg.CachewURL)
store, err := newStore(cfg.Bucket, cfg.Region, cfg.CachewURL, cfg.KeyPrefix)
if err != nil {
return err
}
Expand Down Expand Up @@ -120,6 +121,7 @@ type SaveConfig struct {
Bucket string
Region string
CachewURL string
KeyPrefix string
CacheKey string
Commit string
GitDir string
Expand Down Expand Up @@ -173,7 +175,7 @@ func Save(ctx context.Context, cfg SaveConfig) error {
return errors.Errorf("caches directory not found at %s: %w", cachesDir, err)
}

store, err := newStore(cfg.Bucket, cfg.Region, cfg.CachewURL)
store, err := newStore(cfg.Bucket, cfg.Region, cfg.CachewURL, cfg.KeyPrefix)
if err != nil {
return err
}
Expand Down Expand Up @@ -267,6 +269,7 @@ type SaveDeltaConfig struct {
Bucket string
Region string
CachewURL string
KeyPrefix string
CacheKey string
Branch string
GradleUserHome string
Expand Down Expand Up @@ -345,7 +348,7 @@ func SaveDelta(ctx context.Context, cfg SaveDeltaConfig) error {
return nil
}

store, err := newStore(cfg.Bucket, cfg.Region, cfg.CachewURL)
store, err := newStore(cfg.Bucket, cfg.Region, cfg.CachewURL, cfg.KeyPrefix)
if err != nil {
return err
}
Expand Down
25 changes: 15 additions & 10 deletions gradlecache/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type bundleStore interface {
putStream(ctx context.Context, commit, cacheKey string, r io.Reader) (int64, error)
}

func newStore(bucket, region, cachewURL string) (bundleStore, error) {
func newStore(bucket, region, cachewURL, keyPrefix string) (bundleStore, error) {
if cachewURL != "" {
return newCachewClient(cachewURL), nil
}
Expand All @@ -46,42 +46,47 @@ func newStore(bucket, region, cachewURL string) (bundleStore, error) {
if err != nil {
return nil, err
}
return &s3BundleStore{client: client, bucket: bucket}, nil
return &s3BundleStore{client: client, bucket: bucket, keyPrefix: keyPrefix}, nil
}

// ── S3 bundle store ─────────────────────────────────────────────────────────

type s3BundleStore struct {
client *s3Client
bucket string
client *s3Client
bucket string
keyPrefix string // optional path prefix prepended to all object keys
}

func (s *s3BundleStore) stat(ctx context.Context, commit, cacheKey string) (bundleStatInfo, error) {
obj, err := s.client.stat(ctx, s.bucket, s3Key(commit, cacheKey, bundleFilename(cacheKey)))
obj, err := s.client.stat(ctx, s.bucket, s3Key(s.keyPrefix, commit, cacheKey, bundleFilename(cacheKey)))
if err != nil {
return bundleStatInfo{}, err
}
return bundleStatInfo{Size: obj.Size, etag: obj.ETag}, nil
}

func (s *s3BundleStore) get(ctx context.Context, commit, cacheKey string, info bundleStatInfo) (io.ReadCloser, error) {
return s.client.get(ctx, s.bucket, s3Key(commit, cacheKey, bundleFilename(cacheKey)), s3ObjInfo{Size: info.Size, ETag: info.etag})
return s.client.get(ctx, s.bucket, s3Key(s.keyPrefix, commit, cacheKey, bundleFilename(cacheKey)), s3ObjInfo{Size: info.Size, ETag: info.etag})
}

func (s *s3BundleStore) put(ctx context.Context, commit, cacheKey string, r io.ReadSeeker, size int64) error {
return s.client.put(ctx, s.bucket, s3Key(commit, cacheKey, bundleFilename(cacheKey)), r, size, "application/zstd")
return s.client.put(ctx, s.bucket, s3Key(s.keyPrefix, commit, cacheKey, bundleFilename(cacheKey)), r, size, "application/zstd")
}

func (s *s3BundleStore) putStream(ctx context.Context, commit, cacheKey string, r io.Reader) (int64, error) {
return s.client.putStreamingMultipart(ctx, s.bucket, s3Key(commit, cacheKey, bundleFilename(cacheKey)), r, "application/zstd")
return s.client.putStreamingMultipart(ctx, s.bucket, s3Key(s.keyPrefix, commit, cacheKey, bundleFilename(cacheKey)), r, "application/zstd")
}

func bundleFilename(cacheKey string) string {
return strings.ReplaceAll(cacheKey, ":", "-") + ".tar.zst"
}

func s3Key(commit, cacheKey, bundleFile string) string {
return commit + "/" + cacheKey + "/" + bundleFile
func s3Key(prefix, commit, cacheKey, bundleFile string) string {
key := commit + "/" + cacheKey + "/" + bundleFile
if prefix != "" {
return prefix + "/" + key
}
return key
}

// ── Cachew client ───────────────────────────────────────────────────────────
Expand Down
Loading