diff --git a/bots-common/consts.go b/bots-common/consts.go index 294f53d..8183ce6 100644 --- a/bots-common/consts.go +++ b/bots-common/consts.go @@ -4,5 +4,7 @@ const ( GiteaTokenEnv = "GITEA_TOKEN" DefaultGitPrj = "_ObsPrj" GiteaRequestHeader = "X-Gitea-Event-Type" + + Bot_BuildReview = "autogits_obs_staging_bot" ) diff --git a/bots-common/gitea_utils.go b/bots-common/gitea_utils.go index 86dc3e9..e9de175 100644 --- a/bots-common/gitea_utils.go +++ b/bots-common/gitea_utils.go @@ -1,6 +1,7 @@ package common import ( + "errors" "io" "os" "path/filepath" @@ -12,19 +13,23 @@ import ( "src.opensuse.org/autogits/common/gitea-generated/models" ) +func (h *RequestHandler) allocateGiteaTransport() *transport.Runtime { + r := transport.New("src.opensuse.org", apiclient.DefaultBasePath, [](string){"https"}) + r.DefaultAuthentication = transport.BearerToken(h.GiteaToken) + // r.SetDebug(true) + return r +} + func (h *RequestHandler) CreateRepositoryIfNotExist(org Organization, repoName string) *models.Repository { if h.HasError() { return nil } - r := transport.New("src.opensuse.org", apiclient.DefaultBasePath, [](string){"https"}) - r.DefaultAuthentication = transport.BearerToken(h.GiteaToken) - // r.SetDebug(true) - client := apiclient.New(r, nil) - + transport := h.allocateGiteaTransport() + client := apiclient.New(transport, nil) repo, err := client.Repository.RepoGet( repository.NewRepoGetParams().WithDefaults().WithOwner(org.Username).WithRepo(repoName), - r.DefaultAuthentication) + transport.DefaultAuthentication) if err != nil { switch err.(type) { @@ -86,3 +91,73 @@ func (h *RequestHandler) CreateRepositoryIfNotExist(org Organization, repoName s return repo.Payload } +func (h *RequestHandler) CreatePullRequest(repo *models.Repository, srcId, targetId string) *models.PullRequest { + if h.HasError() { + return nil + } + + transport := h.allocateGiteaTransport() + client := apiclient.New(transport, nil) + + var prOptions models.CreatePullRequestOption + prOptions.Base = repo.Parent.DefaultBranch + prOptions.Head = srcId + + pr, err := client.Repository.RepoCreatePullRequest( + repository. + NewRepoCreatePullRequestParams(). + WithDefaults(). + WithOwner(repo.Owner.UserName). + WithRepo(repo.Name). + WithBody(&prOptions), + transport.DefaultAuthentication, + ) + + if err != nil { + h.LogError("Cannot create pull request: %v", err) + h.Error = err + } + + if !pr.IsSuccess() { + h.LogError("PR creation failed: %s", pr.Error()) + h.Error = errors.New(pr.Error()) + } + + return pr.GetPayload() +} + +func (h *RequestHandler) RequestReviews(pr *models.PullRequest, reviewer string) []*models.PullReview { + if h.HasError() { + return nil + } + + transport := h.allocateGiteaTransport() + client := apiclient.New(transport, nil) + + var reviewOptions models.PullReviewRequestOptions + reviewOptions.Reviewers = []string{reviewer} + + review, err := client.Repository.RepoCreatePullReviewRequests( + repository. + NewRepoCreatePullReviewRequestsParams(). + WithOwner(pr.Base.Repo.Owner.UserName). + WithRepo(pr.Base.Repo.Name). + WithIndex(pr.Index). + WithBody(&reviewOptions), + transport.DefaultAuthentication, + ) + + if err != nil { + h.LogError("Cannot create pull request: %v", err) + h.Error = err + return nil + } + + if !review.IsSuccess() { + h.LogError("PR creation failed: %s", review.Error()) + h.Error = errors.New(review.Error()) + return nil + } + + return review.GetPayload() +} diff --git a/bots-common/go.mod b/bots-common/go.mod index c09004e..c8382e4 100644 --- a/bots-common/go.mod +++ b/bots-common/go.mod @@ -8,11 +8,12 @@ require ( github.com/go-openapi/strfmt v0.23.0 github.com/go-openapi/swag v0.23.0 github.com/go-openapi/validate v0.24.0 + github.com/oapi-codegen/runtime v1.1.1 ) require ( + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/getkin/kin-openapi v0.124.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.23.0 // indirect @@ -21,25 +22,17 @@ require ( github.com/go-openapi/loads v0.22.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/invopop/yaml v0.2.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/mod v0.17.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.21.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/bots-common/go.sum b/bots-common/go.sum index e37bb45..ab90841 100644 --- a/bots-common/go.sum +++ b/bots-common/go.sum @@ -1,10 +1,12 @@ +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= 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/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M= -github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -34,10 +36,9 @@ 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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= -github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -46,20 +47,17 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 h1:rICjNsHbPP1LttefanBPnwsSwl09SqhCO7Ee623qR84= -github.com/oapi-codegen/oapi-codegen/v2 v2.3.0/go.mod h1:4k+cJeSq5ntkwlcpQSxLxICCxQzCL772o30PxdibRt4= +github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= +github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= -github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= 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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= 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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= @@ -74,21 +72,12 @@ go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucg go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0/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/bots-common/request_repo.go b/bots-common/request_repo.go index 86f0e69..dc8ee47 100644 --- a/bots-common/request_repo.go +++ b/bots-common/request_repo.go @@ -13,7 +13,7 @@ type Repository struct { Full_Name string Fork bool Parent *Repository - Owner *User + Owner *Organization Clone_Url string Ssh_Url string diff --git a/pr-review/main.go b/pr-review/main.go index bb29388..07ba2fd 100644 --- a/pr-review/main.go +++ b/pr-review/main.go @@ -1,38 +1,82 @@ package main import ( + "fmt" + "path" + "src.opensuse.org/autogits/common" ) const ( - ListenPort = 8001 - ListenAddr = "[::1]" + ListenAddr = "[::1]:8001" GitAuthor = "GiteaBot - AutoStaging" PrReview = "pr-review" + ) -func processPullRequest(h *common.RequestHandler) error { +func processPullRequestCreated(h *common.RequestHandler) error { req := h.Data.(common.PullRequestAction) - + // requests against project are not handled here if req.Repository.Name == common.DefaultGitPrj { return nil } + // create PrjGit branch for buidling the pull request + branchName := fmt.Sprintf("PR_%s#%d", req.PullRequest.Repository.Name, req.PullRequest.Number) + commitMsg := fmt.Sprintf(`auto-created for %s + +This commit was autocreated by %s +referencing + +PullRequest: %s#%d`, req.PullRequest.Repository.Name, GitAuthor, req.PullRequest.Repository.Name, req.PullRequest.Number) + + prjGit := h.CreateRepositoryIfNotExist(*req.Repository.Owner, common.DefaultGitPrj) + if h.HasError() { + return h.Error + } + + h.GitExec("", "clone", "--depth", "1", prjGit.SSHURL, common.DefaultGitPrj) + h.GitExec("", "checkout", "-B", branchName, prjGit.DefaultBranch) + h.GitExec(common.DefaultGitPrj, "submodule", "update", "--checkout", "--depth", "1", req.Repository.Name) + h.GitExec(path.Join(common.DefaultGitPrj, req.Repository.Name), "fetch", "--depth", "1", req.PullRequest.Head.Sha) + h.GitExec(path.Join(common.DefaultGitPrj, req.Repository.Name), "checkout", req.PullRequest.Head.Sha) + h.GitExec(common.DefaultGitPrj, "commit", "-a", "-m", commitMsg) + h.GitExec(common.DefaultGitPrj, "push", branchName) + + PR := h.CreatePullRequest(prjGit, branchName, prjGit.DefaultBranch) + if h.HasError() { + return h.Error + } + + // request build review + h.RequestReviews(PR, common.Bot_BuildReview) + return nil } +func processPullRequest(h *common.RequestHandler) error { + req := h.Data.(common.PullRequestAction) + + switch req.Action { + case "created": + return processPullRequestCreated(h) + } + + return fmt.Errorf("Unhandled pull request action: %s", req.Action) +} + func main() { var defs common.ListenDefinitions defs.Url = PrReview defs.GitAuthor = GitAuthor - defs.Handlers=make(map[string]common.RequestProcessor) + defs.Handlers = make(map[string]common.RequestProcessor) defs.Handlers[common.RequestType_PR] = processPullRequest common.RequireGiteaSecretToken() common.RequireObsSecretToken() - common.StartServer(defs) + common.StartServerWithAddress(defs, ListenAddr) }