diff --git a/custom-recipes/rbuilder/bin/playground.yaml b/custom-recipes/rbuilder/bin/playground.yaml index d7d6605b..a4ee4a42 100644 --- a/custom-recipes/rbuilder/bin/playground.yaml +++ b/custom-recipes/rbuilder/bin/playground.yaml @@ -10,7 +10,7 @@ recipe: release: name: "reth" org: "paradigmxyz" - version: "v1.10.1" + version: "v1.11.3" # v2.0.0 not supported yet builder: services: @@ -20,8 +20,8 @@ recipe: release: name: "rbuilder" org: "flashbots" - version: "v1.3.4" - format: "binary" + version: "v1.3.15" + format: "binary-arch" args: - "run" - "rbuilder.toml" diff --git a/docs/custom_recipes_guide.md b/docs/custom_recipes_guide.md index 90037788..e2755671 100644 --- a/docs/custom_recipes_guide.md +++ b/docs/custom_recipes_guide.md @@ -285,11 +285,12 @@ services: org: flashbots repo: rbuilder # defaults to name if omitted version: v0.1.0 - format: tar.gz # tar.gz (default) | binary + format: tar.gz # tar.gz (default) | binary | binary-arch ``` -- `format: tar.gz` — downloads and extracts a tarball; arch string is inferred from the OS/arch. -- `format: binary` — downloads the raw binary directly; no extraction, arch ignored. +- `format: tar.gz` — downloads and extracts `--.tar.gz`; arch string is inferred from the OS/arch. +- `format: binary` — downloads the raw binary at ``; no extraction, arch ignored. +- `format: binary-arch` — downloads the raw binary at `--`; used by releases that publish per-architecture binaries without tarballs (e.g. flashbots/rbuilder). ### Lifecycle hooks diff --git a/playground/recipe_yaml.go b/playground/recipe_yaml.go index 176fc361..556d43de 100644 --- a/playground/recipe_yaml.go +++ b/playground/recipe_yaml.go @@ -133,8 +133,10 @@ type YAMLReleaseConfig struct { Org string `yaml:"org"` Repo string `yaml:"repo,omitempty"` Version string `yaml:"version"` - // Format specifies the download format: "tar.gz" (default) or "binary" - // For "binary", downloads the raw binary directly without extraction + // Format specifies the download format: "tar.gz" (default), "binary", or "binary-arch". + // "binary" downloads the raw binary at . + // "binary-arch" downloads the raw binary at -- (used by releases + // like flashbots/rbuilder that publish per-architecture binaries without tarballs). Format string `yaml:"format,omitempty"` } @@ -649,7 +651,7 @@ func yamlReleaseToRelease(cfg *YAMLReleaseConfig) *release { if cfg.Format == "binary" { return "" } - // Default architecture mapping for tar.gz + // Default architecture mapping for tar.gz and binary-arch if goos == "linux" { return "x86_64-unknown-linux-gnu" } else if goos == "darwin" && goarch == "arm64" { diff --git a/playground/releases.go b/playground/releases.go index b002f498..80840015 100644 --- a/playground/releases.go +++ b/playground/releases.go @@ -20,7 +20,10 @@ type release struct { Org string Version string Arch func(string, string) string - // Format specifies the download format: "tar.gz" (default) or "binary" + // Format specifies the download format: "tar.gz" (default), "binary", or "binary-arch". + // "binary" downloads the asset named as-is. + // "binary-arch" downloads the asset named -- as-is (used by + // releases that publish per-architecture raw binaries, e.g. flashbots/rbuilder). Format string // BaseURL overrides the default GitHub releases URL (for testing) BaseURL string @@ -61,6 +64,16 @@ func DownloadRelease(outputFolder string, artifact *release) (string, error) { releasesURL := fmt.Sprintf("%s/%s/%s/releases/download/%s/%s", baseURL, artifact.Org, repo, artifact.Version, artifact.Name) log.Printf("Downloading binary %s: %s\n", outPath, releasesURL) + if err := downloadBinary(releasesURL, outPath); err != nil { + return "", fmt.Errorf("error downloading binary: %v", err) + } + } else if artifact.Format == "binary-arch" { + if archVersion == "" { + return "", fmt.Errorf("unsupported OS/Arch for binary-arch format: %s/%s", goos, goarch) + } + releasesURL := fmt.Sprintf("%s/%s/%s/releases/download/%s/%s-%s-%s", baseURL, artifact.Org, repo, artifact.Version, artifact.Name, artifact.Version, archVersion) + log.Printf("Downloading binary %s: %s\n", outPath, releasesURL) + if err := downloadBinary(releasesURL, outPath); err != nil { return "", fmt.Errorf("error downloading binary: %v", err) } diff --git a/playground/releases_test.go b/playground/releases_test.go index 73e134d3..68478cde 100644 --- a/playground/releases_test.go +++ b/playground/releases_test.go @@ -108,6 +108,62 @@ func TestDownloadRelease_Binary(t *testing.T) { require.Equal(t, os.FileMode(0o755), info.Mode().Perm()) } +func TestDownloadRelease_BinaryArch(t *testing.T) { + tmpDir := t.TempDir() + + binaryContent := []byte("#!/bin/bash\necho hello") + + var requestedPath string + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requestedPath = r.URL.Path + w.Write(binaryContent) + })) + defer server.Close() + + rel := &release{ + Name: "rbuilder", + Org: "flashbots", + Repo: "rbuilder", + Version: "v1.3.15", + Format: "binary-arch", + BaseURL: server.URL, + Arch: func(goos, goarch string) string { + return "x86_64-unknown-linux-gnu" + }, + } + + outPath, err := DownloadRelease(tmpDir, rel) + require.NoError(t, err) + + require.Equal(t, "/flashbots/rbuilder/releases/download/v1.3.15/rbuilder-v1.3.15-x86_64-unknown-linux-gnu", requestedPath) + + content, err := os.ReadFile(outPath) + require.NoError(t, err) + require.Equal(t, binaryContent, content) + + info, err := os.Stat(outPath) + require.NoError(t, err) + require.Equal(t, os.FileMode(0o755), info.Mode().Perm()) +} + +func TestDownloadRelease_BinaryArch_UnsupportedArch(t *testing.T) { + tmpDir := t.TempDir() + + rel := &release{ + Name: "rbuilder", + Org: "flashbots", + Version: "v1.3.15", + Format: "binary-arch", + Arch: func(goos, goarch string) string { + return "" + }, + } + + _, err := DownloadRelease(tmpDir, rel) + require.Error(t, err) + require.Contains(t, err.Error(), "unsupported OS/Arch for binary-arch") +} + func TestDownloadRelease_RepoDefaultsToName(t *testing.T) { tmpDir := t.TempDir()