зеркало из https://github.com/Azure/spec-sla-bot.git
Resolved service bus delay
This commit is contained in:
Родитель
cae05ad228
Коммит
ab7be770af
|
@ -4,8 +4,8 @@
|
|||
[[projects]]
|
||||
name = "cloud.google.com/go"
|
||||
packages = ["civil"]
|
||||
revision = "aad3f485ee528456e0768f20397b4d9dd941e755"
|
||||
version = "v0.25.0"
|
||||
revision = "64a2037ec6be8a4b0c1d1f706ed35b428b989239"
|
||||
version = "v0.26.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -36,8 +36,8 @@
|
|||
"services/servicebus/mgmt/2017-04-01/servicebus",
|
||||
"version"
|
||||
]
|
||||
revision = "fad8443a79b0e755c18c3bec29a8d2bedab0b421"
|
||||
version = "v15.3.0"
|
||||
revision = "4e8cbbfb1aeab140cd0fa97fd16b64ee18c3ca6a"
|
||||
version = "v19.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Azure/azure-service-bus-go"
|
||||
|
@ -45,8 +45,7 @@
|
|||
".",
|
||||
"atom"
|
||||
]
|
||||
revision = "88613d3356e8ce24659eb44cc5bd6a34e250703a"
|
||||
version = "v0.1.0"
|
||||
revision = "4eb9c25e4b2f11d1bfab85cd415c3d703f7358ba"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Azure/buffalo-azure"
|
||||
|
@ -560,7 +559,7 @@
|
|||
"md4",
|
||||
"ssh/terminal"
|
||||
]
|
||||
revision = "80fca2ff14a3fb7db622c9a5462f8ce9ea026cba"
|
||||
revision = "f027049dab0ad238e394a753dba2d14753473a04"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -570,7 +569,7 @@
|
|||
"html",
|
||||
"html/atom"
|
||||
]
|
||||
revision = "f4c29de78a2a91c00474a2e689954305c350adf9"
|
||||
revision = "19491d39cadbd9cd33f26ca22cc89ba4ba38251c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -585,7 +584,7 @@
|
|||
"unix",
|
||||
"windows"
|
||||
]
|
||||
revision = "2be389f392cd91df245b41638f818a1c041f0c08"
|
||||
revision = "acbc56fc7007d2a01796d5bde54f39e3b3e95945"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/appengine"
|
||||
|
@ -628,6 +627,6 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "69ab168166b6ab604139c01a8547de8f0893dce5490dd00b9edd4a4a840fbd75"
|
||||
inputs-digest = "0868c77c0d85e31091d756abe875eb679d8521106e70cafbdcd032a252e0b0d3"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
[[constraint]]
|
||||
name = "github.com/Azure/azure-service-bus-go"
|
||||
version = "0.1.0"
|
||||
revision = "4eb9c25e4b2f11d1bfab85cd415c3d703f7358ba"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Azure/buffalo-azure"
|
||||
|
|
|
@ -2,7 +2,6 @@ package actions
|
|||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/gobuffalo/buffalo"
|
||||
|
@ -64,7 +63,6 @@ func App() *buffalo.App {
|
|||
|
||||
//Subscribe to eventgrid
|
||||
eventgrid.RegisterSubscriber(app, "/specgithub", NewSpecgithubSubscriber(&eventgrid.BaseSubscriber{}))
|
||||
log.Printf("Created handler")
|
||||
//Create AMQP Listener
|
||||
messages.ReceiveFromQueue(context.Background(), os.Getenv("CUSTOMCONNSTR_SERVICEBUS_CONNECTION_STRING"))
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ func (s *SpecgithubSubscriber) ReceivePullRequestEvent(c buffalo.Context, e even
|
|||
if err := json.Unmarshal(e.Data, &payload); err != nil {
|
||||
return c.Error(http.StatusBadRequest, errors.New("unable to unmarshal request data"))
|
||||
}
|
||||
messages.CheckAcknowledgement(payload)
|
||||
messages.CheckAcknowledgement(c, payload)
|
||||
|
||||
// Replace the code below with your logic
|
||||
return c.Render(200, render.JSON(map[string]string{"message": "Hopefully this works"}))
|
||||
|
@ -53,7 +53,7 @@ func (s *SpecgithubSubscriber) ReceiveIssueCommentEvent(c buffalo.Context, e eve
|
|||
return c.Error(http.StatusBadRequest, errors.New("unable to unmarshal request data"))
|
||||
}
|
||||
c.Logger().Debug("Check acknowledgement of comment on PR")
|
||||
messages.CheckAcknowledgementComment(payload)
|
||||
messages.CheckAcknowledgementComment(c, payload)
|
||||
|
||||
// Replace the code below with your logic
|
||||
return c.Render(200, render.JSON(map[string]string{"message": "Hopefully this works"}))
|
||||
|
@ -67,7 +67,7 @@ func (s *SpecgithubSubscriber) ReceiveLabelEvent(c buffalo.Context, e eventgrid.
|
|||
return c.Error(http.StatusBadRequest, errors.New("unable to unmarshal request data"))
|
||||
}
|
||||
c.Logger().Debug("Check acknowledgement of comment on PR")
|
||||
messages.CheckAcknowledgementLabel(payload)
|
||||
messages.CheckAcknowledgementLabel(c, payload)
|
||||
|
||||
// Replace the code below with your logic
|
||||
return c.Render(200, render.JSON(map[string]string{"message": "Hopefully this works"}))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
development:
|
||||
url: {{env "CUSTOMCONNSTR_DATABASE_URL"}}
|
||||
url: {{envOr "CUSTOMCONNSTR_DATABASE_URL" "postgres://postgres:postgres@127.0.0.1:5432/spec_sla_bot_test?sslmode=disable"}}
|
||||
|
||||
test:
|
||||
url: {{envOr "TEST_DATABASE_URL" "postgres://postgres:postgres@127.0.0.1:5432/spec_sla_bot_test?sslmode=disable"}}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package messages
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
@ -13,61 +15,114 @@ import (
|
|||
"github.com/google/go-github/github"
|
||||
)
|
||||
|
||||
var currentExpireTime time.Time
|
||||
//SLAQueue name
|
||||
const SLAQueue = "24hrgitevents"
|
||||
|
||||
func CheckAcknowledgement(event github.PullRequestEvent) {
|
||||
if checkClosed(event, models.DB) || checkUnassigned(event, models.DB) || (event.PullRequest.Assignee == nil && checkOpened(event, models.DB)) {
|
||||
err := UpsertPullRequestEntry(event, models.DB, false, time.Time{})
|
||||
//MessageContent sent to service bus
|
||||
type MessageContent struct {
|
||||
PRID int64
|
||||
HTMLURL string
|
||||
//This should be an array due to the potential of multiple assignees
|
||||
AssigneeLogin string
|
||||
ManagerEmailReminder bool
|
||||
}
|
||||
|
||||
//CheckAcknowledgement determines if a PullRequestEvent is a valid acknowledment of a PR
|
||||
func CheckAcknowledgement(ctx context.Context, event github.PullRequestEvent) error {
|
||||
if checkClosed(ctx, event, models.DB) || checkUnassigned(ctx, event, models.DB) || (event.PullRequest.Assignee == nil && checkOpened(ctx, event, models.DB)) {
|
||||
err := UpsertPullRequestEntry(ctx, event, models.DB, false, time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in CheckAcknowledged", *event.Number)
|
||||
return fmt.Errorf("unable to update event number %d in CheckAcknowledgement", *event.Number)
|
||||
}
|
||||
} else if event.PullRequest.Assignee != nil && (checkAssigned(event, models.DB) || checkReviewed(event, models.DB) || checkEdited(event, models.DB) || checkLabeled(event, models.DB) || checkOpened(event, models.DB)) {
|
||||
message := fmt.Sprintf("PR id, %d, URL, %s, Assignee, %s", *event.PullRequest.ID, *event.PullRequest.HTMLURL, *event.PullRequest.Assignee.Login)
|
||||
log.Print(message)
|
||||
err := SendToQueue(message, currentExpireTime)
|
||||
log.Print("SENT TO QUEUE")
|
||||
} else if event.PullRequest.Assignee != nil && (checkAssigned(ctx, event, models.DB) ||
|
||||
checkReviewed(ctx, event, models.DB) ||
|
||||
checkEdited(ctx, event, models.DB) ||
|
||||
checkLabeled(ctx, event, models.DB) ||
|
||||
checkOpened(ctx, event, models.DB)) {
|
||||
messageStruct := MessageContent{
|
||||
PRID: *event.PullRequest.ID,
|
||||
HTMLURL: *event.PullRequest.HTMLURL,
|
||||
AssigneeLogin: *event.PullRequest.Assignee.Login,
|
||||
ManagerEmailReminder: false,
|
||||
}
|
||||
message, err := json.Marshal(messageStruct)
|
||||
if err != nil {
|
||||
fmt.Errorf("Unable to Marshal message struct for PR %d", *event.PullRequest.ID)
|
||||
return err
|
||||
}
|
||||
err = SendToQueue(ctx, message, expireTime(time.Now()), SLAQueue)
|
||||
if err != nil {
|
||||
log.Printf("Message for event %d not delivered", *event.PullRequest.ID)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckAcknowledgementComment(event github.IssueCommentEvent) {
|
||||
log.Print("CONNECT TO DEVELOPEMENT DB")
|
||||
tx, err := pop.Connect("developement")
|
||||
if err != nil {
|
||||
log.Printf("Could not connect to the developement database")
|
||||
} else if event.Issue != nil && event.Issue.IsPullRequest() && checkCommented(event, tx) {
|
||||
message := fmt.Sprintf("PR id, %d, URL, %s, Assignee, %s", *event.Issue.ID, *event.Issue.URL, *event.Issue.Assignee.Login)
|
||||
log.Print(message)
|
||||
err = SendToQueue(message, currentExpireTime)
|
||||
log.Print("SENT TO QUEUE")
|
||||
//CheckAcknowledgementComment determines if an IssuesCommentEvent on a PR is a valid acknowledgement
|
||||
func CheckAcknowledgementComment(ctx context.Context, event github.IssueCommentEvent) error {
|
||||
if event.Issue != nil && event.Issue.IsPullRequest() && checkCommented(ctx, event, models.DB) {
|
||||
assignees := event.Issue.Assignees
|
||||
for _, assignee := range assignees {
|
||||
id, err := uuid.NewV1()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q := models.DB.RawQuery(`INSERT INTO assignees (id, created_at, updated_at, login, type, html_url)
|
||||
VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT (login) DO UPDATE SET html_url = ?`,
|
||||
id, time.Now(), time.Now(), assignee.Login, assignee.Type, assignee.HTMLURL, assignee.HTMLURL)
|
||||
exErr := q.Exec()
|
||||
if exErr != nil {
|
||||
log.Println("Unable to update event in checkAssigned")
|
||||
return exErr
|
||||
}
|
||||
}
|
||||
messageStruct := MessageContent{
|
||||
PRID: *event.Issue.ID,
|
||||
HTMLURL: *event.Issue.HTMLURL,
|
||||
AssigneeLogin: *event.Issue.Assignee.Login,
|
||||
}
|
||||
message, err := json.Marshal(messageStruct)
|
||||
if err != nil {
|
||||
log.Printf("Message for event %d not delivered", *event.Issue.ID)
|
||||
fmt.Errorf("Unable to Marshal message struct for PR %d", *event.Issue.ID)
|
||||
return err
|
||||
}
|
||||
err = SendToQueue(ctx, message, expireTime(time.Now()), SLAQueue)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Message for event %d not delivered: %v", *event.Issue.ID, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckAcknowledgementLabel(event github.LabelEvent) {
|
||||
log.Printf("Logic to handle a label event not implemented")
|
||||
//CheckAcknowledgementLabel determines if a LabelEvent on a PR is a valid acknowledgement
|
||||
func CheckAcknowledgementLabel(ctx context.Context, event github.LabelEvent) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func updateTime() time.Time {
|
||||
currentTime := time.Now()
|
||||
//ExpireTime calculates the time a PR could violate the SLA depending on the current time
|
||||
func expireTime(currentTime time.Time) time.Time {
|
||||
//return currentTime.Add(slaDuration(currentTime.Weekday()))
|
||||
return currentTime.Add(time.Minute * 2)
|
||||
}
|
||||
|
||||
//slaDuration returns the amount of time an assignee has to respond to a PR given the day
|
||||
func slaDuration(day time.Weekday) time.Duration {
|
||||
delay := 24 * time.Hour
|
||||
|
||||
//Adjusted time for now for testing purposes
|
||||
//if the current weekday is Friday
|
||||
if int(currentTime.Weekday()) == 5 {
|
||||
currentExpireTime := currentTime.Add(time.Minute * time.Duration(1))
|
||||
return currentExpireTime
|
||||
if day > time.Thursday {
|
||||
delay = time.Duration(8-day) * time.Hour * 24
|
||||
}
|
||||
currentExpireTime := currentTime.Add(time.Minute * time.Duration(1))
|
||||
return currentExpireTime
|
||||
return delay
|
||||
}
|
||||
|
||||
func checkCommented(event github.IssueCommentEvent, tx *pop.Connection) bool {
|
||||
//CheckCommented determines if the comment on the PR was valid
|
||||
func checkCommented(ctx context.Context, event github.IssueCommentEvent, tx *pop.Connection) bool {
|
||||
//check that the issue is not nil and that the issue id is a pr id in the db
|
||||
if event.Issue != nil && event.Issue.Assignee != nil && event.Sender != nil && event.Sender.Login != nil {
|
||||
expireTime := updateTime()
|
||||
expireTime := expireTime(time.Now())
|
||||
validTime := true
|
||||
//Check if the right person assignee commented
|
||||
prs := []models.Pullrequest{}
|
||||
|
@ -93,49 +148,43 @@ func checkCommented(event github.IssueCommentEvent, tx *pop.Connection) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func checkAssigned(event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
//CheckAssigned Determines if the PullRequestEvent action was assigneed and if the assignement was valid
|
||||
func checkAssigned(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "assigned") {
|
||||
expireTime := updateTime()
|
||||
expireTime := expireTime(time.Now())
|
||||
validTime := false
|
||||
if event.PullRequest != nil && event.PullRequest.Assignees != nil {
|
||||
validTime = true
|
||||
}
|
||||
err := UpsertPullRequestEntry(event, tx, validTime, expireTime)
|
||||
err := UpsertPullRequestEntry(ctx, event, tx, validTime, expireTime)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
//Add new assignee if it does not exist in the repo
|
||||
if event.PullRequest != nil && event.PullRequest.Assignees != nil {
|
||||
assignees := event.PullRequest.Assignees
|
||||
for _, assignee := range assignees {
|
||||
id, err := uuid.NewV1()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
q := tx.RawQuery(`INSERT INTO assignees (id, created_at, updated_at, login, type, html_url)
|
||||
VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT (login) DO UPDATE SET html_url = ?`,
|
||||
id, time.Now(), time.Now(), assignee.Login, assignee.Type, assignee.HTMLURL, assignee.HTMLURL)
|
||||
exErr := q.Exec()
|
||||
if exErr != nil {
|
||||
log.Print(exErr)
|
||||
log.Printf("Unable to update event number %d in checkAssigned", *event.Number)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
err = AddAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
err = AddPullrequestAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkUnassigned(event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
//CheckUnassigned Determines if the PullRequestEvent action was unassigned and updates the database accordingly
|
||||
func checkUnassigned(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "unassigned") {
|
||||
//Update PR in DB to no longer accept messages until assigned
|
||||
//if the assignee is nil update the expire time to be invalid
|
||||
validTime := false
|
||||
expireTime := time.Time{}
|
||||
if event.PullRequest != nil && event.Number != nil {
|
||||
err := UpsertPullRequestEntry(event, tx, validTime, expireTime)
|
||||
err := UpsertPullRequestEntry(ctx, event, tx, validTime, expireTime)
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in checkUnassigned", *event.Number)
|
||||
return false
|
||||
|
@ -146,39 +195,29 @@ func checkUnassigned(event github.PullRequestEvent, tx *pop.Connection) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func checkReviewed(event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
//CheckAssigned Determines if the PullRequestEvent action was reviewed and if the review was valid
|
||||
func checkReviewed(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "review_requested") {
|
||||
if event.PullRequest.Assignee != nil && event.Sender != nil {
|
||||
err := AddAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
if strings.EqualFold(*event.PullRequest.Assignee.Name, *event.Sender.Name) {
|
||||
validTime := true
|
||||
expireTime := updateTime()
|
||||
expireTime := expireTime(time.Now())
|
||||
if event.PullRequest != nil && event.Number != nil {
|
||||
err := UpsertPullRequestEntry(event, tx, validTime, expireTime)
|
||||
err := UpsertPullRequestEntry(ctx, event, tx, validTime, expireTime)
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in checkReviewed", *event.Number)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkLabeled(event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "labeled") {
|
||||
if event.PullRequest.Assignee != nil && event.Sender != nil {
|
||||
//Check that the label action was done by the assignee
|
||||
if strings.EqualFold(*event.PullRequest.Assignee.Name, *event.Sender.Name) {
|
||||
validTime := true
|
||||
expireTime := updateTime()
|
||||
if event.PullRequest != nil && event.Number != nil {
|
||||
err := UpsertPullRequestEntry(event, tx, validTime, expireTime)
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in checkLabeled", *event.Number)
|
||||
return false
|
||||
}
|
||||
err = AddPullrequestAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -187,62 +226,129 @@ func checkLabeled(event github.PullRequestEvent, tx *pop.Connection) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func checkClosed(event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "closed") {
|
||||
expireTime := time.Time{}
|
||||
validTime := false
|
||||
if event.PullRequest != nil && event.Number != nil {
|
||||
err := UpsertPullRequestEntry(event, tx, validTime, expireTime)
|
||||
//CheckLabeled Determines if the PullRequestEvent action was labeled and if the label action was valid
|
||||
func checkLabeled(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "labeled") {
|
||||
if event.PullRequest.Assignee != nil && event.Sender != nil {
|
||||
err := AddAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in checkClosed", *event.Number)
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
//Check that the label action was done by the assignee
|
||||
if strings.EqualFold(*event.PullRequest.Assignee.Name, *event.Sender.Name) {
|
||||
validTime := true
|
||||
expireTime := expireTime(time.Now())
|
||||
if event.PullRequest != nil && event.Number != nil {
|
||||
err := UpsertPullRequestEntry(ctx, event, tx, validTime, expireTime)
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in checkLabeled", *event.Number)
|
||||
return false
|
||||
}
|
||||
}
|
||||
err = AddPullrequestAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkOpened(event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "opened") {
|
||||
//CheckClosed Determines if the PullRequestEvent action was closed and marks the PR as invalid
|
||||
func checkClosed(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "closed") {
|
||||
expireTime := time.Time{}
|
||||
validTime := false
|
||||
if event.PullRequest != nil && event.Number != nil {
|
||||
err := UpsertPullRequestEntry(ctx, event, tx, validTime, expireTime)
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in checkClosed", *event.Number)
|
||||
return false
|
||||
}
|
||||
}
|
||||
err := AddAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
err = AddPullrequestAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//CheckOpened Determines if the PullRequestEvent action was open and updated the entry in the DB
|
||||
func checkOpened(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "opened") {
|
||||
expiration := time.Time{}
|
||||
validTime := false
|
||||
if event.PullRequest.Assignee != nil {
|
||||
expireTime = updateTime()
|
||||
expiration = expireTime(time.Now())
|
||||
validTime = true
|
||||
}
|
||||
err := UpsertPullRequestEntry(event, tx, validTime, expireTime)
|
||||
err := UpsertPullRequestEntry(ctx, event, tx, validTime, expiration)
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in checkOpened", *event.Number)
|
||||
return false
|
||||
}
|
||||
err = AddAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
err = AddPullrequestAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
func checkEdited(event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
//CheckAssigned Determines if the PullRequestEvent action was reviewed and if the review was valid
|
||||
func checkEdited(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) bool {
|
||||
if strings.EqualFold(*event.Action, "edited") {
|
||||
log.Print("made it to editied event")
|
||||
if event.PullRequest.Assignee != nil && event.Sender != nil {
|
||||
//Make sure the sender is the same as the assignee
|
||||
//if strings.EqualFold(*event.PullRequest.Assignee.Name, *event.Sender.Name) {
|
||||
expireTime := updateTime()
|
||||
err := AddAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
expireTime := expireTime(time.Now())
|
||||
if event.PullRequest != nil && event.Number != nil {
|
||||
err := UpsertPullRequestEntry(event, tx, true, expireTime)
|
||||
err := UpsertPullRequestEntry(ctx, event, tx, true, expireTime)
|
||||
log.Print("updated event")
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in checkEdited", *event.Number)
|
||||
return false
|
||||
}
|
||||
}
|
||||
err = AddPullrequestAssigneeToDB(ctx, event, tx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func UpsertPullRequestEntry(event github.PullRequestEvent, tx *pop.Connection, valid_time bool, expire_time time.Time) error {
|
||||
//UpsertPullRequestEntry performs an upsert on the pullrequests table to update or add a new pullrequest entry
|
||||
func UpsertPullRequestEntry(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection, valid_time bool, expire_time time.Time) error {
|
||||
id, err := uuid.NewV1()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -260,13 +366,78 @@ func UpsertPullRequestEntry(event github.PullRequestEvent, tx *pop.Connection, v
|
|||
NullCheckInt(event.PullRequest.Commits), *event.PullRequest.StatusesURL, expire_time, valid_time, expire_time)
|
||||
err = q.Exec()
|
||||
if err != nil {
|
||||
log.Printf("Unable to update event number %d in Upsert", *event.Number)
|
||||
return fmt.Errorf("Could not complete upsert: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//NullCheckTime
|
||||
//AddAssigneeToDB adds the assigneeo of the pull request to the DB
|
||||
func AddAssigneeToDB(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) error {
|
||||
if event.PullRequest != nil && event.PullRequest.Assignees != nil {
|
||||
assignees := event.PullRequest.Assignees
|
||||
for _, assignee := range assignees {
|
||||
assigneeID, err := uuid.NewV1()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q := tx.RawQuery(`INSERT INTO assignees (id, created_at, updated_at, login, type, html_url)
|
||||
VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT (login) DO NOTHING`,
|
||||
assigneeID, time.Now(), time.Now(), assignee.Login, assignee.Type, assignee.HTMLURL)
|
||||
exErr := q.Exec()
|
||||
if exErr != nil {
|
||||
log.Printf("Unable to update event number %d in checkAssigned", *event.Number)
|
||||
return exErr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Assignee is nil. Cannot add nil assignee to DB")
|
||||
}
|
||||
|
||||
//AddPullrequestAssigneeToDB creates an entry in the pullrequest_assignee table
|
||||
func AddPullrequestAssigneeToDB(ctx context.Context, event github.PullRequestEvent, tx *pop.Connection) error {
|
||||
if event.PullRequest != nil && event.PullRequest.Assignee != nil {
|
||||
//Get assignee ID
|
||||
assignees := []models.Assignee{}
|
||||
err := models.DB.RawQuery(`SELECT * FROM assignees WHERE login=?`, event.PullRequest.Assignee.Login).All(&assignees)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if assignees == nil {
|
||||
log.Print("Assignee is not in the database")
|
||||
return nil
|
||||
}
|
||||
assigneeID := assignees[0].ID
|
||||
|
||||
//Get pullrequest ID
|
||||
prs := []models.Pullrequest{}
|
||||
err = models.DB.RawQuery(`SELECT * FROM pullrequests WHERE git_prid=?`, event.PullRequest.ID).All(&prs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if prs == nil {
|
||||
log.Print("The pull request is not in the database")
|
||||
return nil
|
||||
}
|
||||
pullrequestID := prs[0].ID
|
||||
|
||||
pullrequestAssigneeID, err := uuid.NewV1()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q := tx.RawQuery(`INSERT INTO pullrequest_assignees (id, created_at, updated_at, pullrequest_id, assignee_id)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
pullrequestAssigneeID, time.Now(), time.Now(), pullrequestID, assigneeID)
|
||||
exErr := q.Exec()
|
||||
if exErr != nil {
|
||||
log.Printf("Unable to update event number %d in checkAssigned", *event.Number)
|
||||
return exErr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//NullCheckTime determines if the time.Time value is nil
|
||||
func NullCheckTime(x *time.Time) time.Time {
|
||||
if x == nil {
|
||||
return time.Time{}
|
||||
|
|
|
@ -1,7 +1,32 @@
|
|||
package messages
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_Add_To_DB(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func Test_slaDuration(t *testing.T) {
|
||||
const oneDay = 24 * time.Hour
|
||||
expected := map[time.Weekday]time.Duration{
|
||||
time.Monday: oneDay,
|
||||
time.Thursday: oneDay,
|
||||
time.Friday: 3 * oneDay,
|
||||
time.Saturday: 2 * oneDay,
|
||||
time.Sunday: oneDay,
|
||||
}
|
||||
|
||||
for tc, want := range expected {
|
||||
t.Run(tc.String(), func(t *testing.T) {
|
||||
got := slaDuration(tc)
|
||||
if got != want {
|
||||
t.Logf("got: %v want: %v", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Двоичный файл не отображается.
|
@ -8,35 +8,34 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/spec-sla-bot/models"
|
||||
gomail "gopkg.in/gomail.v2"
|
||||
)
|
||||
|
||||
//Email information structure
|
||||
type Email struct {
|
||||
Password string
|
||||
EmailAddress string
|
||||
Port int
|
||||
}
|
||||
|
||||
//SendEmailToAssignee sends an email to a list of users
|
||||
func SendEmailToAssignee(ctx context.Context, info *Message) error {
|
||||
CreatePrimaryTemplate(info)
|
||||
func SendEmailToAssignee(ctx context.Context, info *MessageContent) error {
|
||||
err := CreatePrimaryTemplate(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile("finalPrimaryTemplate.html")
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
return err
|
||||
}
|
||||
str := string(b)
|
||||
m := gomail.NewMessage()
|
||||
//Get connection string from azure
|
||||
emailUrl := os.Getenv("CUSTOMCONNSTR_EMAIL_URL")
|
||||
|
||||
//parse connection string url
|
||||
parsed, err := url.Parse(emailUrl)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return err
|
||||
}
|
||||
|
||||
port, _ := strconv.Atoi(parsed.Port())
|
||||
password, _ := parsed.User.Password()
|
||||
|
||||
queryString := fmt.Sprintf("SELECT EmailLogin FROM [User] WHERE GitHubUser = '%s';", info.Assignee)
|
||||
fmt.Println("email selection query: ", queryString)
|
||||
//Determine email recipient from database
|
||||
queryString := fmt.Sprintf("SELECT EmailLogin FROM [User] WHERE GitHubUser = '%s';", info.AssigneeLogin)
|
||||
rows, err := InfraDB.QueryContext(ctx, queryString)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -44,30 +43,97 @@ func SendEmailToAssignee(ctx context.Context, info *Message) error {
|
|||
defer rows.Close()
|
||||
var emailTo string
|
||||
if rows != nil {
|
||||
log.Print("rows does not equal null")
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&emailTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
//Can be removed once we use a default email in the repo or use the infra monitor database
|
||||
//to send the email
|
||||
if emailTo == "" {
|
||||
emailTo = "t-jaelli@microsoft.com"
|
||||
}
|
||||
log.Printf("ISSUE")
|
||||
m.SetHeader("To", emailTo)
|
||||
} else {
|
||||
log.Printf("Cannot find email for %s to send SLA reminder email", info.Assignee)
|
||||
return fmt.Errorf("Cannot find email for %s to send SLA reminder email", info.AssigneeLogin)
|
||||
}
|
||||
|
||||
//Parse email connection string
|
||||
emailInfo, err := parseEmailURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.SetHeader("From", "t-jaelli@microsoft.com")
|
||||
//Format email
|
||||
str := string(b)
|
||||
m := gomail.NewMessage()
|
||||
m.SetHeader("From", emailInfo.EmailAddress)
|
||||
m.SetHeader("To", emailTo)
|
||||
m.SetHeader("Subject", "TEST")
|
||||
m.SetHeader("Subject", "SLA Violation - Outstanding Pull Request")
|
||||
m.SetBody("text/html", str)
|
||||
d := gomail.NewDialer("smtp.office365.com", port, "t-jaelli@microsoft.com", password)
|
||||
|
||||
d := gomail.NewDialer("smtp.office365.com", emailInfo.Port, emailInfo.EmailAddress, emailInfo.Password)
|
||||
if err = d.DialAndSend(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendEmailToManager(ctx context.Context, info *MessageContent) error {
|
||||
//Get record of emails sent during date ran
|
||||
emails := []models.Email{}
|
||||
err := models.DB.RawQuery(`SELECT * FROM emails WHERE [time_sent] > '?' AND [time_sent] <= '?'`, time.Now().AddDate(0, 0, -7), time.Now()).All(&emails)
|
||||
if err != nil {
|
||||
log.Print("Could not make query")
|
||||
return err
|
||||
}
|
||||
err = CreateManagerTemplate(emails)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile("finalManagerTemplate.html")
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
return err
|
||||
}
|
||||
|
||||
//Parse email connection string
|
||||
emailInfo, err := parseEmailURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
str := string(b)
|
||||
m := gomail.NewMessage()
|
||||
m.SetHeader("From", emailInfo.EmailAddress)
|
||||
//Will always be sent to the manager
|
||||
m.SetHeader("To", "t-jaelli@microsoft.com")
|
||||
m.SetHeader("Subject", "SLA Violations - A Week In Review")
|
||||
m.SetBody("text/html", str)
|
||||
|
||||
d := gomail.NewDialer("smtp.office365.com", emailInfo.Port, emailInfo.EmailAddress, emailInfo.Password)
|
||||
if err = d.DialAndSend(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseEmailURL() (*Email, error) {
|
||||
emailURL := os.Getenv("CUSTOMCONNSTR_EMAIL_URL")
|
||||
|
||||
parsed, err := url.Parse(emailURL)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
port, _ := strconv.Atoi(parsed.Port())
|
||||
password, _ := parsed.User.Password()
|
||||
emailStruct := &Email{
|
||||
Password: password,
|
||||
Port: port,
|
||||
EmailAddress: "t-jaelli@microsoft.com",
|
||||
}
|
||||
return emailStruct, nil
|
||||
}
|
||||
|
|
|
@ -3,26 +3,41 @@ package messages
|
|||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/spec-sla-bot/models"
|
||||
)
|
||||
|
||||
func CreatePrimaryTemplate(info *Message) {
|
||||
//Map of function names to functions
|
||||
//box := packr.NewBox("../templates")
|
||||
//CreatePrimaryTemplate populates the finalPrimaryTemplate for the assignee email
|
||||
func CreatePrimaryTemplate(info *MessageContent) error {
|
||||
fmap := template.FuncMap{
|
||||
"FormatNumber": FormatNumber,
|
||||
"FormatAssignee": FormatAssignee}
|
||||
t := template.Must(template.New("primaryTemplate.tmpl").Funcs(fmap).ParseFiles("./templates/primaryTemplate.tmpl"))
|
||||
handle, err := os.Create("finalPrimaryTemplate.html")
|
||||
err = t.Execute(handle, *info)
|
||||
err = t.Execute(handle, info)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateAssigneeTemplate() {
|
||||
//CreateManagerTemplate should this accept something other than messageContent
|
||||
func CreateManagerTemplate(emails []models.Email) error {
|
||||
fmap := template.FuncMap{
|
||||
"FormatNumber": FormatNumber,
|
||||
"FormatAssignee": FormatAssignee}
|
||||
t := template.Must(template.New("managerTemplate.tmpl").Funcs(fmap).ParseFiles("./templates/managerTemplate.tmpl"))
|
||||
handle, err := os.Create("finalManagerTemplate.html")
|
||||
err = t.Execute(handle, emails)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*func CreateAssigneeTemplate() {
|
||||
//Map of function names to functions
|
||||
//box := packr.NewBox("../templates")
|
||||
fmap := template.FuncMap{
|
||||
|
@ -37,12 +52,11 @@ func CreateAssigneeTemplate() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
handle, err := os.Create("finalTemplate.html")
|
||||
//fred, err := ioutil.TempFile()
|
||||
err = t.Execute(handle, *result)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
func FormatNumber(number int) string {
|
||||
return fmt.Sprintf("#%-5d", number)
|
||||
|
|
|
@ -8,10 +8,11 @@ import (
|
|||
_ "github.com/denisenkom/go-mssqldb"
|
||||
)
|
||||
|
||||
// InfraDB is a connection to the infra monitor database to be used
|
||||
// throughout the application.
|
||||
var InfraDB *sql.DB
|
||||
|
||||
func init() {
|
||||
log.Print("made it to init in infra")
|
||||
conn, err := sql.Open("mssql", os.Getenv("CUSTOMCONNSTR_INFRA_DATABASE_URL"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
|
|
@ -2,10 +2,9 @@ package messages
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-service-bus-go"
|
||||
|
@ -13,17 +12,11 @@ import (
|
|||
"github.com/gobuffalo/uuid"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
PRID string
|
||||
PullRequestURL string
|
||||
Assignee string
|
||||
}
|
||||
|
||||
//ReceiveFromQueue Sets up the queue to receive from service bus and determines whether
|
||||
//or not an email should be sent to the assignees and updates the datebase accordingly
|
||||
func ReceiveFromQueue(ctx context.Context, connStr string) (*servicebus.ListenerHandle, error) {
|
||||
ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connStr))
|
||||
log.Print("new namespace created")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -33,16 +26,16 @@ func ReceiveFromQueue(ctx context.Context, connStr string) (*servicebus.Listener
|
|||
log.Printf("failed to build a new queue named %q\n", queueName)
|
||||
return nil, err
|
||||
}
|
||||
log.Print("got queue to receive")
|
||||
|
||||
listenHandle, err := q.Receive(ctx, func(ctx context.Context, message *servicebus.Message) servicebus.DispositionAction {
|
||||
messageStruct, err := parseMessage(message.Data)
|
||||
messageStruct := &MessageContent{}
|
||||
err := json.Unmarshal(message.Data, messageStruct)
|
||||
log.Print("parsed message")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return message.DeadLetter(err)
|
||||
}
|
||||
log.Print(messageStruct.Assignee)
|
||||
if ShouldSend(messageStruct) {
|
||||
if ShouldSendAssigneeEmail(messageStruct) {
|
||||
err = SendEmailToAssignee(ctx, messageStruct)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
@ -53,6 +46,12 @@ func ReceiveFromQueue(ctx context.Context, connStr string) (*servicebus.Listener
|
|||
log.Println("Unable to add the emails to the database")
|
||||
return message.DeadLetter(err)
|
||||
}
|
||||
} else if messageStruct.ManagerEmailReminder {
|
||||
err = SendEmailToManager(ctx, messageStruct)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return message.DeadLetter(err)
|
||||
}
|
||||
}
|
||||
return message.Complete()
|
||||
})
|
||||
|
@ -63,6 +62,7 @@ func ReceiveFromQueue(ctx context.Context, connStr string) (*servicebus.Listener
|
|||
return listenHandle, nil
|
||||
}
|
||||
|
||||
//getQueueToReveive gets the queue to receive messages from service bus
|
||||
func getQueueToReceive(ns *servicebus.Namespace, queueName string) (*servicebus.Queue, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
@ -78,58 +78,62 @@ func getQueueToReceive(ns *servicebus.Namespace, queueName string) (*servicebus.
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
q, err := ns.NewQueue(ctx, queueName)
|
||||
q, err := ns.NewQueue(queueName)
|
||||
return q, err
|
||||
}
|
||||
|
||||
//Redo this
|
||||
func parseMessage(data []byte) (*Message, error) {
|
||||
str := string(data[:])
|
||||
if len(str) != 0 {
|
||||
strSplit := strings.FieldsFunc(str, Split)
|
||||
for i, v := range strSplit {
|
||||
strSplit[i] = strings.TrimSpace(v)
|
||||
}
|
||||
return &Message{PRID: strSplit[1], PullRequestURL: strSplit[3], Assignee: strSplit[5]}, nil
|
||||
}
|
||||
return nil, errors.New("could not parse messages returned by service bus")
|
||||
}
|
||||
|
||||
func Split(r rune) bool {
|
||||
return r == ','
|
||||
}
|
||||
|
||||
func ShouldSend(messageStruct *Message) bool {
|
||||
gitPRID, _ := strconv.Atoi(messageStruct.PRID)
|
||||
//ShouldSendAssigneeEmail determines if an email should be sent to the assignee based on
|
||||
//whether the time is valid and the current time is greater than the expire
|
||||
//time
|
||||
func ShouldSendAssigneeEmail(messageStruct *MessageContent) bool {
|
||||
prs := []models.Pullrequest{}
|
||||
err := models.DB.Where("git_prid=?", int64(gitPRID)).All(&prs)
|
||||
err := models.DB.Where("git_prid=?", messageStruct.PRID).All(&prs)
|
||||
if err != nil || prs == nil {
|
||||
log.Print("Could not make querey")
|
||||
return false
|
||||
}
|
||||
for _, pr := range prs {
|
||||
log.Print(time.Now().Sub(pr.ExpireTime))
|
||||
//if pr.ValidTime && time.Now().Sub(pr.ExpireTime) >= 0 {
|
||||
log.Print("returning true, should send message")
|
||||
return true
|
||||
//}
|
||||
//log.Print(time.Now())
|
||||
//log.Print(pr.ExpireTime)
|
||||
if pr.ValidTime && time.Now().Sub(pr.ExpireTime) >= 0 {
|
||||
log.Print("returning true, should send message")
|
||||
return true
|
||||
}
|
||||
}
|
||||
log.Print("pr was nil")
|
||||
return false
|
||||
}
|
||||
|
||||
func AddEmailToDB(messageStruct *Message) error {
|
||||
gitPRID, _ := strconv.Atoi(messageStruct.PRID)
|
||||
id, err := uuid.NewV1()
|
||||
//AddEmailToDB adds an email entry to the database for use when sending
|
||||
//the manager email
|
||||
func AddEmailToDB(messageStruct *MessageContent) error {
|
||||
emailID, err := uuid.NewV1()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//Do I need to populate assignee?
|
||||
q := models.DB.RawQuery(`INSERT INTO emails (id, created_at, updated_at, pullrequest_id, time_sent)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
id, time.Now(), time.Now(), gitPRID, time.Now())
|
||||
emailID, time.Now(), time.Now(), int(messageStruct.PRID), time.Now())
|
||||
err = q.Exec()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return errors.New("Could not complete insert to add email to database")
|
||||
}
|
||||
|
||||
assignees := []models.Assignee{}
|
||||
err = models.DB.RawQuery(`SELECT * FROM assignees WHERE login=?`, messageStruct.AssigneeLogin).All(&assignees)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if assignees == nil {
|
||||
log.Print("Assignee is not in the database")
|
||||
return nil
|
||||
}
|
||||
|
||||
assigneeID := assignees[0].ID
|
||||
emailAssigneeID, err := uuid.NewV1()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q = models.DB.RawQuery(`INSERT INTO email_assignees (id, email_id, assignee_id, created_at,
|
||||
updated_at) VALUES (?, ?, ?, ?, ?)`,
|
||||
emailAssigneeID, emailID, assigneeID, time.Now(), time.Now())
|
||||
err = q.Exec()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
|
|
@ -2,6 +2,7 @@ package messages
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
@ -9,36 +10,39 @@ import (
|
|||
"github.com/Azure/azure-service-bus-go"
|
||||
)
|
||||
|
||||
func SendToQueue(message string, postTime time.Time) error {
|
||||
func SendToQueue(ctx context.Context, message []byte, postTime time.Time, queueName string) error {
|
||||
connStr := os.Getenv("CUSTOMCONNSTR_SERVICEBUS_CONNECTION_STRING")
|
||||
ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connStr))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
queueName := "24hrgitevents"
|
||||
q, err := getQueueToSend(ns, queueName)
|
||||
fmt.Println("Post Time: ", postTime, " Now: ", time.Now())
|
||||
|
||||
q, err := getQueueToSend(ns, queueName)
|
||||
fmt.Println("Queue Name: ", queueName)
|
||||
if err != nil {
|
||||
log.Printf("failed to build a new queue named %q\n", queueName)
|
||||
return err
|
||||
}
|
||||
postTime = postTime.Add(time.Minute * 10)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
msg := servicebus.NewMessageFromString(message)
|
||||
|
||||
msg := servicebus.NewMessage(message)
|
||||
msg.SystemProperties = &servicebus.SystemProperties{
|
||||
ScheduledEnqueueTime: &postTime,
|
||||
}
|
||||
log.Printf("ABOUT TO SEND MESSAGE")
|
||||
log.Print(message)
|
||||
q.Send(ctx, msg)
|
||||
cancel()
|
||||
|
||||
fmt.Println("Scheduled Enqueue Time: ", msg.SystemProperties.ScheduledEnqueueTime)
|
||||
|
||||
err = q.Send(ctx, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Close(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getQueueToSend(ns *servicebus.Namespace, queueName string) (*servicebus.Queue, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
q, err := ns.NewQueue(ctx, queueName)
|
||||
q, err := ns.NewQueue(queueName)
|
||||
return q, err
|
||||
}
|
||||
|
|
|
@ -1,8 +1,97 @@
|
|||
package messages
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
func Test_Send_To_Queue(t *testing.T) {
|
||||
servicebus "github.com/Azure/azure-service-bus-go"
|
||||
)
|
||||
|
||||
//as.Fail("Not Implemented!")
|
||||
func Test_SendToQueue(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
|
||||
connStr := os.Getenv("CUSTOMCONNSTR_SERVICEBUS_CONNECTION_STRING")
|
||||
if connStr == "" {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
|
||||
want := RandomString(15)
|
||||
tempQueueName := RandomString(10)
|
||||
if testing.Verbose() {
|
||||
t.Logf("queue name: %q", tempQueueName)
|
||||
}
|
||||
|
||||
ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connStr))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
queueManager := ns.NewQueueManager()
|
||||
|
||||
q, err := getQueueToSend(ns, tempQueueName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
const waitTime = time.Duration(2 * time.Minute)
|
||||
fmt.Println("Wait time: ", waitTime)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second+waitTime)
|
||||
defer cancel()
|
||||
|
||||
_, err = queueManager.Put(ctx, tempQueueName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
defer queueManager.Delete(ctx, tempQueueName)
|
||||
|
||||
SendToQueue(ctx, want, time.Now().Add(waitTime), tempQueueName)
|
||||
|
||||
start := time.Now()
|
||||
message, err := q.ReceiveOne(ctx)
|
||||
defer message.Complete()
|
||||
|
||||
timeWaited := time.Now().Sub(start)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
got := string(message.Data)
|
||||
if got != want {
|
||||
t.Logf("got:\n\t%q\nwant:\n\t%q", got, want)
|
||||
t.Fail()
|
||||
} else {
|
||||
t.Logf("message matched")
|
||||
}
|
||||
|
||||
const buffer = time.Duration(30 * time.Second)
|
||||
if min := waitTime - buffer; timeWaited < min {
|
||||
t.Logf("received message after %v, expected to wait at least %v", timeWaited, min)
|
||||
t.Fail()
|
||||
} else if max := waitTime + buffer; timeWaited > max {
|
||||
t.Logf("received message after %v, expected to wait no longer than %v", timeWaited, max)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func RandomString(n int) string {
|
||||
var letter = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letter[rand.Intn(len(letter))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ type Assignee struct {
|
|||
Type string `json:"type" db:"type"`
|
||||
HtmlUrl string `json:"html_url" db:"html_url"`
|
||||
Pullrequests Pullrequests `many_to_many:"pullrequest_assignees" db:"-"`
|
||||
//Pullrequests *Pullrequest `many_to_many:"pullrequest_assignee"`
|
||||
//Emails *Email `many_to_many:"email_assignee"`
|
||||
Emails Emails `many_to_many:"email_assignee" db:"-"`
|
||||
}
|
||||
|
||||
// String is not required by pop and may be deleted
|
||||
|
|
|
@ -16,7 +16,7 @@ type Email struct {
|
|||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
PullrequestID int `json:"pullrequest_id" db:"pullrequest_id"`
|
||||
TimeSent string `json:"time_sent" db:"time_sent"`
|
||||
Assignees *Assignee `many_to_many:"email_assignee"`
|
||||
Assignees Assignees `many_to_many:"email_assignees"`
|
||||
}
|
||||
|
||||
// String is not required by pop and may be deleted
|
||||
|
|
|
@ -15,6 +15,8 @@ type EmailAssignee struct {
|
|||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
EmailID uuid.UUID `json:"email_id" db:"email_id"`
|
||||
AssigneeID string `json:"assignee_id" db:"assignee_id"`
|
||||
Email Email `belongs_to:"emails" db:"-"`
|
||||
Assignee Assignee `belongs_to:"assignees" db:"-"`
|
||||
}
|
||||
|
||||
// String is not required by pop and may be deleted
|
||||
|
|
|
@ -8,7 +8,7 @@ th, td {
|
|||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
You have an outstanding PR that has not been acknowledged in past 24 hours. Please acknowlege the PR to abide by the SLA.<br /><br /> Kindly, <br />Jackie (your favorite intern)<br>
|
||||
Dear Samer, <br /><br />Below is a list of SLA violations in the past week.<br /><br /> Kindly, <br />Jackie (your favorite intern)<br>
|
||||
<table style="width:100%">
|
||||
<caption><br />Outstanding Pull Requests</caption>
|
||||
<tr>
|
||||
|
|
|
@ -8,7 +8,7 @@ th, td {
|
|||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
Dear {{.Assignee}},<br /><br /> You have an outstanding PR that has not been acknowledged in past 24 hours. Please acknowlege the PR to abide by the SLA.<br /><br /> Kindly, <br />Jackie (your favorite intern)<br>
|
||||
Dear {{.AssigneeLogin}},<br /><br /> You have an outstanding PR that has not been acknowledged in past 24 hours. Please acknowlege the PR to abide by the SLA.<br /><br /> Kindly, <br />Jackie (your favorite intern)<br>
|
||||
<table style="width:100%">
|
||||
<caption><br />Outstanding Pull Requests</caption>
|
||||
<tr>
|
||||
|
@ -16,9 +16,9 @@ th, td {
|
|||
<th>Assignee</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href={{.PullRequestURL}}>{{ .PRID }}</a></td>
|
||||
{{if .Assignee -}}
|
||||
<td>{{ .Assignee }}</td>
|
||||
<td><a href={{.HTMLURL}}>{{ .PRID }}</a></td>
|
||||
{{if .AssigneeLogin -}}
|
||||
<td>{{ .AssigneeLogin }}</td>
|
||||
{{- else}}
|
||||
<td>NONE</td>
|
||||
{{- end}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче