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  }