Skip to content

Commit

Permalink
Merge pull request #57 from vitessio/andrew/cobradocs-sync
Browse files Browse the repository at this point in the history
  • Loading branch information
frouioui authored Oct 5, 2023
2 parents e228035 + d96e6e0 commit 6dadc55
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 22 deletions.
124 changes: 124 additions & 0 deletions go/cobradocs_sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
Copyright 2023 The Vitess Authors.
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.
*/

package main

import (
"context"
"fmt"

"github.com/google/go-github/v53/github"
"github.com/pkg/errors"
"github.com/vitess.io/vitess-bot/go/git"
"github.com/vitess.io/vitess-bot/go/shell"
)

// synchronize cobradocs from main and release branches
func synchronizeCobraDocs(
ctx context.Context,
client *github.Client,
vitess *git.Repo,
website *git.Repo,
pr *github.PullRequest,
prInfo prInformation,
) (*github.PullRequest, error) {
op := "update cobradocs"
branch := "prod"

websiteProdRef, _, err := client.Git.GetRef(ctx, website.Owner, website.Name, "heads/"+branch)
if err != nil {
return nil, errors.Wrapf(err, "Failed to fetch prod ref for repository %s/%s to %s on Pull Request %d", website.Owner, website.Name, op, prInfo.num)
}

newBranch := fmt.Sprintf("synchronize-cobradocs-for-%d", pr.GetNumber())
_, err = website.CreateBranch(ctx, client, websiteProdRef, newBranch)
if err != nil {
return nil, errors.Wrapf(err, "Failed to create git ref %s ref for repository %s/%s to %s on Pull Request %d", newBranch, website.Owner, website.Name, op, prInfo.num)
}

if err := setupRepo(ctx, vitess, prInfo, op); err != nil {
return nil, err
}

if err := vitess.FetchRef(ctx, "origin", "--tags"); err != nil {
return nil, errors.Wrapf(err, "Failed to fetch tags in repository %s/%s to %s on Pull Request %d", vitess.Owner, vitess.Name, op, prInfo.num)
}

if err := setupRepo(ctx, website, prInfo, op); err != nil {
return nil, err
}

// Checkout the new branch we created.
if err := website.Checkout(ctx, newBranch); err != nil {
return nil, errors.Wrapf(err, "Failed to checkout repository %s/%s to branch %s to %s on Pull Request %d", website.Owner, website.Name, newBranch, op, prInfo.num)
}

// Run the sync script (which authors the commit already).
_, err = shell.NewContext(ctx, "./tools/sync_cobradocs.sh").InDir(website.LocalDir).WithExtraEnv(
fmt.Sprintf("VITESS_DIR=%s", vitess.LocalDir),
"COBRADOCS_SYNC_PERSIST=yes",
).Output()
if err != nil {
return nil, errors.Wrapf(err, "Failed to run cobradoc sync script in repository %s/%s to %s on Pull Request %d", website.Owner, website.Name, newBranch, prInfo.num)
}

// TODO: do we need to amend the commit to change the author to the bot?

// Push the branch
if err := website.Push(ctx, git.PushOpts{
Remote: "origin",
Refs: []string{newBranch},
Force: true,
}); err != nil {
return nil, errors.Wrapf(err, "Failed to push %s to %s on Pull Request %d", newBranch, op, prInfo.num)
}

// Create a Pull Request for the new branch
newPR := &github.NewPullRequest{
Title: github.String(fmt.Sprintf("[cobradocs] synchronize with %s (vitess#%d)", pr.GetTitle(), pr.GetNumber())),
Head: github.String(newBranch),
Base: github.String(branch),
Body: github.String(fmt.Sprintf("## Description\nThis is an automated PR to synchronize the cobradocs with %s", pr.GetHTMLURL())),
MaintainerCanModify: github.Bool(true),
}
newPRCreated, _, err := client.PullRequests.Create(ctx, website.Owner, website.Name, newPR)
if err != nil {
return nil, errors.Wrapf(err, "Failed to create Pull Request using branch %s on %s/%s", newBranch, website.Owner, website.Name)
}

return newPRCreated, nil

}

func setupRepo(ctx context.Context, repo *git.Repo, prInfo prInformation, op string) error {
if err := repo.Clone(ctx); err != nil {
return errors.Wrapf(err, "Failed to clone repository %s/%s to %s on Pull Request %d", repo.Owner, repo.Name, op, prInfo.num)
}

if err := repo.Clean(ctx); err != nil {
return errors.Wrapf(err, "Failed to clean the repository %s/%s to %s on Pull Request %d", repo.Owner, repo.Name, op, prInfo.num)
}

if err := repo.Fetch(ctx, "origin"); err != nil {
return errors.Wrapf(err, "Failed to fetch origin on repository %s/%s to %s on Pull Request %d", repo.Owner, repo.Name, op, prInfo.num)
}

if err := repo.ResetHard(ctx, "HEAD"); err != nil {
return errors.Wrapf(err, "Failed to reset the repository %s/%s to %s on Pull Request %d", repo.Owner, repo.Name, op, prInfo.num)
}

return nil
}
20 changes: 5 additions & 15 deletions go/documentation_generation.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,14 @@ import (
const (
errorCodePrefixLabel = "<!-- start -->"
errorCodeSuffixLabel = "<!-- end -->"

rowsPerPage = 100
)

func detectErrorCodeChanges(ctx context.Context, prInfo prInformation, client *github.Client) (bool, error) {
var allFiles []*github.CommitFile
cont := true
for page := 1; cont; page++ {
files, _, err := client.PullRequests.ListFiles(ctx, prInfo.repoOwner, prInfo.repoName, prInfo.num, &github.ListOptions{PerPage: rowsPerPage})
if err != nil {
return false, errors.Wrapf(err, "Failed to list changed files in Pull Request %s/%s#%d - at page %d", prInfo.repoOwner, prInfo.repoName, prInfo.num, page)
}
allFiles = append(allFiles, files...)
if len(files) < rowsPerPage {
cont = false
break
}
func detectErrorCodeChanges(ctx context.Context, vitess *git.Repo, prInfo prInformation, client *github.Client) (bool, error) {
allFiles, err := vitess.ListPRFiles(ctx, client, prInfo.num)
if err != nil {
return false, err
}

for _, file := range allFiles {
if file.GetFilename() == "go/vt/vterrors/code.go" {
return true, nil
Expand Down
46 changes: 46 additions & 0 deletions go/git/pull_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
Copyright 2023 The Vitess Authors.
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.
*/

package git

import (
"context"

"github.com/google/go-github/v53/github"
)

const rowsPerPage = 100

// ListPRFiles returns a list of all files included in a given PR in the repo.
func (r *Repo) ListPRFiles(ctx context.Context, client *github.Client, pr int) (allFiles []*github.CommitFile, err error) {
cont := true
for page := 1; cont; page++ {
files, _, err := client.PullRequests.ListFiles(ctx, r.Owner, r.Name, pr, &github.ListOptions{
PerPage: rowsPerPage
})
if err != nil {
return false, errors.Wrapf(err, "Failed to list changed files in Pull Request %s/%s#%d - at page %d", r.Owner, r.Name, page)
}
allFiles = append(allFiles, files...)
if len(files) < rowsPerPage {
cont = false
break
}
}

return allFiles
}

77 changes: 70 additions & 7 deletions go/pull_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type prInformation struct {
repoName string
merged bool
labels []string
base *github.PullRequestBranch
head *github.PullRequestBranch
}

func getPRInformation(event github.PullRequestEvent) prInformation {
Expand All @@ -98,6 +100,8 @@ func getPRInformation(event github.PullRequestEvent) prInformation {
repoName: repo.GetName(),
merged: merged,
labels: labels,
base: event.GetPullRequest().GetBase(),
head: event.GetPullRequest().GetHead(),
}
}

Expand Down Expand Up @@ -127,6 +131,10 @@ func (h *PullRequestHandler) Handle(ctx context.Context, eventType, deliveryID s
if err != nil {
return err
}
err = h.createDocsPreview(ctx, event, prInfo)
if err != nil {
return err
}
err = h.createErrorDocumentation(ctx, event, prInfo)
if err != nil {
return err
Expand All @@ -139,11 +147,19 @@ func (h *PullRequestHandler) Handle(ctx context.Context, eventType, deliveryID s
if err != nil {
return err
}
err = h.updateDocs(ctx, event, prInfo)
if err != nil {
return err
}
}
case "synchronize":
prInfo := getPRInformation(event)
if prInfo.repoName == "vitess" {
err := h.createErrorDocumentation(ctx, event, prInfo)
err := h.createDocsPreview(ctx, event, prInfo)
if err != nil {
return err
}
err = h.createErrorDocumentation(ctx, event, prInfo)
if err != nil {
return err
}
Expand Down Expand Up @@ -238,8 +254,14 @@ func (h *PullRequestHandler) createErrorDocumentation(ctx context.Context, event
return nil
}

vitess := &git.Repo{
Owner: prInfo.repoOwner,
Name: prInfo.repoName,
LocalDir: filepath.Join(h.Workdir(), "vitess"),
}

logger.Debug().Msgf("Listing changed files in Pull Request %s/%s#%d", prInfo.repoOwner, prInfo.repoName, prInfo.num)
changeDetected, err := detectErrorCodeChanges(ctx, prInfo, client)
changeDetected, err := detectErrorCodeChanges(ctx, vitess, prInfo, client)
if err != nil {
logger.Err(err).Msg(err.Error())
return nil
Expand All @@ -250,11 +272,6 @@ func (h *PullRequestHandler) createErrorDocumentation(ctx context.Context, event
}
logger.Debug().Msgf("Change detect to 'go/vt/vterrors/code.go' in Pull Request %s/%s#%d", prInfo.repoOwner, prInfo.repoName, prInfo.num)

vitess := &git.Repo{
Owner: prInfo.repoOwner,
Name: prInfo.repoName,
LocalDir: filepath.Join(h.Workdir(), "vitess"),
}
h.vitessRepoLock.Lock()
vterrorsgenVitess, err := cloneVitessAndGenerateErrors(ctx, vitess, prInfo)
h.vitessRepoLock.Unlock()
Expand Down Expand Up @@ -372,3 +389,49 @@ func (h *PullRequestHandler) backportPR(ctx context.Context, event github.PullRe

return nil
}

func (h *PullRequestHandler) createDocsPreview(ctx context.Context, event github.PullRequestEvent, prInfo prInformation) error {
// TODO: Checks:
// 1. Is a PR against either:
// - vitessio/vitess:main
// - vitessio/vitess:release-\d+\.\d+
// 2. PR contains changes to either `go/cmd/**/*.go` OR `go/flags/endtoend/*.txt`
return nil
}

func (h *PullRequestHandler) updateDocs(ctx context.Context, event github.PullRequestEvent, prInfo prInformation) (err error) {
installationID := githubapp.GetInstallationIDFromEvent(&event)
client, err := h.NewInstallationClient(installationID)
if err != nil {
return err
}

ctx, logger := githubapp.PreparePRContext(ctx, installationID, prInfo.repo, event.GetNumber())
defer func() {
if e := panicHandler(logger); e != nil {
err = e
}
}()

// TODO: Checks:
// - is vitessio/vitess:main branch OR is vitessio/vitess versioned tag (v\d+\.\d+\.\d+)
// - PR contains changes to either `go/cmd/**/*.go` OR `go/flags/endtoend/*.txt`
if prInfo.base.GetRef() != "main" {
logger.Debug().Msgf("PR %d is merged to %s, not main, skipping website cobradocs sync", prInfo.num, prInfo.base.GetRef())
return nil
}

vitess := &git.Repo{
Owner: prInfo.repoOwner,
Name: prInfo.repoName,
LocalDir: filepath.Join(h.Workdir(), "vitess"),
}
website := &git.Repo{
Owner: prInfo.repoOwner,
Name: "website",
LocalDir: filepath.Join(h.Workdir(), "website"),
}

_, err = synchronizeCobraDocs(ctx, client, vitess, website, event.GetPullRequest(), prInfo)
return err
}

0 comments on commit 6dadc55

Please sign in to comment.