Skip to content
This repository was archived by the owner on Apr 17, 2025. It is now read-only.

PLAT-1242 | Do not delete branches that may have a second open PR #1

Merged
merged 3 commits into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ clean:
.PHONY: build
build: clean build-darwin build-linux

build-%:
GOOS=$* GOARCH=386 go build -ldflags '${LDFLAGS}' -o ${PREFIX}${NAME}-$*
build-linux:
GOOS=linux GOARCH=386 go build -ldflags '${LDFLAGS}' -o ${PREFIX}${NAME}-linux

build-darwin:
GOOS=darwin GOARCH=amd64 go build -ldflags '${LDFLAGS}' -o ${PREFIX}${NAME}-darwin

.PHONY: docker
docker:
Expand Down
77 changes: 65 additions & 12 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func (ex *Executor) makeRequest(method string, url string) (res *http.Response,
if err != nil {
return nil, err
}

req.Header.Add("Authorization", "token "+ex.token)
res, _ = ex.client.Do(req)
if res.StatusCode >= 400 {
Expand All @@ -92,7 +93,7 @@ func (ex *Executor) listClosedPullRequests(user string, repo string, days int) (
res, err := ex.makeRequest("GET", "repos/"+user+"/"+repo+"/pulls?state=closed&sort=updated&direction=desc&per_page=100&page="+strconv.Itoa(page))

if err != nil {
return pullRequests, errors.New("failed to get pull requests (" + err.Error() + ")")
return pullRequests, errors.New("failed to get closed pull requests (" + err.Error() + ")")
}

d := json.NewDecoder(res.Body)
Expand All @@ -102,7 +103,7 @@ func (ex *Executor) listClosedPullRequests(user string, repo string, days int) (
err = d.Decode(&prs.PullRequests)

if err != nil {
return pullRequests, errors.New("failed to parse pull requests (" + err.Error() + ")")
return pullRequests, errors.New("failed to parse closed pull requests (" + err.Error() + ")")
}

for _, pr := range prs.PullRequests {
Expand All @@ -122,6 +123,36 @@ func (ex *Executor) listClosedPullRequests(user string, repo string, days int) (
return pullRequests, nil
}

func (ex *Executor) listOpenPullRequests(user string, repo string) ([]pullRequest, error) {
pullRequests := make([]pullRequest, 0, 1)

for page, keepGoing := 1, true; keepGoing; page++ {
res, err := ex.makeRequest("GET", "repos/"+user+"/"+repo+"/pulls?state=open&sort=updated&direction=desc&per_page=100&page="+strconv.Itoa(page))

if err != nil {
return pullRequests, errors.New("failed to get open pull requests (" + err.Error() + ")")
}

d := json.NewDecoder(res.Body)
var prs struct {
PullRequests []pullRequest
}
err = d.Decode(&prs.PullRequests)

if err != nil {
return pullRequests, errors.New("failed to parse open pull requests (" + err.Error() + ")")
}

pullRequests = append(pullRequests, prs.PullRequests...)

if len(prs.PullRequests) == 0 || len(prs.PullRequests) < 100 {
break
}
}

return pullRequests, nil
}

func (ex *Executor) listUnprotectedBranches(user string, repo string) ([]branch, error) {
branches := make([]branch, 0, 1)

Expand Down Expand Up @@ -174,18 +205,33 @@ func (ex *Executor) deleteBranches(user string, repo string, branches []string)
return deletedBranches, nil
}

func getStaleBranches(branches []branch, pullRequests []pullRequest) []string {
branchesByName := make(map[string]branch)
staleBranches := make([]string, 0, 1)
func getStaleBranches(closedBranches []branch, closedPullRequests []pullRequest, openPullRequests []pullRequest) []string {
branchShaMap := make(map[string]string) // Map[branch_name]branch_SHA
staleBranchMap := make(map[string]bool) // Map[branch_name]is_stale

for _, b := range closedBranches {
branchShaMap[b.Name] = b.Commit.SHA
}

for _, pr := range closedPullRequests {
staleBranchSHA, branchExists := branchShaMap[pr.Head.Ref]
if branchExists && staleBranchSHA == pr.Head.SHA {
staleBranchMap[pr.Head.Ref] = true
}
}

for _, b := range branches {
branchesByName[b.Name] = b
// If we've marked this branch as stale, but there is another open PR tied to the branch, unmark as stale
for _, pr := range openPullRequests {
_, branchExists := staleBranchMap[pr.Head.Ref]
if branchExists {
staleBranchMap[pr.Head.Ref] = false
}
}

for _, pr := range pullRequests {
staleBranch, branchExists := branchesByName[pr.Head.Ref]
if branchExists && staleBranch.Commit.SHA == pr.Head.SHA {
staleBranches = append(staleBranches, pr.Head.Ref)
staleBranches := make([]string, 0, 1)
for branch, isStale := range staleBranchMap {
if isStale {
staleBranches = append(staleBranches, branch)
}
}

Expand Down Expand Up @@ -269,11 +315,18 @@ func Run(user string, repo string, days int, ex Executor) error {
if err != nil {
return err
}

openPullRequests, err := ex.listOpenPullRequests(user, repo)
if err != nil {
return err
}

unprotectedBranches, err := ex.listUnprotectedBranches(user, repo)
if err != nil {
return err
}
staleBranches := getStaleBranches(unprotectedBranches, closedPullRequests)

staleBranches := getStaleBranches(unprotectedBranches, closedPullRequests, openPullRequests)
db, err := ex.deleteBranches(user, repo, staleBranches)
if err != nil {
return err
Expand Down
22 changes: 22 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,28 @@ func TestRun(t *testing.T) {
"ref": "stalebranch",
"sha": "1761e021e70d29619ca270046b23bd243f652b98"
}
},
{
"number": 2,
"updated_at": "` + now.Format(time.RFC3339) + `",
"head": {
"ref": "notstalebranch",
"sha": "867530990210abcdefg867530990210abcdefg"
}
}
]`,
},
mockHTTPResponse{
method: "GET",
URL: "/repos/user/repo/pulls?state=open&sort=updated&direction=desc&per_page=100&page=1",
body: `[
{
"number": 2,
"updated_at": "` + now.Format(time.RFC3339) + `",
"head": {
"ref": "notstalebranch",
"sha": "867530990210abcdefg867530990210abcdefg"
}
}
]`,
},
Expand Down