From 67a7a8eebd162e5bd85b438041cf58cfd7e72cf9 Mon Sep 17 00:00:00 2001 From: Samuel K Date: Sun, 24 May 2026 10:58:48 -0500 Subject: [PATCH] refactor(hack): port merge-mac-metadata to Go, drop yaml.v2 Rewrites hack/merge-mac-metadata.py in Go (`go run` from the release workflow) so the build no longer needs Python/pyyaml. Upgrades the two remaining yaml.v2 callers to yaml.v3 so yaml.v2 is no longer a direct dependency. --- .github/workflows/release.yml | 8 +- .golangci.yaml | 4 + cmd/pro/import_workspace.go | 2 +- go.mod | 3 +- go.sum | 2 - hack/merge-mac-metadata.py | 73 ------------------ hack/merge_mac_metadata.go | 136 ++++++++++++++++++++++++++++++++++ pkg/devcontainer/compose.go | 2 +- 8 files changed, 148 insertions(+), 82 deletions(-) delete mode 100755 hack/merge-mac-metadata.py create mode 100644 hack/merge_mac_metadata.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f4d539e6a..6112540b9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -233,6 +233,10 @@ jobs: with: persist-credentials: false + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + - name: download update metadata artifacts uses: actions/download-artifact@v8 with: @@ -247,9 +251,7 @@ jobs: done - name: merge macOS metadata from separate arch builds - run: | - pip install pyyaml - python3 hack/merge-mac-metadata.py metadata/ publish-dir/desktop/ + run: go run hack/merge_mac_metadata.go metadata/ publish-dir/desktop/ - name: overlay non-mac metadata files (stable release) if: ${{ !github.event.release.prerelease }} diff --git a/.golangci.yaml b/.golangci.yaml index 66cc8e9a1..94eed5599 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -37,6 +37,10 @@ linters: - gosec text: "G101" path: "pkg/telemetry/analytics/client.go" + - path: "hack/" + linters: + - forbidigo + - gosec settings: cyclop: max-complexity: 8 diff --git a/cmd/pro/import_workspace.go b/cmd/pro/import_workspace.go index 08e29d34d..ad0e3d752 100644 --- a/cmd/pro/import_workspace.go +++ b/cmd/pro/import_workspace.go @@ -20,7 +20,7 @@ import ( "github.com/devsy-org/devsy/pkg/random" "github.com/devsy-org/devsy/pkg/workspace" "github.com/spf13/cobra" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) type ImportCmd struct { diff --git a/go.mod b/go.mod index 721401be5..3e326d0d6 100644 --- a/go.mod +++ b/go.mod @@ -62,7 +62,7 @@ require ( golang.org/x/term v0.42.0 google.golang.org/grpc v1.80.0 google.golang.org/protobuf v1.36.11 - gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.1 gotest.tools v2.2.0+incompatible k8s.io/api v0.35.3 k8s.io/apimachinery v0.35.3 @@ -296,7 +296,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 // indirect k8s.io/apiextensions-apiserver v0.35.0 // indirect k8s.io/apiserver v0.35.3 // indirect diff --git a/go.sum b/go.sum index 951a87564..3604b6106 100644 --- a/go.sum +++ b/go.sum @@ -856,8 +856,6 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/hack/merge-mac-metadata.py b/hack/merge-mac-metadata.py deleted file mode 100755 index 027d06fe5..000000000 --- a/hack/merge-mac-metadata.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python3 -"""Merge macOS electron-updater metadata from separate arch builds. - -When building macOS arm64 and x64 separately, each produces its own -latest-mac.yml (or beta-mac.yml) with only one architecture's files. -This script merges them into a single file with entries for both arches. -""" - -import argparse -import glob -from pathlib import Path - -import yaml - - -def merge_mac_files(metadata_dir: str, output_dir: str) -> None: - metadata_path = Path(metadata_dir) - output_path = Path(output_dir) - - for prefix in ("latest-mac", "beta-mac"): - pattern = str(metadata_path / "**" / f"{prefix}.yml") - found = glob.glob(pattern, recursive=True) - if not found: - continue - - merged_files = [] - base_data = None - - for filepath in found: - with open(filepath) as f: - data = yaml.safe_load(f) - if data is None: - continue - if base_data is None: - base_data = data - if "files" in data: - merged_files.extend(data["files"]) - - if base_data is None: - continue - - base_data["files"] = merged_files - - if merged_files: - base_data["path"] = merged_files[0]["url"] - base_data["sha512"] = merged_files[0]["sha512"] - base_data["size"] = merged_files[0].get("size") - - out_file = output_path / f"{prefix}.yml" - with open(out_file, "w") as f: - yaml.dump(base_data, f, default_flow_style=False, sort_keys=False) - - print(f"Merged {len(found)} files into {out_file}") - - -def main() -> None: - parser = argparse.ArgumentParser( - description="Merge macOS electron-updater metadata from separate arch builds" - ) - parser.add_argument( - "metadata_dir", - help="Directory containing downloaded update-metadata-* artifacts", - ) - parser.add_argument( - "output_dir", - help="Directory to write merged metadata files into", - ) - args = parser.parse_args() - merge_mac_files(args.metadata_dir, args.output_dir) - - -if __name__ == "__main__": - main() diff --git a/hack/merge_mac_metadata.go b/hack/merge_mac_metadata.go new file mode 100644 index 000000000..48ed9708a --- /dev/null +++ b/hack/merge_mac_metadata.go @@ -0,0 +1,136 @@ +// Merge macOS electron-updater metadata from separate arch builds. +// +// When building macOS arm64 and x64 separately, each produces its own +// latest-mac.yml (or beta-mac.yml) with only one architecture's files. +// This script merges them into a single file with entries for both arches. +package main + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + + "gopkg.in/yaml.v3" +) + +func findFiles(root, name string) ([]string, error) { + var found []string + err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() && d.Name() == name { + found = append(found, path) + } + return nil + }) + if err != nil { + return nil, fmt.Errorf("walk %s: %w", root, err) + } + return found, nil +} + +func loadYAML(path string) (map[string]any, error) { + raw, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("read %s: %w", path, err) + } + var data map[string]any + if err := yaml.Unmarshal(raw, &data); err != nil { + return nil, fmt.Errorf("parse %s: %w", path, err) + } + return data, nil +} + +func mergeFileEntries(paths []string) (base map[string]any, files []any, err error) { + for _, p := range paths { + data, err := loadYAML(p) + if err != nil { + return nil, nil, err + } + if data == nil { + continue + } + if base == nil { + base = data + } + if entries, ok := data["files"].([]any); ok { + files = append(files, entries...) + } + } + return base, files, nil +} + +func applyTopLevelFromFirst(base map[string]any, files []any) { + if len(files) == 0 { + return + } + first, ok := files[0].(map[string]any) + if !ok { + return + } + base["path"] = first["url"] + base["sha512"] = first["sha512"] + base["size"] = first["size"] +} + +func writeYAML(path string, data map[string]any) error { + out, err := yaml.Marshal(data) + if err != nil { + return fmt.Errorf("marshal %s: %w", path, err) + } + if err := os.WriteFile(path, out, 0o644); err != nil { + return fmt.Errorf("write %s: %w", path, err) + } + return nil +} + +func mergePrefix(metadataDir, outputDir, prefix string) error { + target := prefix + ".yml" + found, err := findFiles(metadataDir, target) + if err != nil { + return err + } + if len(found) == 0 { + return nil + } + + base, files, err := mergeFileEntries(found) + if err != nil { + return err + } + if base == nil { + return nil + } + + base["files"] = files + applyTopLevelFromFirst(base, files) + + outFile := filepath.Join(outputDir, target) + if err := writeYAML(outFile, base); err != nil { + return err + } + fmt.Printf("Merged %d files into %s\n", len(found), outFile) + return nil +} + +func mergeMacFiles(metadataDir, outputDir string) error { + for _, prefix := range []string{"latest-mac", "beta-mac"} { + if err := mergePrefix(metadataDir, outputDir, prefix); err != nil { + return err + } + } + return nil +} + +func main() { + if len(os.Args) != 3 { + fmt.Fprintf(os.Stderr, "usage: %s \n", os.Args[0]) + os.Exit(2) + } + if err := mergeMacFiles(os.Args[1], os.Args[2]); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/pkg/devcontainer/compose.go b/pkg/devcontainer/compose.go index f6e576dae..f341320c8 100644 --- a/pkg/devcontainer/compose.go +++ b/pkg/devcontainer/compose.go @@ -20,7 +20,7 @@ import ( "github.com/devsy-org/devsy/pkg/driver" "github.com/devsy-org/devsy/pkg/log" "github.com/joho/godotenv" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) const (