Skip to content

Commit

Permalink
feat: impl cherrypicker (#451)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rustin170506 authored Apr 2, 2021
1 parent 9da495c commit 7da4c01
Show file tree
Hide file tree
Showing 10 changed files with 3,114 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ coverage:
status:
project:
default:
# Fail the status if coverage drops by >= 1%
# Fail the status if coverage drops by >= 5%
threshold: 1
18 changes: 18 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ builds:
main: ./cmd/ticommunitycontribution/main.go
env:
- CGO_ENABLED=0
- id: "ti-community-cherrypicker"
binary: ticommunitycherrypicker
goos:
- linux
goarch:
- amd64
main: ./cmd/ticommunitycherrypicker/main.go
env:
- CGO_ENABLED=0
- id: "check-external-plugin-config"
binary: check-external-plugin-config
goos:
Expand Down Expand Up @@ -203,6 +212,15 @@ dockers:
- "ticommunityinfra/tichi-contribution-plugin:{{ .Tag }}"
- "ticommunityinfra/tichi-contribution-plugin:{{ .Major }}"
dockerfile: ./deployments/plugins/contribution/Dockerfile
- binaries:
- ticommunitycherrypicker
builds:
- ti-community-cherrypicker
image_templates:
- "ticommunityinfra/tichi-cherrypicker-plugin:latest"
- "ticommunityinfra/tichi-cherrypicker-plugin:{{ .Tag }}"
- "ticommunityinfra/tichi-cherrypicker-plugin:{{ .Major }}"
dockerfile: ./deployments/plugins/cherrypicker/Dockerfile
-
image_templates:
- "ticommunityinfra/tichi-web:latest"
Expand Down
139 changes: 139 additions & 0 deletions cmd/ticommunitycherrypicker/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package main

import (
"flag"
"fmt"
"net/http"
"os"
"strconv"
"time"

"github.com/sirupsen/logrus"
tiexternalplugins "github.com/ti-community-infra/tichi/internal/pkg/externalplugins"
"github.com/ti-community-infra/tichi/internal/pkg/externalplugins/cherrypicker"
"k8s.io/test-infra/pkg/flagutil"
"k8s.io/test-infra/prow/config/secret"
prowflagutil "k8s.io/test-infra/prow/flagutil"
"k8s.io/test-infra/prow/git/v2"
"k8s.io/test-infra/prow/interrupts"
"k8s.io/test-infra/prow/pjutil"
"k8s.io/test-infra/prow/pluginhelp/externalplugins"
)

type options struct {
port int

dryRun bool
github prowflagutil.GitHubOptions

externalPluginsConfig string

webhookSecretFile string
}

// validate validates github options.
func (o *options) validate() error {
for idx, group := range []flagutil.OptionGroup{&o.github} {
if err := group.Validate(o.dryRun); err != nil {
return fmt.Errorf("%d: %w", idx, err)
}
}

return nil
}

func gatherOptions() options {
o := options{}
fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
fs.IntVar(&o.port, "port", 80, "Port to listen on.")
fs.StringVar(&o.externalPluginsConfig, "external-plugins-config",
"/etc/external_plugins_config/external_plugins_config.yaml", "Path to external plugin config file.")
fs.BoolVar(&o.dryRun, "dry-run", true, "Dry run for testing. Uses API tokens but does not mutate.")
fs.StringVar(&o.webhookSecretFile, "hmac-secret-file",
"/etc/webhook/hmac", "Path to the file containing the GitHub HMAC secret.")

for _, group := range []flagutil.OptionGroup{&o.github} {
group.AddFlags(fs)
}
_ = fs.Parse(os.Args[1:])
return o
}

func main() {
o := gatherOptions()
if err := o.validate(); err != nil {
logrus.Fatalf("Invalid options: %v", err)
}

log := logrus.StandardLogger().WithField("plugin", cherrypicker.PluginName)

epa := &tiexternalplugins.ConfigAgent{}
if err := epa.Start(o.externalPluginsConfig, false); err != nil {
log.WithError(err).Fatalf("Error loading external plugin config from %q.", o.externalPluginsConfig)
}

secretAgent := &secret.Agent{}
if err := secretAgent.Start([]string{o.github.TokenPath, o.webhookSecretFile}); err != nil {
logrus.WithError(err).Fatal("Error starting secrets agent.")
}

githubClient, err := o.github.GitHubClient(secretAgent, o.dryRun)
if err != nil {
logrus.WithError(err).Fatal("Error getting GitHub client.")
}
githubClient.Throttle(360, 360)

gitClient, err := o.github.GitClient(secretAgent, o.dryRun)
if err != nil {
logrus.WithError(err).Fatal("Error getting Git client.")
}
interrupts.OnInterrupt(func() {
if err := gitClient.Clean(); err != nil {
logrus.WithError(err).Error("Could not clean up git client cache.")
}
})

email, err := githubClient.Email()
if err != nil {
log.WithError(err).Fatal("Error getting bot e-mail.")
}

botUser, err := githubClient.BotUser()
if err != nil {
logrus.WithError(err).Fatal("Error getting bot name.")
}

repos, err := githubClient.GetRepos(botUser.Login, true)
if err != nil {
log.WithError(err).Fatal("Error listing bot repositories.")
}

server := &cherrypicker.Server{
TokenGenerator: secretAgent.GetTokenGenerator(o.webhookSecretFile),
BotUser: botUser,
Email: email,
ConfigAgent: epa,

GitClient: git.ClientFactoryFrom(gitClient),
GitHubClient: githubClient,
Log: log,

Bare: &http.Client{},
PatchURL: "https://patch-diff.githubusercontent.com",

Repos: repos,
}

health := pjutil.NewHealth()
health.ServeReady()

mux := http.NewServeMux()
mux.Handle("/", server)

helpProvider := cherrypicker.HelpProvider(epa)
externalplugins.ServeExternalPluginHelp(mux, log, helpProvider)
httpServer := &http.Server{Addr: ":" + strconv.Itoa(o.port), Handler: mux}

defer interrupts.WaitForGracefulShutdown()
interrupts.ListenAndServe(httpServer, 5*time.Second)
}
4 changes: 4 additions & 0 deletions deployments/plugins/cherrypicker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM alpine:3.12
ADD ticommunitycherrypicker /usr/local/bin/
EXPOSE 80
ENTRYPOINT ["/usr/local/bin/ticommunitycherrypicker"]
Loading

0 comments on commit 7da4c01

Please sign in to comment.