From 5b8a412ce561822eba09e0b4f4ca3d344f3ed329 Mon Sep 17 00:00:00 2001 From: Richard Carson Derr Date: Sat, 12 Jul 2025 16:25:03 -0400 Subject: [PATCH 1/6] feat(issue-15): create new module for protobuf --- protobuf/.gitattributes | 4 ++ protobuf/.gitignore | 5 ++ protobuf/dagger.json | 7 +++ protobuf/go.mod | 56 ++++++++++++++++++ protobuf/go.sum | 105 +++++++++++++++++++++++++++++++++ protobuf/golang.go | 72 +++++++++++++++++++++++ protobuf/main.go | 107 ++++++++++++++++++++++++++++++++++ protobuf/protoc.go | 79 +++++++++++++++++++++++++ protobuf/tests/.gitattributes | 4 ++ protobuf/tests/.gitignore | 5 ++ protobuf/tests/dagger.json | 13 +++++ protobuf/tests/go.mod | 54 +++++++++++++++++ protobuf/tests/go.sum | 98 +++++++++++++++++++++++++++++++ protobuf/tests/golang.go | 42 +++++++++++++ protobuf/tests/main.go | 29 +++++++++ 15 files changed, 680 insertions(+) create mode 100644 protobuf/.gitattributes create mode 100644 protobuf/.gitignore create mode 100644 protobuf/dagger.json create mode 100644 protobuf/go.mod create mode 100644 protobuf/go.sum create mode 100644 protobuf/golang.go create mode 100644 protobuf/main.go create mode 100644 protobuf/protoc.go create mode 100644 protobuf/tests/.gitattributes create mode 100644 protobuf/tests/.gitignore create mode 100644 protobuf/tests/dagger.json create mode 100644 protobuf/tests/go.mod create mode 100644 protobuf/tests/go.sum create mode 100644 protobuf/tests/golang.go create mode 100644 protobuf/tests/main.go diff --git a/protobuf/.gitattributes b/protobuf/.gitattributes new file mode 100644 index 0000000..3a45493 --- /dev/null +++ b/protobuf/.gitattributes @@ -0,0 +1,4 @@ +/dagger.gen.go linguist-generated +/internal/dagger/** linguist-generated +/internal/querybuilder/** linguist-generated +/internal/telemetry/** linguist-generated diff --git a/protobuf/.gitignore b/protobuf/.gitignore new file mode 100644 index 0000000..773338b --- /dev/null +++ b/protobuf/.gitignore @@ -0,0 +1,5 @@ +/dagger.gen.go +/internal/dagger +/internal/querybuilder +/internal/telemetry +/.env diff --git a/protobuf/dagger.json b/protobuf/dagger.json new file mode 100644 index 0000000..4684d17 --- /dev/null +++ b/protobuf/dagger.json @@ -0,0 +1,7 @@ +{ + "name": "protobuf", + "engineVersion": "v0.18.12", + "sdk": { + "source": "go" + } +} diff --git a/protobuf/go.mod b/protobuf/go.mod new file mode 100644 index 0000000..ee67e41 --- /dev/null +++ b/protobuf/go.mod @@ -0,0 +1,56 @@ +module dagger/protobuf + +go 1.24.4 + +require ( + github.com/99designs/gqlgen v0.17.75 + github.com/Khan/genqlient v0.8.1 + github.com/containerd/platforms v0.2.1 + github.com/vektah/gqlparser/v2 v2.5.28 + go.opentelemetry.io/otel v1.36.0 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 + go.opentelemetry.io/otel/log v0.12.2 + go.opentelemetry.io/otel/metric v1.36.0 + go.opentelemetry.io/otel/sdk v1.36.0 + go.opentelemetry.io/otel/sdk/log v0.12.2 + go.opentelemetry.io/otel/sdk/metric v1.36.0 + go.opentelemetry.io/otel/trace v1.36.0 + go.opentelemetry.io/proto/otlp v1.6.0 + golang.org/x/sync v0.15.0 + google.golang.org/grpc v1.73.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.2 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sosodev/duration v1.3.1 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect + google.golang.org/protobuf v1.36.6 // indirect +) + +replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc => go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 + +replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp => go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 + +replace go.opentelemetry.io/otel/log => go.opentelemetry.io/otel/log v0.12.2 + +replace go.opentelemetry.io/otel/sdk/log => go.opentelemetry.io/otel/sdk/log v0.12.2 diff --git a/protobuf/go.sum b/protobuf/go.sum new file mode 100644 index 0000000..deeaf8d --- /dev/null +++ b/protobuf/go.sum @@ -0,0 +1,105 @@ +github.com/99designs/gqlgen v0.17.75 h1:GwHJsptXWLHeY7JO8b7YueUI4w9Pom6wJTICosDtQuI= +github.com/99designs/gqlgen v0.17.75/go.mod h1:p7gbTpdnHyl70hmSpM8XG8GiKwmCv+T5zkdY8U8bLog= +github.com/Khan/genqlient v0.8.1 h1:wtOCc8N9rNynRLXN3k3CnfzheCUNKBcvXmVv5zt6WCs= +github.com/Khan/genqlient v0.8.1/go.mod h1:R2G6DzjBvCbhjsEajfRjbWdVglSH/73kSivC9TLWVjU= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4= +github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vektah/gqlparser/v2 v2.5.28 h1:bIulcl3LF69ba6EiZVGD88y4MkM+Jxrf3P2MX8xLRkY= +github.com/vektah/gqlparser/v2 v2.5.28/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 h1:06ZeJRe5BnYXceSM9Vya83XXVaNGe3H1QqsvqRANQq8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2/go.mod h1:DvPtKE63knkDVP88qpatBj81JxN+w1bqfVbsbCbj1WY= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 h1:tPLwQlXbJ8NSOfZc4OkgU5h2A38M4c9kfHSVc4PFQGs= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2/go.mod h1:QTnxBwT/1rBIgAG1goq6xMydfYOBKU6KTiYF4fp5zL8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9O88joYEaI47CnQkxO1XZdpoTF9fEnW2duIddhw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI= +go.opentelemetry.io/otel/log v0.12.2 h1:yob9JVHn2ZY24byZeaXpTVoPS6l+UrrxmxmPKohXTwc= +go.opentelemetry.io/otel/log v0.12.2/go.mod h1:ShIItIxSYxufUMt+1H5a2wbckGli3/iCfuEbVZi/98E= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/log v0.12.2 h1:yNoETvTByVKi7wHvYS6HMcZrN5hFLD7I++1xIZ/k6W0= +go.opentelemetry.io/otel/sdk/log v0.12.2/go.mod h1:DcpdmUXHJgSqN/dh+XMWa7Vf89u9ap0/AAk/XGLnEzY= +go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc h1:uqxdywfHqqCl6LmZzI3pUnXT1RGFYyUgxj0AkWPFxi0= +go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc/go.mod h1:TY/N/FT7dmFrP/r5ym3g0yysP1DefqGpAZr4f82P0dE= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI= +go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0= +google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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/protobuf/golang.go b/protobuf/golang.go new file mode 100644 index 0000000..28be528 --- /dev/null +++ b/protobuf/golang.go @@ -0,0 +1,72 @@ +// Copyright (c) 2025 Z5Labs and Contributors +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +package main + +import "fmt" + +type Go struct { + Protobuf *Protobuf +} + +// Install the protoc-gen-go plugin. +func (m *Protobuf) Go( + version string, +) (*Go, error) { + archiveType := "tar.gz" + if m.Plaform.OS == "windows" { + archiveType = "zip" + } + + plugin := dag.HTTP(fmt.Sprintf( + "https://github.com/protocolbuffers/protobuf-go/releases/download/%s/protoc-gen-go.%s.%s.%s.%s", + version, + m.Plaform.OS, + m.Plaform.Architecture, + archiveType, + )) + + withPlugin, err := m.WithPlugin("protoc-gen-go", plugin) + if err != nil { + return nil, err + } + + return &Go{ + Protobuf: withPlugin, + }, nil +} + +// Generate Go code. +func (p *Protoc) Go( + outDir string, + opt []string, +) *Protoc { + p.Generators = append(p.Generators, generator{ + name: "go", + outDir: outDir, + opts: opt, + }) + + return p +} + +// Install the protoc-gen-go-grpc plugin. +func (g *Go) Grpc() *Go { + return g +} + +// Generate GRPC Go code. +func (p *Protoc) GoGrpc( + outDir string, + opt []string, +) *Protoc { + p.Generators = append(p.Generators, generator{ + name: "go-grpc", + outDir: outDir, + opts: opt, + }) + + return p +} diff --git a/protobuf/main.go b/protobuf/main.go new file mode 100644 index 0000000..174e0b2 --- /dev/null +++ b/protobuf/main.go @@ -0,0 +1,107 @@ +// Copyright (c) 2025 Z5Labs and Contributors +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +package main + +import ( + "context" + "errors" + "fmt" + "strings" + + "dagger/protobuf/internal/dagger" + + "github.com/containerd/platforms" +) + +type Protobuf struct { + Container *dagger.Container + + // +private + Plaform platforms.Platform +} + +func New( + ctx context.Context, + version string, + // +optional + platform dagger.Platform, + // +optional + from *dagger.Container, +) (*Protobuf, error) { + if platform == "" { + platform = dagger.Platform(platforms.DefaultString()) + } + + p, err := platforms.Parse(string(platform)) + if err != nil { + return nil, err + } + + if from == nil { + c, err := newContainer(version, p) + if err != nil { + return nil, err + } + + from = c + } + + return &Protobuf{ + Container: from, + Plaform: p, + }, nil +} + +func newContainer(version string, platform platforms.Platform) (*dagger.Container, error) { + arch, err := mapToProtoArch(platform.Architecture) + if err != nil { + return nil, err + } + + protoc := dag.HTTP(fmt.Sprintf( + "https://github.com/protocolbuffers/protobuf/releases/download/%s/protoc-%s-%s-%s.zip", + version, + strings.TrimPrefix(version, "v"), + platform.OS, + arch, + )) + + c := dag.Container(). + WithFile("/bin/protoc", protoc) + + return c, nil +} + +func mapToProtoArch(arch string) (string, error) { + mapping := map[string]string{ + "amd64": "x86_64", + "ppc64le": "ppcle_64", + } + + mappedArch, ok := mapping[arch] + if !ok { + return "", errors.New("protoc does not support: " + arch) + + } + + return mappedArch, nil +} + +// Register the given binary file as a protoc plugin. +func (m *Protobuf) WithPlugin(name string, bin *dagger.File) (*Protobuf, error) { + if strings.HasPrefix(name, "protoc-gen-") { + return nil, errors.New("plugin name must start with: protoc-gen-") + } + + m.Container = m.Container.WithFile("/protobuf/plugin/"+name, bin) + + return m, nil +} + +// Copy well-known types, protoc, and plugins to the provided container. +func (m *Protobuf) CopyTo(container *dagger.Container) *dagger.Container { + return container +} diff --git a/protobuf/protoc.go b/protobuf/protoc.go new file mode 100644 index 0000000..60521eb --- /dev/null +++ b/protobuf/protoc.go @@ -0,0 +1,79 @@ +// Copyright (c) 2025 Z5Labs and Contributors +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +package main + +import ( + "context" + "fmt" + + "dagger/protobuf/internal/dagger" +) + +type generator struct { + name string + outDir string + opts []string +} + +type Protoc struct { + // +private + Protobuf *Protobuf + + // +private + Generators []generator +} + +// Run protoc. +func (m *Protobuf) Protoc() *Protoc { + return &Protoc{ + Protobuf: m, + } +} + +// Compile protocol buffer definitions. +func (p *Protoc) Compile( + ctx context.Context, + + source *dagger.Directory, + + proto []string, + + // Specify the directory in which to search for imports. + // +default=["."] + includePath []string, + + // +default=true + includeWellKnownTypes bool, +) (string, error) { + args := []string{ + "protoc", + } + if includeWellKnownTypes { + args = append(args, "-I") // TODO + } + + for _, p := range includePath { + args = append(args, "-I", p) + } + + for _, g := range p.Generators { + args = append(args, fmt.Sprintf("--%s_out", g.name), g.outDir) + + for _, opt := range g.opts { + args = append(args, fmt.Sprintf("--%s_opt", g.name), opt) + } + } + + for _, p := range proto { + args = append(args, p) + } + + return p.Protobuf.Container. + WithMountedDirectory("/src", source). + WithWorkdir("/src"). + WithExec(args). + Stdout(ctx) +} diff --git a/protobuf/tests/.gitattributes b/protobuf/tests/.gitattributes new file mode 100644 index 0000000..3a45493 --- /dev/null +++ b/protobuf/tests/.gitattributes @@ -0,0 +1,4 @@ +/dagger.gen.go linguist-generated +/internal/dagger/** linguist-generated +/internal/querybuilder/** linguist-generated +/internal/telemetry/** linguist-generated diff --git a/protobuf/tests/.gitignore b/protobuf/tests/.gitignore new file mode 100644 index 0000000..773338b --- /dev/null +++ b/protobuf/tests/.gitignore @@ -0,0 +1,5 @@ +/dagger.gen.go +/internal/dagger +/internal/querybuilder +/internal/telemetry +/.env diff --git a/protobuf/tests/dagger.json b/protobuf/tests/dagger.json new file mode 100644 index 0000000..e35a9fc --- /dev/null +++ b/protobuf/tests/dagger.json @@ -0,0 +1,13 @@ +{ + "name": "protobuf-tests", + "engineVersion": "v0.18.12", + "sdk": { + "source": "go" + }, + "dependencies": [ + { + "name": "protobuf", + "source": ".." + } + ] +} diff --git a/protobuf/tests/go.mod b/protobuf/tests/go.mod new file mode 100644 index 0000000..c9185c5 --- /dev/null +++ b/protobuf/tests/go.mod @@ -0,0 +1,54 @@ +module dagger/protobuf-tests + +go 1.24.4 + +require ( + github.com/99designs/gqlgen v0.17.75 + github.com/Khan/genqlient v0.8.1 + github.com/sourcegraph/conc v0.3.0 + github.com/vektah/gqlparser/v2 v2.5.28 + go.opentelemetry.io/otel v1.36.0 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 + go.opentelemetry.io/otel/log v0.12.2 + go.opentelemetry.io/otel/metric v1.36.0 + go.opentelemetry.io/otel/sdk v1.36.0 + go.opentelemetry.io/otel/sdk/log v0.12.2 + go.opentelemetry.io/otel/sdk/metric v1.36.0 + go.opentelemetry.io/otel/trace v1.36.0 + go.opentelemetry.io/proto/otlp v1.6.0 + golang.org/x/sync v0.15.0 + google.golang.org/grpc v1.73.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.2 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/sosodev/duration v1.3.1 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect + google.golang.org/protobuf v1.36.6 // indirect +) + +replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc => go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 + +replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp => go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 + +replace go.opentelemetry.io/otel/log => go.opentelemetry.io/otel/log v0.12.2 + +replace go.opentelemetry.io/otel/sdk/log => go.opentelemetry.io/otel/sdk/log v0.12.2 diff --git a/protobuf/tests/go.sum b/protobuf/tests/go.sum new file mode 100644 index 0000000..9d45787 --- /dev/null +++ b/protobuf/tests/go.sum @@ -0,0 +1,98 @@ +github.com/99designs/gqlgen v0.17.75 h1:GwHJsptXWLHeY7JO8b7YueUI4w9Pom6wJTICosDtQuI= +github.com/99designs/gqlgen v0.17.75/go.mod h1:p7gbTpdnHyl70hmSpM8XG8GiKwmCv+T5zkdY8U8bLog= +github.com/Khan/genqlient v0.8.1 h1:wtOCc8N9rNynRLXN3k3CnfzheCUNKBcvXmVv5zt6WCs= +github.com/Khan/genqlient v0.8.1/go.mod h1:R2G6DzjBvCbhjsEajfRjbWdVglSH/73kSivC9TLWVjU= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4= +github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vektah/gqlparser/v2 v2.5.28 h1:bIulcl3LF69ba6EiZVGD88y4MkM+Jxrf3P2MX8xLRkY= +github.com/vektah/gqlparser/v2 v2.5.28/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 h1:06ZeJRe5BnYXceSM9Vya83XXVaNGe3H1QqsvqRANQq8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2/go.mod h1:DvPtKE63knkDVP88qpatBj81JxN+w1bqfVbsbCbj1WY= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 h1:tPLwQlXbJ8NSOfZc4OkgU5h2A38M4c9kfHSVc4PFQGs= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2/go.mod h1:QTnxBwT/1rBIgAG1goq6xMydfYOBKU6KTiYF4fp5zL8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9O88joYEaI47CnQkxO1XZdpoTF9fEnW2duIddhw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI= +go.opentelemetry.io/otel/log v0.12.2 h1:yob9JVHn2ZY24byZeaXpTVoPS6l+UrrxmxmPKohXTwc= +go.opentelemetry.io/otel/log v0.12.2/go.mod h1:ShIItIxSYxufUMt+1H5a2wbckGli3/iCfuEbVZi/98E= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/log v0.12.2 h1:yNoETvTByVKi7wHvYS6HMcZrN5hFLD7I++1xIZ/k6W0= +go.opentelemetry.io/otel/sdk/log v0.12.2/go.mod h1:DcpdmUXHJgSqN/dh+XMWa7Vf89u9ap0/AAk/XGLnEzY= +go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc h1:uqxdywfHqqCl6LmZzI3pUnXT1RGFYyUgxj0AkWPFxi0= +go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc/go.mod h1:TY/N/FT7dmFrP/r5ym3g0yysP1DefqGpAZr4f82P0dE= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI= +go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0= +google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +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/protobuf/tests/golang.go b/protobuf/tests/golang.go new file mode 100644 index 0000000..d014cc6 --- /dev/null +++ b/protobuf/tests/golang.go @@ -0,0 +1,42 @@ +// Copyright (c) 2025 Z5Labs and Contributors +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +package main + +import ( + "context" + + "dagger/protobuf-tests/internal/dagger" +) + +type Go struct { + // +private + Protobuf *dagger.Protobuf +} + +func (m *ProtobufTests) Go() *Go { + return &Go{ + Protobuf: m.Protobuf.Go().Protobuf(), + } +} + +func (g *Go) All(ctx context.Context) error { + return nil +} + +type GoGrpc struct { + // +private + Protobuf *dagger.Protobuf +} + +func (m *ProtobufTests) GoGrpc() *GoGrpc { + return &GoGrpc{ + Protobuf: m.Protobuf.Go().Grpc().Protobuf(), + } +} + +func (g *GoGrpc) All(ctx context.Context) error { + return nil +} diff --git a/protobuf/tests/main.go b/protobuf/tests/main.go new file mode 100644 index 0000000..a468143 --- /dev/null +++ b/protobuf/tests/main.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + + "dagger/protobuf-tests/internal/dagger" + + "github.com/sourcegraph/conc/pool" +) + +type ProtobufTests struct { + // +private + Protobuf *dagger.Protobuf +} + +func New( + // +default="v31.1" + version string, +) *ProtobufTests { + return &ProtobufTests{ + Protobuf: dag.Protobuf(version), + } +} + +func (m *ProtobufTests) All(ctx context.Context) error { + ep := pool.New().WithErrors().WithContext(ctx) + + return ep.Wait() +} From 8dab872b84722fa48fe6ce16d359b98fc7be097f Mon Sep 17 00:00:00 2001 From: Richard Carson Derr Date: Sat, 12 Jul 2025 18:41:27 -0400 Subject: [PATCH 2/6] feat(issue-15): use archive module --- protobuf/dagger.json | 8 +++++++- protobuf/golang.go | 24 +++++++++++++++++++----- protobuf/main.go | 15 +++++++++++---- protobuf/protoc.go | 4 +--- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/protobuf/dagger.json b/protobuf/dagger.json index 4684d17..55de386 100644 --- a/protobuf/dagger.json +++ b/protobuf/dagger.json @@ -3,5 +3,11 @@ "engineVersion": "v0.18.12", "sdk": { "source": "go" - } + }, + "dependencies": [ + { + "name": "archive", + "source": "../archive" + } + ] } diff --git a/protobuf/golang.go b/protobuf/golang.go index 28be528..b1c9d5a 100644 --- a/protobuf/golang.go +++ b/protobuf/golang.go @@ -5,7 +5,10 @@ package main -import "fmt" +import ( + "dagger/protobuf/internal/dagger" + "fmt" +) type Go struct { Protobuf *Protobuf @@ -16,19 +19,30 @@ func (m *Protobuf) Go( version string, ) (*Go, error) { archiveType := "tar.gz" - if m.Plaform.OS == "windows" { + if m.OS == "windows" { archiveType = "zip" } plugin := dag.HTTP(fmt.Sprintf( "https://github.com/protocolbuffers/protobuf-go/releases/download/%s/protoc-gen-go.%s.%s.%s.%s", version, - m.Plaform.OS, - m.Plaform.Architecture, + version, + m.OS, + m.Arch, archiveType, )) - withPlugin, err := m.WithPlugin("protoc-gen-go", plugin) + var dir *dagger.Directory + switch archiveType { + case "zip": + dir = dag.Archive().Zip().Extract(plugin) + case "tar.gz": + dir = dag.Archive().Tar().Extract(plugin, dagger.ArchiveTarExtractOpts{ + Gzip: true, + }) + } + + withPlugin, err := m.WithPlugin("protoc-gen-go", dir.File("protoc-gen-go")) if err != nil { return nil, err } diff --git a/protobuf/main.go b/protobuf/main.go index 174e0b2..54355e0 100644 --- a/protobuf/main.go +++ b/protobuf/main.go @@ -20,7 +20,10 @@ type Protobuf struct { Container *dagger.Container // +private - Plaform platforms.Platform + OS string + + // +private + Arch string } func New( @@ -51,7 +54,8 @@ func New( return &Protobuf{ Container: from, - Plaform: p, + OS: p.OS, + Arch: p.Architecture, }, nil } @@ -69,8 +73,11 @@ func newContainer(version string, platform platforms.Platform) (*dagger.Containe arch, )) + dir := dag.Archive().Zip().Extract(protoc) + c := dag.Container(). - WithFile("/bin/protoc", protoc) + WithDirectory("/protobuf", dir). + WithEnvVariable("PATH", "/protobuf/bin/") return c, nil } @@ -96,7 +103,7 @@ func (m *Protobuf) WithPlugin(name string, bin *dagger.File) (*Protobuf, error) return nil, errors.New("plugin name must start with: protoc-gen-") } - m.Container = m.Container.WithFile("/protobuf/plugin/"+name, bin) + m.Container = m.Container.WithFile("/protobuf/bin/"+name, bin) return m, nil } diff --git a/protobuf/protoc.go b/protobuf/protoc.go index 60521eb..17b91d3 100644 --- a/protobuf/protoc.go +++ b/protobuf/protoc.go @@ -67,9 +67,7 @@ func (p *Protoc) Compile( } } - for _, p := range proto { - args = append(args, p) - } + args = append(args, proto...) return p.Protobuf.Container. WithMountedDirectory("/src", source). From 7c5a8d15b01a1ef31760ab1727d15fcb96b9cc21 Mon Sep 17 00:00:00 2001 From: Richard Carson Derr Date: Sun, 13 Jul 2025 23:04:03 -0400 Subject: [PATCH 3/6] test(issue-15): added protoc go cases --- protobuf/golang.go | 19 +++-- protobuf/main.go | 15 +++- protobuf/protoc.go | 68 ++++++++++----- protobuf/tests/golang.go | 82 ++++++++++++++++++- protobuf/tests/main.go | 2 + protobuf/tests/testdata/proto/message.proto | 9 ++ .../tests/testdata/proto/well_known.proto | 11 +++ 7 files changed, 173 insertions(+), 33 deletions(-) create mode 100644 protobuf/tests/testdata/proto/message.proto create mode 100644 protobuf/tests/testdata/proto/well_known.proto diff --git a/protobuf/golang.go b/protobuf/golang.go index b1c9d5a..6f5c18b 100644 --- a/protobuf/golang.go +++ b/protobuf/golang.go @@ -6,8 +6,9 @@ package main import ( - "dagger/protobuf/internal/dagger" "fmt" + + "dagger/protobuf/internal/dagger" ) type Go struct { @@ -55,12 +56,14 @@ func (m *Protobuf) Go( // Generate Go code. func (p *Protoc) Go( outDir string, + + // +optional opt []string, ) *Protoc { p.Generators = append(p.Generators, generator{ - name: "go", - outDir: outDir, - opts: opt, + Name: "go", + OutDir: outDir, + Opts: opt, }) return p @@ -74,12 +77,14 @@ func (g *Go) Grpc() *Go { // Generate GRPC Go code. func (p *Protoc) GoGrpc( outDir string, + + // +optional opt []string, ) *Protoc { p.Generators = append(p.Generators, generator{ - name: "go-grpc", - outDir: outDir, - opts: opt, + Name: "go-grpc", + OutDir: outDir, + Opts: opt, }) return p diff --git a/protobuf/main.go b/protobuf/main.go index 54355e0..3f9de9e 100644 --- a/protobuf/main.go +++ b/protobuf/main.go @@ -9,6 +9,7 @@ import ( "context" "errors" "fmt" + "path" "strings" "dagger/protobuf/internal/dagger" @@ -76,8 +77,12 @@ func newContainer(version string, platform platforms.Platform) (*dagger.Containe dir := dag.Archive().Zip().Extract(protoc) c := dag.Container(). + From("alpine"). WithDirectory("/protobuf", dir). - WithEnvVariable("PATH", "/protobuf/bin/") + WithEnvVariable("PATH", "/protobuf/bin/:${PATH}", dagger.ContainerWithEnvVariableOpts{ + Expand: true, + }). + WithExec([]string{"chmod", "+x", "/protobuf/bin/protoc"}) return c, nil } @@ -99,11 +104,15 @@ func mapToProtoArch(arch string) (string, error) { // Register the given binary file as a protoc plugin. func (m *Protobuf) WithPlugin(name string, bin *dagger.File) (*Protobuf, error) { - if strings.HasPrefix(name, "protoc-gen-") { + if !strings.HasPrefix(name, "protoc-gen-") { return nil, errors.New("plugin name must start with: protoc-gen-") } - m.Container = m.Container.WithFile("/protobuf/bin/"+name, bin) + binPath := path.Join("/protobuf/bin", name) + + m.Container = m.Container. + WithFile(binPath, bin). + WithExec([]string{"chmod", "+x", binPath}) return m, nil } diff --git a/protobuf/protoc.go b/protobuf/protoc.go index 17b91d3..73d20fa 100644 --- a/protobuf/protoc.go +++ b/protobuf/protoc.go @@ -6,16 +6,15 @@ package main import ( - "context" "fmt" "dagger/protobuf/internal/dagger" ) type generator struct { - name string - outDir string - opts []string + Name string + OutDir string + Opts []string } type Protoc struct { @@ -35,8 +34,6 @@ func (m *Protobuf) Protoc() *Protoc { // Compile protocol buffer definitions. func (p *Protoc) Compile( - ctx context.Context, - source *dagger.Directory, proto []string, @@ -45,33 +42,62 @@ func (p *Protoc) Compile( // +default=["."] includePath []string, - // +default=true - includeWellKnownTypes bool, -) (string, error) { - args := []string{ + // +optional + excludeWellKnownTypes bool, +) (*dagger.Directory, error) { + args, outDirs := buildCompileArgs( + excludeWellKnownTypes, + includePath, + p.Generators, + proto, + ) + + c := p.Protobuf.Container. + WithMountedDirectory("/src", source). + WithWorkdir("/src") + + for _, outDir := range outDirs { + c = c.WithExec([]string{"mkdir", "-p", outDir}) + } + + c = c.WithExec(args) + + dir := dag.Directory() + for _, outDir := range outDirs { + dir = dir.WithDirectory(outDir, c.Directory(outDir)) + } + + return dir, nil +} + +func buildCompileArgs( + excludeWellKnownTypes bool, + includePath []string, + generators []generator, + proto []string, +) (args []string, outDirs []string) { + args = []string{ "protoc", } - if includeWellKnownTypes { - args = append(args, "-I") // TODO + if !excludeWellKnownTypes { + args = append(args, "-I", "/protobuf/include/") } for _, p := range includePath { args = append(args, "-I", p) } - for _, g := range p.Generators { - args = append(args, fmt.Sprintf("--%s_out", g.name), g.outDir) + for _, g := range generators { + outDirs = append(outDirs, g.OutDir) + + args = append(args, fmt.Sprintf("--%s_out", g.Name), g.OutDir) - for _, opt := range g.opts { - args = append(args, fmt.Sprintf("--%s_opt", g.name), opt) + for _, opt := range g.Opts { + args = append(args, fmt.Sprintf("--%s_opt", g.Name), opt) } } args = append(args, proto...) - return p.Protobuf.Container. - WithMountedDirectory("/src", source). - WithWorkdir("/src"). - WithExec(args). - Stdout(ctx) + return } diff --git a/protobuf/tests/golang.go b/protobuf/tests/golang.go index d014cc6..3dcd777 100644 --- a/protobuf/tests/golang.go +++ b/protobuf/tests/golang.go @@ -7,8 +7,11 @@ package main import ( "context" + "fmt" "dagger/protobuf-tests/internal/dagger" + + "github.com/sourcegraph/conc/pool" ) type Go struct { @@ -18,11 +21,86 @@ type Go struct { func (m *ProtobufTests) Go() *Go { return &Go{ - Protobuf: m.Protobuf.Go().Protobuf(), + Protobuf: m.Protobuf.Go("v1.36.6").Protobuf(), } } func (g *Go) All(ctx context.Context) error { + ep := pool.New().WithErrors().WithContext(ctx) + + ep.Go(g.ProtocTest) + ep.Go(g.ProtocWithWellKnownTypesTest) + ep.Go(g.ProtocWithoutWellKnownTypesTest) + + return ep.Wait() +} + +func (g *Go) ProtocTest(ctx context.Context) error { + dir := g.Protobuf. + Protoc(). + Go("proto-go"). + Compile( + dag.CurrentModule().Source().Directory("testdata"), + []string{"proto/message.proto"}, + ). + Directory("proto-go") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 1 { + return fmt.Errorf("expected only 1 generated file: %v", entries) + } + + return nil +} + +func (g *Go) ProtocWithWellKnownTypesTest(ctx context.Context) error { + dir := g.Protobuf. + Protoc(). + Go("proto-go"). + Compile( + dag.CurrentModule().Source().Directory("testdata"), + []string{"proto/well_known.proto"}, + ). + Directory("proto-go") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 1 { + return fmt.Errorf("expected only 1 generated file: %v", entries) + } + + return nil +} + +func (g *Go) ProtocWithoutWellKnownTypesTest(ctx context.Context) error { + dir := g.Protobuf. + Protoc(). + Go("proto-go"). + Compile( + dag.CurrentModule().Source().Directory("testdata"), + []string{"proto/well_known.proto"}, + dagger.ProtobufProtocCompileOpts{ + ExcludeWellKnownTypes: true, + }, + ). + Directory("proto-go") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 1 { + return fmt.Errorf("expected only 1 generated file: %v", entries) + } + return nil } @@ -33,7 +111,7 @@ type GoGrpc struct { func (m *ProtobufTests) GoGrpc() *GoGrpc { return &GoGrpc{ - Protobuf: m.Protobuf.Go().Grpc().Protobuf(), + Protobuf: m.Protobuf.Go("v1.36.6").Grpc().Protobuf(), } } diff --git a/protobuf/tests/main.go b/protobuf/tests/main.go index a468143..722af52 100644 --- a/protobuf/tests/main.go +++ b/protobuf/tests/main.go @@ -25,5 +25,7 @@ func New( func (m *ProtobufTests) All(ctx context.Context) error { ep := pool.New().WithErrors().WithContext(ctx) + ep.Go(m.Go().All) + return ep.Wait() } diff --git a/protobuf/tests/testdata/proto/message.proto b/protobuf/tests/testdata/proto/message.proto new file mode 100644 index 0000000..e861c15 --- /dev/null +++ b/protobuf/tests/testdata/proto/message.proto @@ -0,0 +1,9 @@ +edition = "2023"; + +package test; + +option go_package = "dagger/protobuf-tests/testdata/protopb"; + +message Hello { + string world = 1; +} \ No newline at end of file diff --git a/protobuf/tests/testdata/proto/well_known.proto b/protobuf/tests/testdata/proto/well_known.proto new file mode 100644 index 0000000..b700707 --- /dev/null +++ b/protobuf/tests/testdata/proto/well_known.proto @@ -0,0 +1,11 @@ +edition = "2023"; + +package test; + +option go_package = "dagger/protobuf-tests/testdata/protopb"; + +import "google/protobuf/timestamp.proto"; + +message WellKnown { + google.protobuf.Timestamp timestamp = 1; +} \ No newline at end of file From 9b3c09a341398d55d83401069aa17d146ed7ac30 Mon Sep 17 00:00:00 2001 From: Richard Carson Derr Date: Sun, 13 Jul 2025 23:50:42 -0400 Subject: [PATCH 4/6] feat(issue-15): install go grpc protoc plugin --- protobuf/golang.go | 42 +++- protobuf/main.go | 8 +- protobuf/tests/golang.go | 180 ++++++++++++++++-- protobuf/tests/main.go | 19 +- protobuf/tests/testdata/proto/service.proto | 17 ++ .../testdata/proto/well_known_service.proto | 20 ++ 6 files changed, 255 insertions(+), 31 deletions(-) create mode 100644 protobuf/tests/testdata/proto/service.proto create mode 100644 protobuf/tests/testdata/proto/well_known_service.proto diff --git a/protobuf/golang.go b/protobuf/golang.go index 6f5c18b..5db6087 100644 --- a/protobuf/golang.go +++ b/protobuf/golang.go @@ -6,7 +6,9 @@ package main import ( + "context" "fmt" + "strings" "dagger/protobuf/internal/dagger" ) @@ -18,15 +20,18 @@ type Go struct { // Install the protoc-gen-go plugin. func (m *Protobuf) Go( version string, -) (*Go, error) { +) *Go { + const name = "protoc-gen-go" + archiveType := "tar.gz" if m.OS == "windows" { archiveType = "zip" } plugin := dag.HTTP(fmt.Sprintf( - "https://github.com/protocolbuffers/protobuf-go/releases/download/%s/protoc-gen-go.%s.%s.%s.%s", + "https://github.com/protocolbuffers/protobuf-go/releases/download/%s/%s.%s.%s.%s.%s", version, + name, version, m.OS, m.Arch, @@ -43,14 +48,11 @@ func (m *Protobuf) Go( }) } - withPlugin, err := m.WithPlugin("protoc-gen-go", dir.File("protoc-gen-go")) - if err != nil { - return nil, err - } + m = m.WithPlugin(name, dir.File(name)) return &Go{ - Protobuf: withPlugin, - }, nil + Protobuf: m, + } } // Generate Go code. @@ -70,8 +72,28 @@ func (p *Protoc) Go( } // Install the protoc-gen-go-grpc plugin. -func (g *Go) Grpc() *Go { - return g +func (g *Go) Grpc( + ctx context.Context, + + // +default="latest" + version string, +) (*Go, error) { + const name = "protoc-gen-go-grpc" + + c := dag.Container(). + From("golang:alpine"). + WithExec([]string{"go", "install", fmt.Sprintf("google.golang.org/grpc/cmd/%s@%s", name, version)}) + + binPath, err := c. + WithExec([]string{"which", name}). + Stdout(ctx) + if err != nil { + return nil, err + } + + g.Protobuf = g.Protobuf.WithPlugin(name, c.File(strings.TrimSpace(binPath))) + + return g, nil } // Generate GRPC Go code. diff --git a/protobuf/main.go b/protobuf/main.go index 3f9de9e..648dd56 100644 --- a/protobuf/main.go +++ b/protobuf/main.go @@ -103,18 +103,14 @@ func mapToProtoArch(arch string) (string, error) { } // Register the given binary file as a protoc plugin. -func (m *Protobuf) WithPlugin(name string, bin *dagger.File) (*Protobuf, error) { - if !strings.HasPrefix(name, "protoc-gen-") { - return nil, errors.New("plugin name must start with: protoc-gen-") - } - +func (m *Protobuf) WithPlugin(name string, bin *dagger.File) *Protobuf { binPath := path.Join("/protobuf/bin", name) m.Container = m.Container. WithFile(binPath, bin). WithExec([]string{"chmod", "+x", binPath}) - return m, nil + return m } // Copy well-known types, protoc, and plugins to the provided container. diff --git a/protobuf/tests/golang.go b/protobuf/tests/golang.go index 3dcd777..8f4ce60 100644 --- a/protobuf/tests/golang.go +++ b/protobuf/tests/golang.go @@ -7,7 +7,9 @@ package main import ( "context" + "errors" "fmt" + "slices" "dagger/protobuf-tests/internal/dagger" @@ -19,9 +21,12 @@ type Go struct { Protobuf *dagger.Protobuf } -func (m *ProtobufTests) Go() *Go { +func (m *ProtobufTests) Go( + // +default="v1.36.6" + version string, +) *Go { return &Go{ - Protobuf: m.Protobuf.Go("v1.36.6").Protobuf(), + Protobuf: m.Protobuf.Go(version).Protobuf(), } } @@ -38,12 +43,15 @@ func (g *Go) All(ctx context.Context) error { func (g *Go) ProtocTest(ctx context.Context) error { dir := g.Protobuf. Protoc(). - Go("proto-go"). + Go("proto-go", dagger.ProtobufProtocGoOpts{ + Opt: []string{"paths=source_relative"}, + }). Compile( dag.CurrentModule().Source().Directory("testdata"), []string{"proto/message.proto"}, ). - Directory("proto-go") + Directory("proto-go"). + Directory("proto") entries, err := dir.Entries(ctx) if err != nil { @@ -51,7 +59,12 @@ func (g *Go) ProtocTest(ctx context.Context) error { } if len(entries) != 1 { - return fmt.Errorf("expected only 1 generated file: %v", entries) + return fmt.Errorf("expected 1 generated file(s): %v", entries) + } + + generatedFileName := entries[0] + if generatedFileName != "message.pb.go" { + return errors.New("unexpected file name for generated file: " + generatedFileName) } return nil @@ -60,12 +73,15 @@ func (g *Go) ProtocTest(ctx context.Context) error { func (g *Go) ProtocWithWellKnownTypesTest(ctx context.Context) error { dir := g.Protobuf. Protoc(). - Go("proto-go"). + Go("proto-go", dagger.ProtobufProtocGoOpts{ + Opt: []string{"paths=source_relative"}, + }). Compile( dag.CurrentModule().Source().Directory("testdata"), []string{"proto/well_known.proto"}, ). - Directory("proto-go") + Directory("proto-go"). + Directory("proto") entries, err := dir.Entries(ctx) if err != nil { @@ -73,7 +89,12 @@ func (g *Go) ProtocWithWellKnownTypesTest(ctx context.Context) error { } if len(entries) != 1 { - return fmt.Errorf("expected only 1 generated file: %v", entries) + return fmt.Errorf("expected 1 generated file(s): %v", entries) + } + + generatedFileName := entries[0] + if generatedFileName != "well_known.pb.go" { + return errors.New("unexpected file name for generated file: " + generatedFileName) } return nil @@ -82,7 +103,9 @@ func (g *Go) ProtocWithWellKnownTypesTest(ctx context.Context) error { func (g *Go) ProtocWithoutWellKnownTypesTest(ctx context.Context) error { dir := g.Protobuf. Protoc(). - Go("proto-go"). + Go("proto-go", dagger.ProtobufProtocGoOpts{ + Opt: []string{"paths=source_relative"}, + }). Compile( dag.CurrentModule().Source().Directory("testdata"), []string{"proto/well_known.proto"}, @@ -90,7 +113,8 @@ func (g *Go) ProtocWithoutWellKnownTypesTest(ctx context.Context) error { ExcludeWellKnownTypes: true, }, ). - Directory("proto-go") + Directory("proto-go"). + Directory("proto") entries, err := dir.Entries(ctx) if err != nil { @@ -98,7 +122,12 @@ func (g *Go) ProtocWithoutWellKnownTypesTest(ctx context.Context) error { } if len(entries) != 1 { - return fmt.Errorf("expected only 1 generated file: %v", entries) + return fmt.Errorf("expected 1 generated file(s): %v", entries) + } + + generatedFileName := entries[0] + if generatedFileName != "well_known.pb.go" { + return errors.New("unexpected file name for generated file: " + generatedFileName) } return nil @@ -109,12 +138,137 @@ type GoGrpc struct { Protobuf *dagger.Protobuf } -func (m *ProtobufTests) GoGrpc() *GoGrpc { +func (m *ProtobufTests) GoGrpc( + // +default="v1.36.6" + goVersion string, + + // +default="latest" + version string, +) *GoGrpc { return &GoGrpc{ - Protobuf: m.Protobuf.Go("v1.36.6").Grpc().Protobuf(), + Protobuf: m.Protobuf.Go(goVersion).Grpc(dagger.ProtobufGoGrpcOpts{ + Version: version, + }).Protobuf(), } } func (g *GoGrpc) All(ctx context.Context) error { + ep := pool.New().WithErrors().WithContext(ctx) + + ep.Go(g.ProtocTest) + ep.Go(g.ProtocWithWellKnownTypesTest) + ep.Go(g.ProtocWithoutWellKnownTypesTest) + + return ep.Wait() +} + +func (g *GoGrpc) ProtocTest(ctx context.Context) error { + dir := g.Protobuf. + Protoc(). + Go("proto-go", dagger.ProtobufProtocGoOpts{ + Opt: []string{"paths=source_relative"}, + }). + GoGrpc("proto-go", dagger.ProtobufProtocGoGrpcOpts{ + Opt: []string{"paths=source_relative"}, + }). + Compile( + dag.CurrentModule().Source().Directory("testdata"), + []string{"proto/service.proto"}, + ). + Directory("proto-go"). + Directory("proto") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 2 { + return fmt.Errorf("expected 2 generated file(s): %v", entries) + } + + if !slices.Contains(entries, "service.pb.go") { + return errors.New("missing generated proto file: service.pb.go") + } + if !slices.Contains(entries, "service_grpc.pb.go") { + return errors.New("missing generated grpc proto file: service_grpc.pb.go") + } + + return nil +} + +func (g *GoGrpc) ProtocWithWellKnownTypesTest(ctx context.Context) error { + dir := g.Protobuf. + Protoc(). + Go("proto-go", dagger.ProtobufProtocGoOpts{ + Opt: []string{"paths=source_relative"}, + }). + GoGrpc("proto-go", dagger.ProtobufProtocGoGrpcOpts{ + Opt: []string{"paths=source_relative"}, + }). + Compile( + dag.CurrentModule().Source().Directory("testdata"), + []string{"proto/well_known_service.proto"}, + dagger.ProtobufProtocCompileOpts{ + ExcludeWellKnownTypes: false, + }, + ). + Directory("proto-go"). + Directory("proto") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 2 { + return fmt.Errorf("expected 2 generated file(s): %v", entries) + } + + if !slices.Contains(entries, "well_known_service.pb.go") { + return errors.New("missing generated proto file: well_known_service.pb.go") + } + if !slices.Contains(entries, "well_known_service_grpc.pb.go") { + return errors.New("missing generated grpc proto file: well_known_service_grpc.pb.go") + } + + return nil +} + +func (g *GoGrpc) ProtocWithoutWellKnownTypesTest(ctx context.Context) error { + dir := g.Protobuf. + Protoc(). + Go("proto-go", dagger.ProtobufProtocGoOpts{ + Opt: []string{"paths=source_relative"}, + }). + GoGrpc("proto-go", dagger.ProtobufProtocGoGrpcOpts{ + Opt: []string{"paths=source_relative"}, + }). + Compile( + dag.CurrentModule().Source().Directory("testdata"), + []string{"proto/well_known_service.proto"}, + dagger.ProtobufProtocCompileOpts{ + ExcludeWellKnownTypes: true, + }, + ). + Directory("proto-go"). + Directory("proto") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 2 { + return fmt.Errorf("expected 2 generated file(s): %v", entries) + } + + if !slices.Contains(entries, "well_known_service.pb.go") { + return errors.New("missing generated proto file: well_known_service.pb.go") + } + if !slices.Contains(entries, "well_known_service_grpc.pb.go") { + return errors.New("missing generated grpc proto file: well_known_service_grpc.pb.go") + } + return nil } diff --git a/protobuf/tests/main.go b/protobuf/tests/main.go index 722af52..37c5fc0 100644 --- a/protobuf/tests/main.go +++ b/protobuf/tests/main.go @@ -11,21 +11,36 @@ import ( type ProtobufTests struct { // +private Protobuf *dagger.Protobuf + + // +private + GoVersion string + + // +private + GoGrpcVersion string } func New( // +default="v31.1" version string, + + // +default="v1.36.6" + goVersion string, + + // +default="latest" + goGrpcVersion string, ) *ProtobufTests { return &ProtobufTests{ - Protobuf: dag.Protobuf(version), + Protobuf: dag.Protobuf(version), + GoVersion: goVersion, + GoGrpcVersion: goGrpcVersion, } } func (m *ProtobufTests) All(ctx context.Context) error { ep := pool.New().WithErrors().WithContext(ctx) - ep.Go(m.Go().All) + ep.Go(m.Go(m.GoVersion).All) + ep.Go(m.GoGrpc(m.GoVersion, m.GoGrpcVersion).All) return ep.Wait() } diff --git a/protobuf/tests/testdata/proto/service.proto b/protobuf/tests/testdata/proto/service.proto new file mode 100644 index 0000000..3fb8b4a --- /dev/null +++ b/protobuf/tests/testdata/proto/service.proto @@ -0,0 +1,17 @@ +edition = "2023"; + +package test; + +option go_package = "dagger/protobuf-tests/testdata/protopb"; + +service Echo { + rpc Echo (Request) returns (Response); +} + +message Request { + string msg = 1; +} + +message Response { + string msg = 1; +} \ No newline at end of file diff --git a/protobuf/tests/testdata/proto/well_known_service.proto b/protobuf/tests/testdata/proto/well_known_service.proto new file mode 100644 index 0000000..85aea82 --- /dev/null +++ b/protobuf/tests/testdata/proto/well_known_service.proto @@ -0,0 +1,20 @@ +edition = "2023"; + +package test; + +option go_package = "dagger/protobuf-tests/testdata/protopb"; + +import "google/protobuf/timestamp.proto"; + +service Echo { + rpc Echo (Request) returns (Response); +} + +message Request { + string msg = 1; + google.protobuf.Timestamp timestamp = 2; +} + +message Response { + string msg = 1; +} \ No newline at end of file From a2e8ae5ec6f8802306d63f7d794ee776f725e5d5 Mon Sep 17 00:00:00 2001 From: Richard Carson Derr Date: Sun, 13 Jul 2025 23:52:09 -0400 Subject: [PATCH 5/6] feat(issue-15): implement copy to --- protobuf/main.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/protobuf/main.go b/protobuf/main.go index 648dd56..10703f0 100644 --- a/protobuf/main.go +++ b/protobuf/main.go @@ -115,5 +115,9 @@ func (m *Protobuf) WithPlugin(name string, bin *dagger.File) *Protobuf { // Copy well-known types, protoc, and plugins to the provided container. func (m *Protobuf) CopyTo(container *dagger.Container) *dagger.Container { - return container + return container. + WithDirectory("/protobuf", m.Container.Directory("/protobuf")). + WithEnvVariable("PATH", "/protobuf/bin/:${PATH}", dagger.ContainerWithEnvVariableOpts{ + Expand: true, + }) } From 3bdd1be8ec92e7563044695f7e1b91ff43c42f74 Mon Sep 17 00:00:00 2001 From: Richard Carson Derr Date: Sun, 13 Jul 2025 23:54:32 -0400 Subject: [PATCH 6/6] test(issue-15): run protobuf tests as part of ci pipeline --- internal/ci/dagger.json | 4 ++++ internal/ci/tests.go | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/ci/dagger.json b/internal/ci/dagger.json index e069f84..b104812 100644 --- a/internal/ci/dagger.json +++ b/internal/ci/dagger.json @@ -12,6 +12,10 @@ { "name": "go-tests", "source": "../../go/tests" + }, + { + "name": "protobuf-tests", + "source": "../../protobuf/tests" } ] } diff --git a/internal/ci/tests.go b/internal/ci/tests.go index 282fd80..f14d4bb 100644 --- a/internal/ci/tests.go +++ b/internal/ci/tests.go @@ -22,11 +22,13 @@ func (m *Ci) Tests() *Tests { func (t *Tests) All(ctx context.Context) error { ep := pool.New().WithErrors().WithContext(ctx) + ep.Go(dag.ArchiveTests().All) + ep.Go(dag.GoTests(dagger.GoTestsOpts{ Version: "latest", }).All) - ep.Go(dag.ArchiveTests().All) + ep.Go(dag.ProtobufTests().All) return ep.Wait() }