Skip to content

Commit

Permalink
Add messages option
Browse files Browse the repository at this point in the history
Adding messages option to the derek bot in order
to apply tempaltes or boilerplate things that we write
all the time.

Signed-off-by: Martin Dekov (VMware) <[email protected]>
  • Loading branch information
martindekov authored and alexellis committed Jul 21, 2019
1 parent b75f534 commit dd12614
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 4 deletions.
27 changes: 27 additions & 0 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,33 @@ Derek unlock
> Note: once locked no further comments are allowed apart from users with admin access.
#### Add predefined message
Have Derek add pre-configured comments to a PR or Issue thread, for example when you would like to direct someone towards the contributing guide.
Configure the feature in `.DEREK.yml` file. It should look something like:
```
custom_messages:
- name: docs
value: Hello, please check out the docs ...
- name: slack
value: |
--
To join our slack channel ...
```
Above are two examples which shows simple configuration, the first one is the method for single line messages, the second one is more specific multi line literal, which should be exactly below the `|` sign in order to be displayed and not having errors while parsing.
Tell derek to send the message:
```
Derek message: docs
```
```
Derek msg: slack
```
### Notes on usage
#### Editing the .DEREK.yml file
Expand Down
48 changes: 47 additions & 1 deletion handler/commentHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const (
removeMilestoneConstant string = "RemoveMilestone"
assignReviewerConstant string = "AssignReviewer"
unassignReviewerConstant string = "UnassignReviewer"
messageConstant string = "message"

noDCO string = "no-dco"
labelLimitDefault int = 5
Expand All @@ -61,7 +62,7 @@ func makeClient(installation int, config config.Config) (*github.Client, context
}

// HandleComment handles a comment
func HandleComment(req types.IssueCommentOuter, config config.Config) {
func HandleComment(req types.IssueCommentOuter, config config.Config, derekConfig *types.DerekRepoConfig) {

var feedback string
var err error
Expand Down Expand Up @@ -114,6 +115,11 @@ func HandleComment(req types.IssueCommentOuter, config config.Config) {
feedback, err = editReviewers(prReq, command.Type, command.Value, config)
break

case messageConstant:

feedback, err = createMessage(req, command.Type, command.Value, config, derekConfig)
break

default:
feedback = "Unable to work with comment: " + req.Comment.Body
err = nil
Expand Down Expand Up @@ -426,6 +432,8 @@ func parse(body string, commandTriggers []string) *types.CommentAction {
commandTrigger + "remove milestone: ": removeMilestoneConstant,
commandTrigger + "set reviewer: ": assignReviewerConstant,
commandTrigger + "clear reviewer: ": unassignReviewerConstant,
commandTrigger + "message: ": messageConstant,
commandTrigger + "msg: ": messageConstant,
}

for trigger, commandType := range commands {
Expand Down Expand Up @@ -506,3 +514,41 @@ func getMultiLabelLimit() int {
}
return labelLimitDefault
}

func createMessage(req types.IssueCommentOuter, cmdType, cmdValue string, config config.Config, derekConfig *types.DerekRepoConfig) (string, error) {
var err error

var buffer bytes.Buffer

buffer.WriteString(fmt.Sprintf("%s wants to add message of type '%s' on issue #%d \n", req.Comment.User.Login, cmdValue, req.Issue.Number))

messageValue, err := createIssueComment(derekConfig.Messages, cmdValue)
if err != nil {
return buffer.String(), fmt.Errorf("Error while filtering message: %s", err.Error())
}

buffer.WriteString(fmt.Sprintf("Message '%s' with content: \n%s\nfound.\n", cmdValue, *messageValue.Body))

client, ctx := makeClient(req.Installation.ID, config)

comment, resp, err := client.Issues.CreateComment(ctx, req.Repository.Owner.Login, req.Repository.Name, req.Issue.Number, messageValue)
if err != nil {
return buffer.String(), err
}
buffer.WriteString(fmt.Sprintf("Successfully applied comment: \n%s\nstatus code: %d",
*comment.Body,
resp.StatusCode))

return buffer.String(), nil
}

func createIssueComment(messages []types.Message, wantedMessage string) (*github.IssueComment, error) {
for _, message := range messages {
if message.Name == wantedMessage {
return &github.IssueComment{
Body: &message.Value,
}, nil
}
}
return nil, fmt.Errorf("Message: `%s` is not configured", wantedMessage)
}
50 changes: 50 additions & 0 deletions handler/commentHandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/alexellis/derek/types"
"github.com/google/go-github/github"
)

func Test_getCommandTrigger(t *testing.T) {
Expand Down Expand Up @@ -803,5 +804,54 @@ func Test_getCommandValue(t *testing.T) {
}
})
}
}

func Test_createIssueComment(t *testing.T) {
desiredBody := "The content of the message with slack info"
tests := []struct {
title string
message []types.Message
wantedMessage string
wantedErr bool
desiredGitHubBody *github.IssueComment
}{
{
title: "Desired message is found.",
message: []types.Message{
{Name: "slack", Value: "The content of the message with slack info"},
{Name: "docs", Value: "The content of the message with docs info"},
},
wantedMessage: "slack",
wantedErr: false,
desiredGitHubBody: &github.IssueComment{
Body: &desiredBody,
},
},
{
title: "User tried to set non existing message",
message: []types.Message{
{Name: "slack", Value: "The content of the message with slack info"},
{Name: "docs", Value: "The content of the message with docs info"},
},
wantedMessage: "dco",
wantedErr: true,
desiredGitHubBody: nil,
},
}
for _, test := range tests {
t.Run(test.title, func(t *testing.T) {
gitHubComment, err := createIssueComment(test.message, test.wantedMessage)
if gitHubComment != nil && test.desiredGitHubBody != nil {
if *gitHubComment.Body != *test.desiredGitHubBody.Body {
t.Errorf("Expected body to contain: %s got :%s",
*test.desiredGitHubBody.Body,
*gitHubComment.Body)
}
}
if err != nil && test.wantedErr == false {
t.Errorf("Unexpected error: %s",
err.Error())
}
})
}
}
12 changes: 9 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ func handleEvent(eventType string, bytesIn []byte, config config.Config) error {
derekConfig, err = handler.GetRepoConfig(req.Repository.Owner.Login, req.Repository.Name)
}
if err != nil {
return fmt.Errorf("Unable to access maintainers file at: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
return fmt.Errorf("Unable to access maintainers file at: %s/%s\nError: %s",
req.Repository.Owner.Login,
req.Repository.Name,
err.Error())
}
if req.Action != handler.ClosedConstant {
contributingURL := getContributingURL(derekConfig.ContributingURL, req.Repository.Owner.Login, req.Repository.Name)
Expand Down Expand Up @@ -116,12 +119,15 @@ func handleEvent(eventType string, bytesIn []byte, config config.Config) error {
derekConfig, err = handler.GetRepoConfig(req.Repository.Owner.Login, req.Repository.Name)
}
if err != nil {
return fmt.Errorf("Unable to access maintainers file at: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
return fmt.Errorf("Unable to access maintainers file at: %s/%s\nError: %s",
req.Repository.Owner.Login,
req.Repository.Name,
err.Error())
}

if req.Action != deleted {
if handler.PermittedUserFeature(comments, derekConfig, req.Comment.User.Login) {
handler.HandleComment(req, config)
handler.HandleComment(req, config, derekConfig)
}
}
break
Expand Down
7 changes: 7 additions & 0 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ type DerekRepoConfig struct {

//ContributingURL url to contribution guide
ContributingURL string `yaml:"contributing_url"`

Messages []Message `yaml:"custom_messages"`
}

type Message struct {
Name string `yaml:"name"`
Value string `yaml:"value"`
}

// FirstTimeContributor whether the contributor is new to the repo
Expand Down

0 comments on commit dd12614

Please sign in to comment.