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() } 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..55de386 --- /dev/null +++ b/protobuf/dagger.json @@ -0,0 +1,13 @@ +{ + "name": "protobuf", + "engineVersion": "v0.18.12", + "sdk": { + "source": "go" + }, + "dependencies": [ + { + "name": "archive", + "source": "../archive" + } + ] +} 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..5db6087 --- /dev/null +++ b/protobuf/golang.go @@ -0,0 +1,113 @@ +// Copyright (c) 2025 Z5Labs and Contributors +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +package main + +import ( + "context" + "fmt" + "strings" + + "dagger/protobuf/internal/dagger" +) + +type Go struct { + Protobuf *Protobuf +} + +// Install the protoc-gen-go plugin. +func (m *Protobuf) Go( + version string, +) *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/%s.%s.%s.%s.%s", + version, + name, + version, + m.OS, + m.Arch, + archiveType, + )) + + 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, + }) + } + + m = m.WithPlugin(name, dir.File(name)) + + return &Go{ + Protobuf: m, + } +} + +// 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, + }) + + return p +} + +// Install the protoc-gen-go-grpc plugin. +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. +func (p *Protoc) GoGrpc( + outDir string, + + // +optional + 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..10703f0 --- /dev/null +++ b/protobuf/main.go @@ -0,0 +1,123 @@ +// 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" + "path" + "strings" + + "dagger/protobuf/internal/dagger" + + "github.com/containerd/platforms" +) + +type Protobuf struct { + Container *dagger.Container + + // +private + OS string + + // +private + Arch string +} + +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, + OS: p.OS, + Arch: p.Architecture, + }, 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, + )) + + dir := dag.Archive().Zip().Extract(protoc) + + c := dag.Container(). + From("alpine"). + WithDirectory("/protobuf", dir). + WithEnvVariable("PATH", "/protobuf/bin/:${PATH}", dagger.ContainerWithEnvVariableOpts{ + Expand: true, + }). + WithExec([]string{"chmod", "+x", "/protobuf/bin/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 { + binPath := path.Join("/protobuf/bin", name) + + m.Container = m.Container. + WithFile(binPath, bin). + WithExec([]string{"chmod", "+x", binPath}) + + return m +} + +// Copy well-known types, protoc, and plugins to the provided container. +func (m *Protobuf) CopyTo(container *dagger.Container) *dagger.Container { + return container. + WithDirectory("/protobuf", m.Container.Directory("/protobuf")). + WithEnvVariable("PATH", "/protobuf/bin/:${PATH}", dagger.ContainerWithEnvVariableOpts{ + Expand: true, + }) +} diff --git a/protobuf/protoc.go b/protobuf/protoc.go new file mode 100644 index 0000000..73d20fa --- /dev/null +++ b/protobuf/protoc.go @@ -0,0 +1,103 @@ +// Copyright (c) 2025 Z5Labs and Contributors +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +package main + +import ( + "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( + source *dagger.Directory, + + proto []string, + + // Specify the directory in which to search for imports. + // +default=["."] + includePath []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 !excludeWellKnownTypes { + args = append(args, "-I", "/protobuf/include/") + } + + for _, p := range includePath { + args = append(args, "-I", p) + } + + 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) + } + } + + args = append(args, proto...) + + return +} 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..8f4ce60 --- /dev/null +++ b/protobuf/tests/golang.go @@ -0,0 +1,274 @@ +// 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" + "slices" + + "dagger/protobuf-tests/internal/dagger" + + "github.com/sourcegraph/conc/pool" +) + +type Go struct { + // +private + Protobuf *dagger.Protobuf +} + +func (m *ProtobufTests) Go( + // +default="v1.36.6" + version string, +) *Go { + return &Go{ + Protobuf: m.Protobuf.Go(version).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", dagger.ProtobufProtocGoOpts{ + Opt: []string{"paths=source_relative"}, + }). + Compile( + dag.CurrentModule().Source().Directory("testdata"), + []string{"proto/message.proto"}, + ). + Directory("proto-go"). + Directory("proto") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 1 { + 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 +} + +func (g *Go) ProtocWithWellKnownTypesTest(ctx context.Context) error { + dir := g.Protobuf. + Protoc(). + 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") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 1 { + 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 +} + +func (g *Go) ProtocWithoutWellKnownTypesTest(ctx context.Context) error { + dir := g.Protobuf. + Protoc(). + Go("proto-go", dagger.ProtobufProtocGoOpts{ + Opt: []string{"paths=source_relative"}, + }). + Compile( + dag.CurrentModule().Source().Directory("testdata"), + []string{"proto/well_known.proto"}, + dagger.ProtobufProtocCompileOpts{ + ExcludeWellKnownTypes: true, + }, + ). + Directory("proto-go"). + Directory("proto") + + entries, err := dir.Entries(ctx) + if err != nil { + return err + } + + if len(entries) != 1 { + 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 +} + +type GoGrpc struct { + // +private + Protobuf *dagger.Protobuf +} + +func (m *ProtobufTests) GoGrpc( + // +default="v1.36.6" + goVersion string, + + // +default="latest" + version string, +) *GoGrpc { + return &GoGrpc{ + 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 new file mode 100644 index 0000000..37c5fc0 --- /dev/null +++ b/protobuf/tests/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "context" + + "dagger/protobuf-tests/internal/dagger" + + "github.com/sourcegraph/conc/pool" +) + +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), + GoVersion: goVersion, + GoGrpcVersion: goGrpcVersion, + } +} + +func (m *ProtobufTests) All(ctx context.Context) error { + ep := pool.New().WithErrors().WithContext(ctx) + + 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/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/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.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 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