diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2d09917 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,43 @@ +name: CI + +on: + pull_request: + types: + - "opened" + - "synchronize" + paths-ignore: + - "README.md" + - ".gitignore" + +jobs: + lint: + runs-on: ubuntu-latest + env: + GOPATH: /home/runner/go + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.21 + - name: golangci-lint + uses: golangci/golangci-lint-action@v4 + with: + version: v1.54 + + test: + runs-on: ubuntu-latest + env: + GOPATH: /home/runner/go + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.21 + - name: Test + run: go test -v ./... + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..98b7649 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +# Go parameters +GOCMD=go +GOBUILD=$(GOCMD) build +GOFMT=$(GOCMD) fmt +GOVET=$(GOCMD) vet +GOTEST=$(GOCMD) test +BINARY_NAME=gerrit-translator-cdevents +PKG_DIR=./pkg/ + +all: fmt vet test build + +build: + CGO_ENABLED=0 GOOS=linux $(GOBUILD) -o $(BINARY_NAME) $(PKG_DIR) + +test: + $(GOTEST) -v ./... + +fmt: + $(GOFMT) ./... + +vet: + $(GOVET) ./... + +clean: + rm -f $(BINARY_NAME) diff --git a/README.md b/README.md index 711aaaa..bb3bd07 100644 --- a/README.md +++ b/README.md @@ -1 +1,32 @@ -# gerrit-translator \ No newline at end of file +# Gerrit Translator CDEvents +A translator plugin for translating [Gerrit events](https://gerrit-review.googlesource.com/Documentation/cmd-stream-events.html#events) into [Source Code Control CDEvents](https://cdevents.dev/docs/source-code-version-control/). +This plugin is served using Hashicorp's [go-plugin](https://github.com/hashicorp/go-plugin/). + +The binary of this plugin is published with a release URL and is used by external applications like [cdevents/webhook-adapter](https://github.com/cdevents/webhook-adapter) + +The published plugin's binary can be downloaded and loaded by creating a new plugin client using HashiCorp's go-plugin, which manages the lifecycle of this plugin and establishes the RPC connection. + +### How to build locally +Run the `make` command from the project root directory, which creates a plugin's binary with the name `gerrit-translator-cdevents` +````make +make all +```` + +### Gerrit-CDEvents type mapping for translation +Below are the Gerrit events that currently have mappings with CDEvents and are supported by this translator. + +| CDEvent Type | Gerrit Event Type | +| :------------ |:-------------------| +| dev.cdevents.repository.created| project-created | +| dev.cdevents.repository.modified | project-head-updated | +| dev.cdevents.branch.created | ref-updated | +| dev.cdevents.branch.deleted | ref-updated | +| dev.cdevents.change.created | patchset-created | +| dev.cdevents.change.reviewed | comment-added | +| dev.cdevents.change.merged | change-merged | +| dev.cdevents.change.abandoned | change-abandoned | +| dev.cdevents.change.updated | patchset-created | + + + + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..abf0097 --- /dev/null +++ b/go.mod @@ -0,0 +1,45 @@ +module github.com/cdevents/gerrit-translator + +go 1.22.0 + +replace github.com/cdevents/webhook-adapter => github.com/Nordix/webhook-cdevents-adapter v0.0.0-20240314095508-2cc2c286506d + +require ( + github.com/cdevents/sdk-go v0.3.2 + github.com/cdevents/webhook-adapter v0.0.0-00010101000000-000000000000 + github.com/hashicorp/go-plugin v1.6.0 +) + +require ( + github.com/cloudevents/sdk-go/v2 v2.15.2 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.18.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/package-url/packageurl-go v0.1.2 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect + google.golang.org/grpc v1.62.1 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9b610be --- /dev/null +++ b/go.sum @@ -0,0 +1,119 @@ +github.com/Nordix/webhook-cdevents-adapter v0.0.0-20240314095508-2cc2c286506d h1:Q9qrqKuFI5LkHHdDgc72CPqGHrjsXh2OB/Bnz8ZV9AU= +github.com/Nordix/webhook-cdevents-adapter v0.0.0-20240314095508-2cc2c286506d/go.mod h1:0Rhvovzk4lUTR65yAmxWJH2xmxl52TomCpA4HEn+0bU= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= +github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/cdevents/sdk-go v0.3.2 h1:E9spqXsOCqSDJgKff7IS2pFFx479fC9ocrfBwCZyXJM= +github.com/cdevents/sdk-go v0.3.2/go.mod h1:8bMgOeAIlKTnjGcafMRCKLatA1mEywd0LM6XqJ06eP8= +github.com/cloudevents/sdk-go/v2 v2.15.2 h1:54+I5xQEnI73RBhWHxbI1XJcqOFOVJN85vb41+8mHUc= +github.com/cloudevents/sdk-go/v2 v2.15.2/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= +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/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U= +github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A= +github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/package-url/packageurl-go v0.1.2 h1:0H2DQt6DHd/NeRlVwW4EZ4oEI6Bn40XlNPRqegcxuo4= +github.com/package-url/packageurl-go v0.1.2/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= +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/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +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.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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/pkg/gerrit/create_cdevents.go b/pkg/gerrit/create_cdevents.go new file mode 100644 index 0000000..c057b64 --- /dev/null +++ b/pkg/gerrit/create_cdevents.go @@ -0,0 +1,102 @@ +/* +Copyright (C) 2024 Nordix Foundation. +For a full list of individual contributors, please see the commit history. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +SPDX-License-Identifier: Apache-2.0 +*/ + +package gerrit + +import ( + sdk "github.com/cdevents/sdk-go/pkg/api" +) + +func (projectCreated *ProjectCreated) RepositoryCreatedCDEvent() (string, error) { + Log().Info("Creating CDEvent RepositoryCreatedEvent") + cdEvent, err := sdk.NewRepositoryCreatedEvent() + if err != nil { + Log().Error("Error creating CDEvent RepositoryCreatedEvent %s\n", err) + return "", err + } + cdEvent.SetSource(projectCreated.RepoURL) + cdEvent.SetSubjectName(projectCreated.ProjectName) + cdEvent.SetSubjectId(projectCreated.HeadName) + cdEvent.SetSubjectUrl(projectCreated.RepoURL) + cdEventStr, err := sdk.AsJsonString(cdEvent) + if err != nil { + Log().Error("Error creating RepositoryCreated CDEvent as Json string %s\n", err) + return "", err + } + + return cdEventStr, nil +} + +func (projectHeadUpdated *ProjectHeadUpdated) RepositoryModifiedCDEvent() (string, error) { + Log().Info("Creating CDEvent RepositoryModifiedEvent") + cdEvent, err := sdk.NewRepositoryModifiedEvent() + if err != nil { + Log().Error("Error creating CDEvent RepositoryModified %s\n", err) + return "", err + } + cdEvent.SetSource(projectHeadUpdated.RepoURL) + cdEvent.SetSubjectName(projectHeadUpdated.ProjectName) + cdEvent.SetSubjectId(projectHeadUpdated.NewHead) + cdEvent.SetSubjectUrl(projectHeadUpdated.NewHead) + cdEventStr, err := sdk.AsJsonString(cdEvent) + if err != nil { + Log().Error("Error creating RepositoryModified CDEvent as Json string %s\n", err) + return "", err + } + + return cdEventStr, nil +} + +func (refUpdated *RefUpdated) BranchCreatedCDEvent() (string, error) { + Log().Info("Creating CDEvent BranchCreatedEvent") + cdEvent, err := sdk.NewBranchCreatedEvent() + if err != nil { + Log().Error("Error creating CDEvent BranchCreatedEvent %s\n", err) + return "", err + } + cdEvent.SetSource(refUpdated.RepoURL) + cdEvent.SetSubjectId(refUpdated.RefUpdate.NewRev) + cdEvent.SetSubjectRepository(&sdk.Reference{Id: refUpdated.RefUpdate.RefName}) + cdEvent.SetSubjectSource(refUpdated.RefUpdate.Project) + + cdEventStr, err := sdk.AsJsonString(cdEvent) + if err != nil { + Log().Error("Error creating BranchCreated CDEvent as Json string %s\n", err) + return "", err + } + return cdEventStr, nil +} + +func (refUpdated *RefUpdated) BranchDeletedCDEvent() (string, error) { + Log().Info("Creating CDEvent BranchDeletedEvent") + cdEvent, err := sdk.NewBranchDeletedEvent() + if err != nil { + Log().Error("Error creating CDEvent BranchDeletedEvent %s\n", err) + return "", err + } + cdEvent.SetSource(refUpdated.RepoURL) + cdEvent.SetSubjectId(refUpdated.RefUpdate.OldRev) + cdEvent.SetSubjectRepository(&sdk.Reference{Id: refUpdated.RefUpdate.RefName}) + cdEvent.SetSubjectSource(refUpdated.RefUpdate.Project) + + cdEventStr, err := sdk.AsJsonString(cdEvent) + if err != nil { + Log().Error("Error creating BranchDeleted CDEvent as Json string %s\n", err) + return "", err + } + return cdEventStr, nil +} diff --git a/pkg/gerrit/event.go b/pkg/gerrit/event.go new file mode 100644 index 0000000..e9ebf5a --- /dev/null +++ b/pkg/gerrit/event.go @@ -0,0 +1,84 @@ +/* +Copyright (C) 2024 Nordix Foundation. +For a full list of individual contributors, please see the commit history. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +SPDX-License-Identifier: Apache-2.0 +*/ + +package gerrit + +import ( + "encoding/json" + "fmt" + "net/http" +) + +type GerritEvent struct { + Event string + RepoURL string +} + +func NewGerritEvent(event string, repoURL string) (pEvent *GerritEvent) { + pEvent = &GerritEvent{event, repoURL} + return +} + +func HandleTranslateGerritEvent(event string, header http.Header) (string, error) { + Log().Info("Handle translation into CDEvent from Gerrit event %s\n", event) + repoURL := "" + if header.Get("X-Origin-Url") != "" { + repoURL = header.Get("X-Origin-Url") + } + gerritEvent := NewGerritEvent(event, repoURL) + cdEvent, err := gerritEvent.TranslateIntoCDEvent() + if err != nil { + Log().Error("Error translating Gerrit event into CDEvent %s\n", err) + return "", err + } + Log().Info("Gerrit Event translated into CDEvent %s\n", cdEvent) + return cdEvent, nil +} + +func (pEvent *GerritEvent) TranslateIntoCDEvent() (string, error) { + eventMap := make(map[string]interface{}) + cdEvent := "" + err := json.Unmarshal([]byte(pEvent.Event), &eventMap) + if err != nil { + Log().Error("Error occurred while Unmarshal gerritEvent data into gerritEvent map", err) + return "", err + } + eventType := eventMap["type"] + Log().Info("handling translating to CDEvent from Gerrit Event type: %s\n", eventType) + + switch eventType { + case "project-created": + cdEvent, err = pEvent.HandleProjectCreatedEvent() + if err != nil { + return "", err + } + case "ref-updated": + cdEvent, err = pEvent.HandleRefUpdatedEvent() + if err != nil { + return "", err + } + case "project-head-updated": + cdEvent, err = pEvent.HandleProjectHeadUpdatedEvent() + if err != nil { + return "", err + } + default: + Log().Info("Not handling CDEvent translation for Gerrit event type: %s\n", eventMap["type"]) + return "", fmt.Errorf("gerrit event type %s, not supported for translation", eventType) + } + return cdEvent, nil +} diff --git a/pkg/gerrit/event_types.go b/pkg/gerrit/event_types.go new file mode 100644 index 0000000..0056952 --- /dev/null +++ b/pkg/gerrit/event_types.go @@ -0,0 +1,55 @@ +/* +Copyright (C) 2024 Nordix Foundation. +For a full list of individual contributors, please see the commit history. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +SPDX-License-Identifier: Apache-2.0 +*/ + +package gerrit + +type CommonFields struct { + Type string `json:"type"` + EventCreatedOn float64 `json:"eventCreatedOn"` + RepoURL string `json:"repoURL,omitempty"` +} + +type Submitter struct { + Name string `json:"name"` + Email string `json:"email"` + Username string `json:"username"` +} +type RefUpdate struct { + OldRev string `json:"oldRev"` + NewRev string `json:"newRev"` + RefName string `json:"refName"` + Project string `json:"project"` +} + +// Gerrit event types + +type ProjectCreated struct { + ProjectName string `json:"projectName"` + HeadName string `json:"headName"` + CommonFields +} +type ProjectHeadUpdated struct { + ProjectName string `json:"projectName"` + OldHead string `json:"oldHead"` + NewHead string `json:"newHead"` + CommonFields +} +type RefUpdated struct { + Submitter Submitter `json:"submitter"` + RefUpdate RefUpdate `json:"refUpdate"` + CommonFields +} diff --git a/pkg/gerrit/logger.go b/pkg/gerrit/logger.go new file mode 100644 index 0000000..4f41e7c --- /dev/null +++ b/pkg/gerrit/logger.go @@ -0,0 +1,41 @@ +package gerrit + +import ( + "errors" + "syscall" + + "go.uber.org/zap" +) + +var sugar *zap.SugaredLogger + +// init Initialize a new production zap logger +func init() { + logger, err := zap.NewProduction() + if err != nil { + panic("failed to initialize logger: " + err.Error()) + } + defer func(logger *zap.Logger) { + err := Sync(sugar) + if err != nil { + panic("failed to initialize logger Sync: " + err.Error()) + } + }(logger) + sugar = logger.Sugar() +} + +func Sync(logger *zap.SugaredLogger) error { + err := logger.Sync() + if !errors.Is(err, syscall.EINVAL) { + return err + } + return nil +} + +// Log returns the zap logger If initialized +func Log() *zap.SugaredLogger { + if sugar == nil { + panic("zap logger is not initialized") + } + return sugar +} diff --git a/pkg/gerrit/translate_events.go b/pkg/gerrit/translate_events.go new file mode 100644 index 0000000..b0f73d9 --- /dev/null +++ b/pkg/gerrit/translate_events.go @@ -0,0 +1,83 @@ +/* +Copyright (C) 2024 Nordix Foundation. +For a full list of individual contributors, please see the commit history. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +SPDX-License-Identifier: Apache-2.0 +*/ + +package gerrit + +import ( + "encoding/json" +) + +func (pEvent *GerritEvent) HandleProjectCreatedEvent() (string, error) { + var projectCreated ProjectCreated + err := json.Unmarshal([]byte(pEvent.Event), &projectCreated) + if err != nil { + Log().Error("Error occurred while Unmarshal GerritEvent into ProjectCreated struct", err) + return "", err + } + Log().Info("ProjectCreated GerritEvent received : ", projectCreated.ProjectName, projectCreated.HeadName, projectCreated.CommonFields.Type) + projectCreated.RepoURL = pEvent.RepoURL + cdEvent, err := projectCreated.RepositoryCreatedCDEvent() + if err != nil { + return "", err + } + Log().Info("Translated project-created gerrit event into dev.cdevents.repository.created CDEvent: ", cdEvent) + return cdEvent, nil +} + +func (pEvent *GerritEvent) HandleProjectHeadUpdatedEvent() (string, error) { + var projectHeadUpdated ProjectHeadUpdated + err := json.Unmarshal([]byte(pEvent.Event), &projectHeadUpdated) + if err != nil { + Log().Error("Error occurred while Unmarshal GerritEvent into ProjectHeadUpdated struct", err) + return "", err + } + Log().Info("ProjectHeadUpdated GerritEvent received for project : ", projectHeadUpdated.ProjectName) + projectHeadUpdated.RepoURL = pEvent.RepoURL + cdEvent, err := projectHeadUpdated.RepositoryModifiedCDEvent() + if err != nil { + return "", err + } + Log().Info("Translated project-head-updated gerrit event into dev.cdevents.repository.modified CDEvent: ", cdEvent) + return cdEvent, nil +} + +func (pEvent *GerritEvent) HandleRefUpdatedEvent() (string, error) { + cdEvent := "" + var refUpdated RefUpdated + err := json.Unmarshal([]byte(pEvent.Event), &refUpdated) + if err != nil { + Log().Error("Error occurred while Unmarshal GerritEvent into RefUpdated struct", err) + return "", err + } + Log().Info("RefUpdated GerritEvent received : ", refUpdated.RefUpdate.RefName, refUpdated.Submitter.Name, refUpdated.CommonFields.Type) + refUpdated.RepoURL = pEvent.RepoURL + if refUpdated.RefUpdate.OldRev == "0000000000000000000000000000000000000000" { + cdEvent, err = refUpdated.BranchCreatedCDEvent() + if err != nil { + return "", err + } + Log().Info("Translated ref-updated gerrit event into dev.cdevents.branch.created CDEvent: ", cdEvent) + } else if refUpdated.RefUpdate.NewRev == "0000000000000000000000000000000000000000" { + cdEvent, err = refUpdated.BranchDeletedCDEvent() + if err != nil { + return "", err + } + Log().Info("Translated ref-updated gerrit event into dev.cdevents.branch.deleted CDEvent: ", cdEvent) + } + + return cdEvent, nil +} diff --git a/pkg/translator.go b/pkg/translator.go new file mode 100644 index 0000000..404d8fa --- /dev/null +++ b/pkg/translator.go @@ -0,0 +1,50 @@ +/* +Copyright (C) 2024 Nordix Foundation. +For a full list of individual contributors, please see the commit history. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +SPDX-License-Identifier: Apache-2.0 +*/ + +package main + +import ( + "net/http" + + "github.com/cdevents/gerrit-translator/pkg/gerrit" + "github.com/cdevents/webhook-adapter/pkg/cdevents" + "github.com/hashicorp/go-plugin" +) + +type EventTranslator struct{} + +// TranslateEvent Invoked from external application to translate Gerrit event into CDEvent +func (EventTranslator) TranslateEvent(event string, headers http.Header) (string, error) { + gerrit.Log().Info("Serving from gerrit-translator plugin") + cdEvent, err := gerrit.HandleTranslateGerritEvent(event, headers) + if err != nil { + return "", err + } + return cdEvent, nil +} + +func main() { + plugin.Serve(&plugin.ServeConfig{ + HandshakeConfig: cdevents.Handshake, + Plugins: map[string]plugin.Plugin{ + "gerrit-translator-cdevents": &cdevents.TranslatorGRPCPlugin{Impl: &EventTranslator{}}, + }, + + // A non-nil value here enables gRPC serving for this plugin... + GRPCServer: plugin.DefaultGRPCServer, + }) +}