github.com/samcontesse/bitbucket-cascade-merge@v0.0.0-20230227091349-c5ec053235b5/main.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "log" 6 "net/http" 7 "os" 8 "path/filepath" 9 "strings" 10 ) 11 12 func main() { 13 // initialize a buffered channel to process merges one at the time 14 events := make(chan PullRequestEvent, 100) 15 go worker(events) 16 17 // start the hook listener 18 handler := NewEventHandler(events) 19 addr := fmt.Sprintf(":%s", getEnv("PORT", "5000")) 20 http.Handle("/", handler.CheckToken(getEnv("TOKEN", ""), handler.Handle())) 21 err := http.ListenAndServe(addr, nil) 22 if err != nil { 23 log.Fatalf("cannot start server on %s", addr) 24 } 25 26 close(events) 27 } 28 29 func worker(event <-chan PullRequestEvent) { 30 for e := range event { 31 32 // retrieve auth from environment 33 username := getEnv("BITBUCKET_USERNAME", "") 34 password := getEnv("BITBUCKET_PASSWORD", "") 35 36 // get the clone url which is not provided in the webhook 37 api := NewBitbucket(username, password, e.Repository.Owner.UUID, e.Repository.Name) 38 url, err := api.GetCloneURL("https") 39 if err != nil { 40 log.Printf("cannot read clone url of %s (owner=%s): %s", e.Repository.Name, e.Repository.Owner.UUID, err) 41 continue 42 } 43 44 c, err := NewClient(&ClientOptions{ 45 Path: filepath.Join(os.TempDir(), e.Repository.Uuid), 46 URL: url, 47 Credentials: &Credentials{ 48 Username: username, 49 Password: password, 50 }, 51 }) 52 53 if err != nil { 54 log.Printf("failed to initialize git repository: %s", err) 55 } 56 57 // query repository branching model to know which branches are candidate for cascading 58 opts, err := api.GetCascadeOptions(e.Repository.Owner.UUID, e.Repository.Name) 59 if err != nil { 60 log.Printf("cannot detect cascade options for %s, check branching model", e.Repository.Name) 61 continue 62 } 63 64 // check destination branch is candidate for auto merge 65 destination := e.PullRequest.Destination.Branch.Name 66 if strings.HasPrefix(destination, opts.DevelopmentName) && !strings.HasPrefix(destination, opts.ReleasePrefix) { 67 continue 68 } 69 70 // cascade merge the pull request 71 state := c.CascadeMerge(e.PullRequest.Destination.Branch.Name, opts) 72 if state != nil { 73 74 // create a new pull request when cascade fails 75 err := api.CreatePullRequest( 76 "Automatic merge failure", 77 "There was a merge conflict automatically merging this branch", 78 state.Source, 79 state.Target) 80 81 if err != nil { 82 log.Printf("could not create a pull request %s to %s on %s", state.Source, state.Target, e.Repository.Name) 83 } 84 } 85 86 } 87 }