diff --git a/server/plugin/command.go b/server/plugin/command.go index bb1549725..9b7166631 100644 --- a/server/plugin/command.go +++ b/server/plugin/command.go @@ -6,6 +6,7 @@ import ( "strings" "unicode" + "github.com/google/go-github/v41/github" "github.com/mattermost/mattermost-plugin-api/experimental/command" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" @@ -25,6 +26,11 @@ const ( featureStars = "stars" ) +const ( + ErrorNoWebhookFound = "\nNo webhook was found for this repository or organization. To create one, enter the following slash command `/github setup webhook`" + GithubListOptionsPerPageValue = 50 +) + var validFeatures = map[string]bool{ featureIssueCreation: true, featureIssues: true, @@ -265,6 +271,50 @@ func (p *Plugin) handleSubscriptionsList(_ *plugin.Context, args *model.CommandA return txt } +func (p *Plugin) getWebhookListForRepoOrOrg(githubClient *github.Client, repo, owner string, ctx context.Context) (bool, error) { + isWebhook := false + opt := &github.ListOptions{ + PerPage: GithubListOptionsPerPageValue, + } + + for { + var githubHooks []*github.Hook + var githubResponse *github.Response + var err error + + if repo == "" { + githubHooks, githubResponse, err = githubClient.Organizations.ListHooks(ctx, owner, opt) + } else { + githubHooks, githubResponse, err = githubClient.Repositories.ListHooks(ctx, owner, repo, opt) + } + + if err != nil { + p.API.LogWarn("Not able to get the list of webhooks", "Owner", owner, "Repo", repo, "Error", err.Error()) + // Breaking from the loop if the repo or org is not found + if strings.Contains(err.Error(), "404 Not Found") { + isWebhook = true + break + } else { + return isWebhook, err + } + } + + for _, hook := range githubHooks { + if strings.Contains(hook.Config["url"].(string), p.getSiteURL()) { + isWebhook = true + break + } + } + + if githubResponse.NextPage == 0 { + break + } + opt.Page = githubResponse.NextPage + } + + return isWebhook, nil +} + func (p *Plugin) handleSubscribesAdd(_ *plugin.Context, args *model.CommandArgs, parameters []string, userInfo *GitHubUserInfo) string { if len(parameters) == 0 { return "Please specify a repository." @@ -325,7 +375,17 @@ func (p *Plugin) handleSubscribesAdd(_ *plugin.Context, args *model.CommandArgs, return err.Error() } - return fmt.Sprintf("Successfully subscribed to organization %s.", owner) + subOrgMsg := fmt.Sprintf("Successfully subscribed to organization %s.", owner) + + isWebhook, err := p.getWebhookListForRepoOrOrg(githubClient, repo, owner, ctx) + if err != nil { + return errors.Wrap(err, "failed to get the list of webhooks").Error() + } + + if !isWebhook { + subOrgMsg += ErrorNoWebhookFound + } + return subOrgMsg } if err := p.Subscribe(ctx, githubClient, args.UserId, owner, repo, args.ChannelId, features, flags); err != nil { @@ -342,6 +402,15 @@ func (p *Plugin) handleSubscribesAdd(_ *plugin.Context, args *model.CommandArgs, msg += "\n\n**Warning:** You subscribed to a private repository. Anyone with access to this channel will be able to read the events getting posted here." } + isWebhook, err := p.getWebhookListForRepoOrOrg(githubClient, repo, owner, ctx) + if err != nil { + return errors.Wrap(err, "failed to get the list of webhooks").Error() + } + + if !isWebhook { + msg += ErrorNoWebhookFound + } + return msg } diff --git a/server/plugin/plugin.go b/server/plugin/plugin.go index 4f0713a6c..c1b757798 100644 --- a/server/plugin/plugin.go +++ b/server/plugin/plugin.go @@ -990,3 +990,10 @@ func (p *Plugin) getUsername(mmUserID string) (string, error) { return "@" + info.GitHubUsername, nil } + +func (p *Plugin) getSiteURL() string { + if p.API.GetConfig().ServiceSettings.SiteURL != nil { + return *p.API.GetConfig().ServiceSettings.SiteURL + } + return "" +}