/*func me(c *integram.Context) (*gitlab.User, error) { api:=Api(c).Repositories.Commits.GetCommit() user := &gitlab.User{} c.User.Cache("me", user) if user.ID > 0 { return user, nil } user, _, err := Api(c).Users.CurrentUser() if err != nil { return nil, err } c.User.SetCache("me", user, time.Hour*24*30) return user, nil } func cacheNickMap(c *integram.Context) error { me, err := me(c) if err != nil { return err } c.SetServiceCache("nick_map_"+me.Username, c.User.UserName, time.Hour*24*365) err = c.SetServiceCache("nick_map_"+me.Email, c.User.UserName, time.Hour*24*365) return err } */ func hostedAppSecretEntered(c *integram.Context, baseURL string, appID string) error { c.SetServiceBaseURL(baseURL) appSecret := strings.TrimSpace(c.Message.Text) if len(appSecret) != 64 { c.NewMessage().SetText("Looks like this *Application Secret* is incorrect. Must be a 64 HEX symbols. Please try again").EnableHTML().DisableWebPreview().SetReplyAction(hostedAppSecretEntered, baseURL).Send() return errors.New("Application Secret '" + appSecret + "' is incorrect") } conf := integram.OAuthProvider{BaseURL: c.ServiceBaseURL, ID: appID, Secret: appSecret} token, err := conf.OAuth2Client(c).Exchange(oauth2.NoContext, "-") if strings.Contains(err.Error(), `"error":"invalid_grant"`) { // means the app is exists c.SaveOAuthProvider(c.ServiceBaseURL, appID, appSecret) _, err := mustBeAuthed(c) return err } c.NewMessage().SetText("Application ID or Secret is incorrect. Please try again. Enter *Application Id*"). EnableHTML(). SetReplyAction(hostedAppIDEntered, baseURL).Send() fmt.Printf("Exchange: token: %+v, err:%v\n", token, err) return nil }
func commitReplied(c *integram.Context, baseURL string, projectID int, commitID string) error { c.Message.SetReplyAction(commitReplied, baseURL, projectID, commitID) c.SetServiceBaseURL(baseURL) authorized, err := mustBeAuthed(c) if !authorized { return c.User.SetAfterAuthAction(sendCommitComment, c, projectID, commitID, c.Message) } c.Service().DoJob(sendCommitComment, c, projectID, commitID, c.Message) return err }
func snippetReplied(c *integram.Context, baseURL string, projectID int, snippetID int) error { c.SetServiceBaseURL(baseURL) authorized, err := mustBeAuthed(c) if !authorized { c.User.SetAfterAuthAction(sendSnippetComment, baseURL, projectID, snippetID, c.Message.Text) } else { _, err = c.Service().DoJob(sendSnippetComment, c, baseURL, projectID, snippetID, c.Message.Text) } c.Message.SetReplyAction(mrReplied, baseURL, projectID, snippetID) return err }
func hostedAppIDEntered(c *integram.Context, baseURL string) error { c.SetServiceBaseURL(baseURL) appID := strings.TrimSpace(c.Message.Text) if len(appID) != 64 { c.NewMessage().SetText("Looks like this *Application Id* is incorrect. Must be a 64 HEX symbols. Please try again"). EnableHTML(). SetReplyAction(hostedAppIDEntered, baseURL).Send() return errors.New("Application Id '" + appID + "' is incorrect") } return c.NewMessage().SetText("Great! Now write me the *Secret* for this application"). EnableHTML(). SetReplyAction(hostedAppSecretEntered, baseURL, appID).Send() }
// we nee msg param because action c.Message can contains selected commit id from prev state at commitsReplied and not the comment message func commitToReplySelected(c *integram.Context, baseURL string, projectID int, msg *integram.IncomingMessage) error { commitID, _ := c.KeyboardAnswer() c.Message.SetReplyAction(commitReplied, baseURL, projectID, commitID) c.SetServiceBaseURL(baseURL) authorized, err := mustBeAuthed(c) if !authorized { return c.User.SetAfterAuthAction(sendCommitComment, c, projectID, commitID, msg.Text) } c.Service().DoJob(sendCommitComment, projectID, commitID) return err }
func webhookHandler(c *integram.Context, request *integram.WebhookContext) (err error) { wh := &webhook{} err = request.JSON(wh) if err != nil { return } msg := c.NewMessage() if wh.Repository.Homepage != "" { c.SetServiceBaseURL(wh.Repository.Homepage) } else if wh.ObjectAttributes != nil { if wh.ObjectAttributes.URL == "" { c.Log().WithField("wh", wh).Error("gitlab webhook empty url") } c.SetServiceBaseURL(wh.ObjectAttributes.URL) } switch wh.ObjectKind { case "push": s := strings.Split(wh.Ref, "/") branch := s[len(s)-1] text := "" added := 0 removed := 0 modified := 0 anyOherPersonCommits := false for _, commit := range wh.Commits { if commit.Author.Email != wh.UserEmail && commit.Author.Name != wh.UserName { anyOherPersonCommits = true } } for _, commit := range wh.Commits { commit.Message = strings.TrimSuffix(commit.Message, "\n") if anyOherPersonCommits { text += mention(c, commit.Author.Name, commit.Author.Email) + ": " } text += m.URL(commit.Message, commit.URL) + "\n" added += len(commit.Added) removed += len(commit.Removed) modified += len(commit.Modified) } f := "" if modified > 0 { f += strconv.Itoa(modified) + " files modified" } if added > 0 { if f == "" { f += strconv.Itoa(added) + " files added" } else { f += " " + strconv.Itoa(added) + " added" } } if removed > 0 { if f == "" { f += strconv.Itoa(removed) + " files removed" } else { f += " " + strconv.Itoa(removed) + " removed" } } wp := "" if len(wh.Commits) > 1 { wp = c.WebPreview(fmt.Sprintf("%d commits", len(wh.Commits)), "@"+wh.Before[0:10]+" ... @"+wh.After[0:10], f, compareURL(wh.Repository.Homepage, wh.Before, wh.After), "") } else if len(wh.Commits) == 1 { wp = c.WebPreview("Commit", "@"+wh.After[0:10], f, wh.Commits[0].URL, "") } var err error if len(wh.Commits) > 0 { if len(wh.Commits) == 1 { msg.SetReplyAction(commitReplied, c.ServiceBaseURL.String(), wh.ProjectID, wh.Commits[0].ID) } else { msg.SetReplyAction(commitsReplied, c.ServiceBaseURL.String(), wh.ProjectID, wh.Commits) } text := fmt.Sprintf("%s %s to %s\n%s", mention(c, wh.UserName, wh.UserEmail), m.URL("pushed", wp), m.URL(wh.Repository.Name+"/"+branch, wh.Repository.Homepage+"/tree/"+url.QueryEscape(branch)), text) c.Chat.SetCache("commit_"+wh.Commits[len(wh.Commits)-1].ID, text, time.Hour*24*30) err = msg.AddEventID("commit_" + wh.Commits[len(wh.Commits)-1].ID).SetText(text). EnableHTML(). Send() } else { if wh.After != "0000000000000000000000000000000000000000" && wh.After != "" { err = msg.SetText(fmt.Sprintf("%s created branch %s\n%s", mention(c, wh.UserName, wh.UserEmail), m.URL(wh.Repository.Name+"/"+branch, wh.Repository.Homepage+"/tree/"+url.QueryEscape(branch)), text)). EnableHTML(). Send() } else { err = msg.SetText(fmt.Sprintf("%s deleted branch %s\n%s", mention(c, wh.UserName, wh.UserEmail), m.Bold(wh.Repository.Name+"/"+branch), text)). EnableHTML(). Send() } } return err case "tag_push": s := strings.Split(wh.Ref, "/") itemType := s[len(s)-2] if itemType == "tags" { itemType = "tag" } else if itemType == "heads" { itemType = "branch" } return msg.SetText(fmt.Sprintf("%s pushed new %s at %s", mention(c, wh.UserName, wh.UserEmail), m.URL(itemType+" "+s[len(s)-1], wh.Repository.Homepage+"/tree/"+s[len(s)-1]), m.URL(wh.UserName+" / "+wh.Repository.Name, wh.Repository.Homepage))). EnableHTML().DisableWebPreview().Send() case "issue": if wh.ObjectAttributes.MilestoneID > 0 { // Todo: need an API access to fetch milestones } msg.SetReplyAction(issueReplied, c.ServiceBaseURL.String(), wh.ObjectAttributes.ProjectID, wh.ObjectAttributes.ID) if wh.ObjectAttributes.Action == "open" { return msg.AddEventID("issue_" + strconv.Itoa(wh.ObjectAttributes.ID)).SetText(fmt.Sprintf("%s %s %s at %s:\n%s\n%s", mention(c, wh.User.Username, wh.UserEmail), wh.ObjectAttributes.State, m.URL("issue", wh.ObjectAttributes.URL), m.URL(wh.User.Username+" / "+wh.Repository.Name, wh.Repository.Homepage), m.Bold(wh.ObjectAttributes.Title), wh.ObjectAttributes.Description)). EnableHTML().DisableWebPreview().Send() } action := "updated" if wh.ObjectAttributes.Action == "reopen" { action = "reopened" } else if wh.ObjectAttributes.Action == "close" { action = "closed" } id := issueMessageID(c, wh.ObjectAttributes.ID) if id > 0 { // reply to existing message return msg.SetText(fmt.Sprintf("%s by %s", m.Bold(action), mention(c, wh.User.Username, ""))). EnableHTML().DisableWebPreview().SetReplyToMsgID(id).Send() } // original message not found. Send WebPreview wp := c.WebPreview("Issue", wh.ObjectAttributes.Title, wh.User.Username+" / "+wh.Repository.Name, wh.ObjectAttributes.URL, "") return msg.SetText(fmt.Sprintf("%s by %s", m.URL(action, wp), mention(c, wh.User.Username, ""))).EnableHTML().Send() case "note": wp := "" noteType := "" originMsg := &integram.Message{} noteID := strconv.Itoa(wh.ObjectAttributes.ID) if wh.ObjectAttributes.Note == "Commit" { // collisions by date are unlikely here noteID = wh.ObjectAttributes.CreatedAt } if msg, _ := c.FindMessageByEventID(noteUniqueID(wh.ObjectAttributes.ProjectID, noteID)); msg != nil { return nil } switch wh.ObjectAttributes.NoteableType { case "Commit": noteType = "commit" originMsg, _ = c.FindMessageByEventID(fmt.Sprintf("commit_%s", wh.ObjectAttributes.CommitID)) if originMsg != nil { break } wp = c.WebPreview("Commit", "@"+wh.ObjectAttributes.CommitID[0:10], wh.User.Username+" / "+wh.Repository.Name, wh.ObjectAttributes.URL, "") case "MergeRequest": noteType = "merge request" originMsg, _ = c.FindMessageByEventID(fmt.Sprintf("mr_%d", wh.MergeRequest.ID)) if originMsg != nil { break } wp = c.WebPreview("Merge Request", wh.MergeRequest.Title, wh.User.Username+" / "+wh.Repository.Name, wh.ObjectAttributes.URL, "") case "Issue": noteType = "issue" originMsg, _ = c.FindMessageByEventID(fmt.Sprintf("issue_%d", wh.Issue.ID)) if originMsg != nil { break } wp = c.WebPreview("Issue", wh.Issue.Title, wh.User.Username+" / "+wh.Repository.Name, wh.ObjectAttributes.URL, "") case "Snippet": noteType = "snippet" originMsg, _ = c.FindMessageByEventID(fmt.Sprintf("snippet_%d", wh.Snippet.ID)) if originMsg != nil { break } wp = c.WebPreview("Snippet", wh.Snippet.Title, wh.User.Username+" / "+wh.Repository.Name, wh.ObjectAttributes.URL, "") } if originMsg == nil { if wp == "" { wp = wh.ObjectAttributes.URL } if noteType == "" { noteType = strings.ToLower(wh.ObjectAttributes.NoteableType) } return msg.SetTextFmt("%s commented on %s: %s", mention(c, wh.User.Username, ""), m.URL(noteType, wp), wh.ObjectAttributes.Note). EnableHTML(). Send() } return msg.SetText(fmt.Sprintf("%s: %s", mention(c, wh.User.Username, ""), wh.ObjectAttributes.Note)). DisableWebPreview().EnableHTML().SetReplyToMsgID(originMsg.MsgID).Send() case "merge_request": cs := chatSettings(c) if !cs.MR.Open && (wh.ObjectAttributes.Action == "open" || wh.ObjectAttributes.Action == "reopen") { return nil } if !cs.MR.Close && (wh.ObjectAttributes.Action == "close") { return nil } if !cs.MR.Update && (wh.ObjectAttributes.Action == "update") { return nil } if !cs.MR.Merge && (wh.ObjectAttributes.Action == "merge") { return nil } if wh.ObjectAttributes.Action == "open" { if wh.ObjectAttributes.Description != "" { wh.ObjectAttributes.Description = "\n" + wh.ObjectAttributes.Description } err := msg.AddEventID("mr_" + strconv.Itoa(wh.ObjectAttributes.ID)).SetText(fmt.Sprintf("%s %s %s at %s:\n%s%s", mention(c, wh.User.Username, wh.UserEmail), wh.ObjectAttributes.State, m.URL("merge request", wh.ObjectAttributes.URL), m.URL(wh.UserName+" / "+wh.Repository.Name, wh.Repository.Homepage), m.Bold(wh.ObjectAttributes.Title), wh.ObjectAttributes.Description)). EnableHTML().DisableWebPreview().Send() return err } originMsg, _ := c.FindMessageByEventID(fmt.Sprintf("mr_%d", wh.ObjectAttributes.ID)) if originMsg != nil { return msg.SetText(fmt.Sprintf("%s %s by %s", m.URL("merge request", wh.ObjectAttributes.URL), wh.ObjectAttributes.State, mention(c, wh.User.Username, wh.UserEmail))). EnableHTML().SetReplyToMsgID(originMsg.MsgID).DisableWebPreview().Send() } wp := c.WebPreview("Merge Request", wh.ObjectAttributes.Title, wh.ObjectAttributes.Description, wh.ObjectAttributes.URL, "") return msg.SetText(fmt.Sprintf("%s %s by %s", m.URL("Merge request", wp), wh.ObjectAttributes.State, mention(c, wh.User.Username, wh.UserEmail))). EnableHTML().Send() case "build": time.Sleep(time.Second) // workaround for simultaneously push/build webhooks // todo: replace with job? commitMsg, _ := c.FindMessageByEventID(fmt.Sprintf("commit_%s", wh.SHA)) text := "" commit := "" build := m.URL(strings.ToUpper(wh.BuildStage[0:1])+wh.BuildStage[1:], fmt.Sprintf("%s/builds/%d", wh.Repository.Homepage, wh.BuildID)) if commitMsg == nil { hpURL := strings.Split(wh.Repository.Homepage, "/") username := hpURL[len(hpURL)-2] commit = m.URL("Commit", c.WebPreview("Commit", "@"+wh.SHA[0:10], username+" / "+wh.Repository.Name, wh.Repository.URL+"/commit/"+wh.SHA, "")) + " " build = m.URL(wh.BuildStage, fmt.Sprintf("%s/builds/%d", wh.Repository.Homepage, wh.BuildID)) } else { msg.SetReplyToMsgID(commitMsg.MsgID).DisableWebPreview() } if strings.ToLower(wh.BuildStage) != strings.ToLower(wh.BuildName) { build += " #" + wh.BuildName } if wh.BuildStatus == "pending" { text = "⏳ CI: " + commit + build + " is pending" } else if wh.BuildStatus == "running" { text = "⚙ CI: " + commit + build + " is running" } else if wh.BuildStatus == "success" { text = fmt.Sprintf("✅ CI: "+commit+build+" succeeded after %.1f sec", wh.BuildDuration) } else if wh.BuildStatus == "failed" { text = fmt.Sprintf("‼️ CI: "+commit+build+" failed after %.1f sec", wh.BuildDuration) } else if wh.BuildStatus == "canceled" { text = fmt.Sprintf("🔚 CI: "+commit+build+" canceled by %s after %.1f sec", mention(c, wh.User.Name, ""), wh.BuildDuration) } if commitMsg != nil { var commitMsgText string c.Chat.Cache("commit_"+wh.Commit.SHA, &commitMsgText) if commitMsgText != "" { _, err = c.EditMessagesTextWithEventID(commitMsg.EventID[0], commitMsgText+"\n"+text) } } cs := chatSettings(c) if cs.CI.Success && (wh.BuildStatus == "success") || cs.CI.Cancel && (wh.BuildStatus == "canceled") || cs.CI.Fail && (wh.BuildStatus == "failed") { return msg.SetText(text). EnableHTML().Send() } } return }