<commit_before>﻿namespace OctoHook.WebHooks
{
	using Octokit;
	using Octokit.Events;
	using System.Text.RegularExpressions;
	using System.Linq;
	using System.Threading.Tasks;
	using OctoHook.CommonComposition;
	using OctoHook.Diagnostics;

	/// <summary>
	/// Forcedly closes issues even if they aren't closed automatically by GitHub, 
	/// which happens when the associated commit is pushed to a non-default branch.
	/// </summary>
	[Component]
	public class AutoClose : IWebHook<PushEvent>
	{
		static readonly ITracer tracer = Tracer.Get<AutoClose>();
		static readonly Regex CloseExpr = new Regex(@"(close[s|d]?|fix(es|ed)?|resolve[s|d]?)",
				RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
		static Regex IssueNumberExpr = new Regex(@"(?<=\#)\d+", RegexOptions.Compiled);

		private IGitHubClient github;

		public AutoClose(IGitHubClient github)
		{
			this.github = github;
		}

		public void Process(PushEvent @event)
		{
			ProcessAsync(@event).Wait();
		}

		public async Task ProcessAsync(PushEvent @event)
		{
			var closingCommits = @event.Commits.Where(c => CloseExpr.IsMatch(c.Message)).ToArray();
			if (closingCommits.Length == 0)
			{
				tracer.Verbose("There are no commits to process that have a close/fix/resolve message.");
				return;
			}

			tracer.Verbose("Found {0} commits to process that have a close/fix/resolve message.", closingCommits.Length);

			var closedIssues = closingCommits
				.SelectMany(c => IssueNumberExpr
					.Matches(c.Message)
					.OfType<Match>()
					.Select(m => int.Parse(m.Value)))
				.Distinct()
				.Select(number => github.Issue.Get(
					@event.Repository.Owner.Name ?? @event.Repository.Owner.Login,
					@event.Repository.Name,
					number));

			foreach (var closedIssue in closedIssues)
			{
				var issue = await closedIssue;
				if (issue.State == ItemState.Closed)
				{
					tracer.Verbose("Skipping issue #{0} as it was already closed.", issue.Number);
					continue;
				}

				await github.Issue.Update(
					@event.Repository.Owner.Name ?? @event.Repository.Owner.Login,
					@event.Repository.Name,
					issue.Number,
					new IssueUpdate
					{
						State = ItemState.Closed,<commit_msg>Only skip auto-close if the issue is closed AND is unassigned already<commit_after>﻿namespace OctoHook.WebHooks
{
	using Octokit;
	using Octokit.Events;
	using System.Text.RegularExpressions;
	using System.Linq;
	using System.Threading.Tasks;
	using OctoHook.CommonComposition;
	using OctoHook.Diagnostics;

	/// <summary>
	/// Forcedly closes issues even if they aren't closed automatically by GitHub, 
	/// which happens when the associated commit is pushed to a non-default branch.
	/// </summary>
	[Component]
	public class AutoClose : IWebHook<PushEvent>
	{
		static readonly ITracer tracer = Tracer.Get<AutoClose>();
		static readonly Regex CloseExpr = new Regex(@"(close[s|d]?|fix(es|ed)?|resolve[s|d]?)",
				RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
		static Regex IssueNumberExpr = new Regex(@"(?<=\#)\d+", RegexOptions.Compiled);

		private IGitHubClient github;

		public AutoClose(IGitHubClient github)
		{
			this.github = github;
		}

		public void Process(PushEvent @event)
		{
			ProcessAsync(@event).Wait();
		}

		public async Task ProcessAsync(PushEvent @event)
		{
			var closingCommits = @event.Commits.Where(c => CloseExpr.IsMatch(c.Message)).ToArray();
			if (closingCommits.Length == 0)
			{
				tracer.Verbose("There are no commits to process that have a close/fix/resolve message.");
				return;
			}

			tracer.Verbose("Found {0} commits to process that have a close/fix/resolve message.", closingCommits.Length);

			var closedIssues = closingCommits
				.SelectMany(c => IssueNumberExpr
					.Matches(c.Message)
					.OfType<Match>()
					.Select(m => int.Parse(m.Value)))
				.Distinct()
				.Select(number => github.Issue.Get(
					@event.Repository.Owner.Name ?? @event.Repository.Owner.Login,
					@event.Repository.Name,
					number));

			foreach (var closedIssue in closedIssues)
			{
				var issue = await closedIssue;
				if (issue.State == ItemState.Closed && issue.Assignee == null)
				{
					tracer.Verbose("Skipping issue #{0} as it was already closed and unassigned.", issue.Number);
					continue;
				}

				await github.Issue.Update(
					@event.Repository.Owner.Name ?? @event.Repository.Owner.Login,
					@event.Repository.Name,
					issue.Number,
					new IssueUpdate
					{
						State = ItemState.Closed,
{'fraction_non_alphanumeric': 0.12324805339265851, 'fraction_numerical': 0.0013348164627363737, 'mean_word_length': 3.644628099173554, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5798640', 'n_tokens_mistral': 1704, 'n_tokens_neox': 1400, 'n_words': 338}