From 746a8477e73c4baaba395543ca594c8c2d8727cc Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Jan 2018 15:46:36 +0000 Subject: [PATCH 1/2] Improve [owner/repo]#issue expansion regex so that it is less greedy and no longer matches #1a a#1 as a default match for #1. --- .../go-neb/services/github/github.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/github.com/matrix-org/go-neb/services/github/github.go b/src/github.com/matrix-org/go-neb/services/github/github.go index 89398bb..72b2c30 100644 --- a/src/github.com/matrix-org/go-neb/services/github/github.go +++ b/src/github.com/matrix-org/go-neb/services/github/github.go @@ -28,7 +28,8 @@ const ServiceType = "github" // Matches alphanumeric then a /, then more alphanumeric then a #, then a number. // E.g. owner/repo#11 (issue/PR numbers) - Captured groups for owner/repo/number -var ownerRepoIssueRegex = regexp.MustCompile(`(([A-z0-9-_.]+)/([A-z0-9-_.]+))?#([0-9]+)`) +// Does not match things like #3dprinting and testing#1234 (incomplete owner/repo format) +var ownerRepoIssueRegex = regexp.MustCompile(`(?:(?:([A-z0-9-_.]+)/([A-z0-9-_.]+))|\B)#([0-9]+)\b`) // Matches like above, but anchored to start and end of the string respectively. var ownerRepoIssueRegexAnchored = regexp.MustCompile(`^(([A-z0-9-_.]+)/([A-z0-9-_.]+))?#([0-9]+)$`) @@ -502,15 +503,15 @@ func (s *Service) Expansions(cli *gomatrix.Client) []types.Expansion { Regexp: ownerRepoIssueRegex, Expand: func(roomID, userID string, matchingGroups []string) interface{} { // There's an optional group in the regex so matchingGroups can look like: - // [foo/bar#55 foo/bar foo bar 55] - // [#55 55] - if len(matchingGroups) != 5 { + // [foo/bar#55 foo bar 55] + // [#55 55] + if len(matchingGroups) != 4 { log.WithField("groups", matchingGroups).WithField("len", len(matchingGroups)).Print( "Unexpected number of groups", ) return nil } - if matchingGroups[1] == "" && matchingGroups[2] == "" && matchingGroups[3] == "" { + if matchingGroups[1] == "" && matchingGroups[2] == "" { // issue only match, this only works if there is a default repo defaultRepo := s.defaultRepo(roomID) if defaultRepo == "" { @@ -527,18 +528,17 @@ func (s *Service) Expansions(cli *gomatrix.Client) []types.Expansion { // Fill in the missing fields in matching groups and fall through into ["foo/bar#11", "foo", "bar", "11"] matchingGroups = []string{ defaultRepo + matchingGroups[0], - defaultRepo, segs[0], segs[1], - matchingGroups[4], + matchingGroups[3], } } - num, err := strconv.Atoi(matchingGroups[4]) + num, err := strconv.Atoi(matchingGroups[3]) if err != nil { - log.WithField("issue_number", matchingGroups[4]).Print("Bad issue number") + log.WithField("issue_number", matchingGroups[3]).Print("Bad issue number") return nil } - return s.expandIssue(roomID, userID, matchingGroups[2], matchingGroups[3], num) + return s.expandIssue(roomID, userID, matchingGroups[1], matchingGroups[2], num) }, }, } From a31aaab46e73e7e46589eb9ee1ad192082753522 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 8 Feb 2018 10:30:34 +0000 Subject: [PATCH 2/2] Linkify/Expand commits Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../go-neb/services/github/github.go | 104 +++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/src/github.com/matrix-org/go-neb/services/github/github.go b/src/github.com/matrix-org/go-neb/services/github/github.go index 72b2c30..e6fd3be 100644 --- a/src/github.com/matrix-org/go-neb/services/github/github.go +++ b/src/github.com/matrix-org/go-neb/services/github/github.go @@ -26,10 +26,18 @@ import ( // ServiceType of the Github service const ServiceType = "github" +// Optionally matches alphanumeric then a /, then more alphanumeric +// Used as a base for the expansion regexes below. +var ownerRepoBaseRegex = `(?:(?:([A-z0-9-_.]+)/([A-z0-9-_.]+))|\B)` + // Matches alphanumeric then a /, then more alphanumeric then a #, then a number. // E.g. owner/repo#11 (issue/PR numbers) - Captured groups for owner/repo/number // Does not match things like #3dprinting and testing#1234 (incomplete owner/repo format) -var ownerRepoIssueRegex = regexp.MustCompile(`(?:(?:([A-z0-9-_.]+)/([A-z0-9-_.]+))|\B)#([0-9]+)\b`) +var ownerRepoIssueRegex = regexp.MustCompile(ownerRepoBaseRegex + `#([0-9]+)\b`) + +// Matches alphanumeric then a /, then more alphanumeric then a @, then a hex string. +// E.g. owner/repo@deadbeef1234 (commit hash) - Captured groups for owner/repo/hash +var ownerRepoCommitRegex = regexp.MustCompile(ownerRepoBaseRegex + `@([0-9a-fA-F]+)\b`) // Matches like above, but anchored to start and end of the string respectively. var ownerRepoIssueRegexAnchored = regexp.MustCompile(`^(([A-z0-9-_.]+)/([A-z0-9-_.]+))?#([0-9]+)$`) @@ -81,7 +89,7 @@ func (s *Service) requireGithubClientFor(userID string) (cli *gogithub.Client, r } const numberGithubSearchSummaries = 3 -const cmdGithubSearchUsage = `!github create owner/repo "search query"` +const cmdGithubSearchUsage = `!github search "search query"` func (s *Service) cmdGithubSearch(roomID, userID string, args []string) (interface{}, error) { cli := s.githubClientFor(userID, true) @@ -89,7 +97,7 @@ func (s *Service) cmdGithubSearch(roomID, userID string, args []string) (interfa return &gomatrix.TextMessage{"m.notice", "Usage: " + cmdGithubSearchUsage}, nil } - query := fmt.Sprintf("repo:%s %s", args[0], strings.Join(args[1:], " ")) + query := strings.Join(args, " ") searchResult, res, err := cli.Search.Issues(query, nil) if err != nil { @@ -426,6 +434,58 @@ func (s *Service) expandIssue(roomID, userID, owner, repo string, issueNum int) } } +func (s *Service) expandCommit(roomID, userID, owner, repo, sha string) interface{} { + cli := s.githubClientFor(userID, true) + + c, _, err := cli.Repositories.GetCommit(owner, repo, sha) + if err != nil { + log.WithError(err).WithFields(log.Fields{ + "owner": owner, + "repo": repo, + "sha": sha, + }).Print("Failed to fetch commit") + return nil + } + + commit := c.Commit + var htmlBuffer bytes.Buffer + var plainBuffer bytes.Buffer + + shortUrl := strings.TrimSuffix(*c.HTMLURL, *c.SHA) + sha + htmlBuffer.WriteString(fmt.Sprintf("%s
", *c.HTMLURL, shortUrl)) + plainBuffer.WriteString(fmt.Sprintf("%s\n", shortUrl)) + + if c.Stats != nil { + htmlBuffer.WriteString(fmt.Sprintf("[~%d, +%d, -%d] ", len(c.Files), *c.Stats.Additions, *c.Stats.Deletions)) + plainBuffer.WriteString(fmt.Sprintf("[~%d, +%d, -%d] ", len(c.Files), *c.Stats.Additions, *c.Stats.Deletions)) + } + + if commit.Author != nil { + authorName := "" + if commit.Author.Name != nil { + authorName = *commit.Author.Name + } else if commit.Author.Login != nil { + authorName = *commit.Author.Login + } + + htmlBuffer.WriteString(fmt.Sprintf("%s: ", authorName)) + plainBuffer.WriteString(fmt.Sprintf("%s: ", authorName)) + } + + if commit.Message != nil { + segs := strings.SplitN(*commit.Message, "\n", 2) + htmlBuffer.WriteString(segs[0]) + plainBuffer.WriteString(segs[0]) + } + + return &gomatrix.HTMLMessage{ + Body: plainBuffer.String(), + MsgType: "m.notice", + Format: "org.matrix.custom.html", + FormattedBody: htmlBuffer.String(), + } +} + // Commands supported: // !github create owner/repo "issue title" "optional issue description" // Responds with the outcome of the issue creation request. This command requires @@ -541,6 +601,44 @@ func (s *Service) Expansions(cli *gomatrix.Client) []types.Expansion { return s.expandIssue(roomID, userID, matchingGroups[1], matchingGroups[2], num) }, }, + types.Expansion{ + Regexp: ownerRepoCommitRegex, + Expand: func(roomID, userID string, matchingGroups []string) interface{} { + // There's an optional group in the regex so matchingGroups can look like: + // [foo/bar@a123 foo bar a123] + // [@a123 a123] + if len(matchingGroups) != 4 { + log.WithField("groups", matchingGroups).WithField("len", len(matchingGroups)).Print( + "Unexpected number of groups", + ) + return nil + } + if matchingGroups[1] == "" && matchingGroups[2] == "" { + // issue only match, this only works if there is a default repo + defaultRepo := s.defaultRepo(roomID) + if defaultRepo == "" { + return nil + } + segs := strings.Split(defaultRepo, "/") + if len(segs) != 2 { + log.WithFields(log.Fields{ + "room_id": roomID, + "default_repo": defaultRepo, + }).Error("Default repo is malformed") + return nil + } + // Fill in the missing fields in matching groups and fall through into ["foo/bar@a123", "foo", "bar", "a123"] + matchingGroups = []string{ + defaultRepo + matchingGroups[0], + segs[0], + segs[1], + matchingGroups[3], + } + } + + return s.expandCommit(roomID, userID, matchingGroups[1], matchingGroups[2], matchingGroups[3]) + }, + }, } }