Skip to content

Commit

Permalink
Merge pull request #60 from vitessio/andrew/release-handler
Browse files Browse the repository at this point in the history
  • Loading branch information
frouioui committed Oct 9, 2023
2 parents 5e3ab4c + 88f9f43 commit 3aa03be
Show file tree
Hide file tree
Showing 10 changed files with 617 additions and 35 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ It currently automates the following tasks:
- The suffix following the labels `Backport to: ` or `Forwardport to:` must match the [git branch name](https://github.com/vitessio/vitess/branches/all?query=release-)
- If there is conflict, the backport PR will be created as a draft and a comment will be added to ping the author of the original PR.
- Automatic query serving error code documentation
- Automatic cobra documentation generation for programs:
- If a PR is merged to `main`, a website PR is created automatically.
- If a PR is merged to another branch, nothing is done (yet!).
- When a release is published, a website PR to update the `COBRADOC_VERSION_PAIRS` and regenerate the docs is opened. If an existing sync PR is in-flight, the second PR will be based on that one, and they may be merged in either order.

## Installing the Bot
You can install and configure the bot with the following commands:
Expand Down Expand Up @@ -36,7 +40,7 @@ In order to test the bot locally you will need to create a new GitHub App in htt
- In the `Webhook` section you will need to fill in the `Webhook URL`. You can get this value by running `lt --port 8080` locally, this will print the URL linked to your local environment. Use that URL in the field. You must add `/api/github/hook` after the URL printed by `lt`, to redirect the webhooks to the correct API path (i.e. `https://lazy-frogs-hear.loca.lt/api/github/hook`).
- You also need to set a `Webhook secret` and save its value for later.
- In the section `Permissions`, we need for repository permissions: `Contents` (Read & Write), `Issues` (Read & Write), `Metadata` (Read Only), `Pull requests` (Read & Write)
- In the section `Subscribe to events` select: `Create`, `Issue comment`, `Issues`, `Pull request`, `Push`. Or any other permission depending on what you need for your local dev.
- In the section `Subscribe to events` select: `Create`, `Issue comment`, `Issues`, `Pull request`, `Push`, and `Release`. Or any other permission depending on what you need for your local dev.
- In the section `Where can this GitHub App be installed?`, select `Any account`.
- Click on `Create GitHub App`.

Expand All @@ -49,6 +53,7 @@ Now, create an `.env` file at the root. The file is formatted as follows:
```dotenv
SERVER_ADDRESS=127.0.0.1
REVIEW_CHECKLIST_PATH=./config/review_checklist.txt
BOT_USER_LOGIN=vitess-bot[bot]
PRIVATE_KEY_PATH=.data/<NAME_OF_YOUR_SSH_PRIVATE_KEY_FILE>
GITHUB_APP_INTEGRATION_ID=<SIX_FIGURES_APP_ID>
GITHUB_APP_WEBHOOK_SECRET=<SECRETS_YOU_CREATED_EARLIER>
Expand All @@ -57,4 +62,6 @@ GITHUB_V3_API_URL=https://api.github.com/

Replace the placeholders with the proper values. You will be able to find `GITHUB_APP_INTEGRATION_ID` in the `General` page of your GitHub App under `App ID`.

Note that the `BOT_USER_LOGIN` is the name you gave the App you created above, _plus_ the literal `[bot]` on the end.

Once that is done, you should be able to run the program!
23 changes: 15 additions & 8 deletions go/cobradocs_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ func synchronizeCobraDocs(
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 {
if err := setupRepo(ctx, vitess, fmt.Sprintf("%s on Pull Request %d", op, prInfo.num)); 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 {
if err := setupRepo(ctx, website, fmt.Sprintf("%s on Pull Request %d", op, prInfo.num)); err != nil {
return nil, err
}

Expand All @@ -75,7 +75,14 @@ func synchronizeCobraDocs(
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?
// Amend the commit to change the author to the bot.
if err := website.Commit(ctx, "", git.CommitOpts{
Author: botCommitAuthor,
Amend: true,
NoEdit: true,
}); err != nil {
return nil, errors.Wrapf(err, "Failed to amend commit author to %s on Pull Request %d", op, prInfo.num)
}

// Push the branch
if err := website.Push(ctx, git.PushOpts{
Expand Down Expand Up @@ -103,21 +110,21 @@ func synchronizeCobraDocs(

}

func setupRepo(ctx context.Context, repo *git.Repo, prInfo prInformation, op string) error {
func setupRepo(ctx context.Context, repo *git.Repo, 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)
return errors.Wrapf(err, "Failed to clone repository %s/%s to %s", repo.Owner, repo.Name, op)
}

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)
return errors.Wrapf(err, "Failed to clean the repository %s/%s to %s", repo.Owner, repo.Name, op)
}

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)
return errors.Wrapf(err, "Failed to fetch origin on repository %s/%s to %s", repo.Owner, repo.Name, op)
}

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 errors.Wrapf(err, "Failed to reset the repository %s/%s to %s", repo.Owner, repo.Name, op)
}

return nil
Expand Down
3 changes: 3 additions & 0 deletions go/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
type config struct {
Github githubapp.Config

botLogin string
reviewChecklist string
address string
logFile string
Expand Down Expand Up @@ -63,6 +64,8 @@ func readConfig() (*config, error) {
}
c.reviewChecklist = string(bytes)

c.botLogin = os.Getenv("BOT_USER_LOGIN")

// Get server address
serverAddress := os.Getenv("SERVER_ADDRESS")
if serverAddress == "" {
Expand Down
22 changes: 22 additions & 0 deletions go/git/pull_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@ import (

const rowsPerPage = 100

func (r *Repo) ListPRs(ctx context.Context, client *github.Client, opts github.PullRequestListOptions) (pulls []*github.PullRequest, err error) {
cont := true
for page := 1; cont; page++ {
opts.ListOptions = github.ListOptions{
PerPage: rowsPerPage,
Page: page,
}
prs, _, err := client.PullRequests.List(ctx, r.Owner, r.Name, &opts)
if err != nil {
return nil, errors.Wrapf(err, "Failed to list pull requests in %s/%s - at page %d", r.Owner, r.Name, page)
}

pulls = append(pulls, prs...)
if len(prs) < rowsPerPage {
cont = false
break
}
}

return pulls, nil
}

// 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
Expand Down
12 changes: 12 additions & 0 deletions go/git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ type Repo struct {
LocalDir string
}

func NewRepo(owner, name string) *Repo {
return &Repo{
Owner: owner,
Name: name,
}
}

func (r *Repo) WithLocalDir(dir string) *Repo {
r.LocalDir = dir
return r
}

func (r *Repo) Add(ctx context.Context, arg ...string) error {
_, err := shell.NewContext(ctx, "git", append([]string{"add"}, arg...)...).InDir(r.LocalDir).Output()
return err
Expand Down
7 changes: 6 additions & 1 deletion go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,13 @@ func main() {
panic(err)
}

releaseHandler, err := NewReleaseHandler(cc, cfg.botLogin)
if err != nil {
panic(err)
}

webhookHandler := githubapp.NewEventDispatcher(
[]githubapp.EventHandler{prCommentHandler},
[]githubapp.EventHandler{prCommentHandler, releaseHandler},
cfg.Github.App.WebhookSecret,
githubapp.WithScheduler(
githubapp.AsyncScheduler(),
Expand Down
45 changes: 20 additions & 25 deletions go/pull_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,10 @@ 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"),
}
vitess := git.NewRepo(
prInfo.repoOwner,
prInfo.repoName,
).WithLocalDir(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, vitess, prInfo, client)
Expand All @@ -280,11 +279,10 @@ func (h *PullRequestHandler) createErrorDocumentation(ctx context.Context, event
return nil
}

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

h.websiteRepoLock.Lock()
currentVersionDocs, err := cloneWebsiteAndGetCurrentVersionOfDocs(ctx, website, prInfo)
Expand Down Expand Up @@ -359,11 +357,10 @@ func (h *PullRequestHandler) backportPR(ctx context.Context, event github.PullRe
logger.Debug().Msgf("Will forwardport Pull Request %s/%s#%d to branches %v", prInfo.repoOwner, prInfo.repoName, prInfo.num, forwardportBranches)
}

vitessRepo := &git.Repo{
Owner: prInfo.repoOwner,
Name: prInfo.repoName,
LocalDir: filepath.Join(h.Workdir(), "vitess"),
}
vitessRepo := git.NewRepo(
prInfo.repoOwner,
prInfo.repoName,
).WithLocalDir(filepath.Join(h.Workdir(), "vitess"))
mergedCommitSHA := pr.GetMergeCommitSHA()

for _, branch := range backportBranches {
Expand Down Expand Up @@ -421,11 +418,10 @@ func (h *PullRequestHandler) updateDocs(ctx context.Context, event github.PullRe
return nil
}

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

docChanges, err := detectCobraDocChanges(ctx, vitess, client, prInfo)
if err != nil {
Expand All @@ -437,11 +433,10 @@ func (h *PullRequestHandler) updateDocs(ctx context.Context, event github.PullRe
return nil
}

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

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

0 comments on commit 3aa03be

Please sign in to comment.