public bool Process(IssuesEvent issue, IssueUpdate update) { if (processed.Contains(issue)) return false; var updated = ProcessAsync(issue, update).Result; processed.Add(issue); return updated; }
public bool Process(IssuesEvent issue, IssueUpdate update) { var match = expression.Match(update.Title); if (!match.Success) return false; var login = match.Groups["user"].Value; if (string.Equals(login, "me", StringComparison.OrdinalIgnoreCase)) update.Assignee = issue.Sender.Login; else update.Assignee = login; update.Title = update.Title.Replace(match.Value, ""); return true; }
public bool Process(IssuesEvent issue, IssueUpdate update) { var match = expression.Match(update.Title); if (!match.Success) return false; if (labels == null) { labels = github.Issue.Labels.GetForRepository(issue.Repository.Owner.Login, issue.Repository.Name) .Result .Select(l => l.Name) .ToList(); } // Match label in case-insensitive manner, without the prefix first var label = labels.FirstOrDefault(l => string.Equals(l, match.Groups["simpleLabel"].Value, StringComparison.OrdinalIgnoreCase)); if (label == null) // Labels themselves could use the "+" sign, so we match next by the full string. label = labels.FirstOrDefault(l => string.Equals(l, match.Groups["fullLabel"].Value, StringComparison.OrdinalIgnoreCase)); if (label != null) { update.AddLabel(label); tracer.Verbose("Applied pre-defined label '{0}'", label); } else { // Just apply the bare label as-is otherwise. label = match.Groups["simpleLabel"].Value; update.AddLabel(label); tracer.Verbose("Applied ad-hoc label '{0}'", label); } update.Title = update.Title.Replace(match.Value, ""); return true; }
private async Task<bool> ProcessAsync(IssuesEvent issue, IssueUpdate update) { var storyPrefix = storyPrefixExpr.Match(issue.Issue.Title); if (!storyPrefix.Success) { tracer.Verbose("Skipping issue {0}/{1}#{2} without a story prefix: '{3}'.", issue.Repository.Owner.Login, issue.Repository.Name, issue.Issue.Number, issue.Issue.Title); return false; } // Skip issues that are the story itself. if (issue.Issue.Labels != null && issue.Issue.Labels.Any(l => string.Equals(l.Name, "story", StringComparison.OrdinalIgnoreCase))) return false; // Skip the issue if it already has a story link if (!string.IsNullOrEmpty(issue.Issue.Body)) { foreach (var number in issueLinkExpr.Matches(issue.Issue.Body).OfType<Match>().Where(m => m.Success).Select(m => int.Parse(m.Value))) { try { var linkedIssue = await github.Issue.Get(issue.Repository.Owner.Login, issue.Repository.Name, number); if (linkedIssue.Labels.Any(l => string.Equals(l.Name, "story", StringComparison.OrdinalIgnoreCase))) { tracer.Info("Skipping issue {0}/{1}#{2} as it already contains story link to #{3}.", issue.Repository.Owner.Login, issue.Repository.Name, issue.Issue.Number, number); return false; } } catch (NotFoundException) { // It may be a link to a bug/issue in another system. } } } // Find the story with the same prefix. var repository = issue.Repository.Owner.Login + "/" + issue.Repository.Name; var story = await FindOpenStoryByPrefixAsync(repository, storyPrefix.Value); if (story == null || story.State == ItemState.Closed) { tracer.Warn("Issue {0}/{1}#{2} has story prefix '{3}' but no matching opened issue with the label 'Story' or 'story' was found with such prefix.", issue.Repository.Owner.Login, issue.Repository.Name, issue.Issue.Number, storyPrefix.Value); return false; } update.State = issue.Issue.State; update.Body = (issue.Issue.Body == null ? "" : issue.Issue.Body + @" ") + "Story #" + story.Number; tracer.Info("Established new story link between issue {0}/{1}#{2} and story #{3}.", issue.Repository.Owner.Login, issue.Repository.Name, issue.Issue.Number, story.Number); return true; }