<jupyter_start><jupyter_text>[this doc on github](https://github.com/dotnet/interactive/tree/main/samples/notebooks/csharp/Samples) .NET interactive report project report for [.NET interactive repo]()  SetupImporting pacakges and setting up connection<jupyter_code>#i "nuget:https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json" 
#i "nuget:https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" 

#r "nuget:NodaTime, 2.4.8"
#r "nuget:Octokit, 0.47.0"
#r "nuget: XPlot.Plotly.Interactive, 4.0.6"

using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags;
using Microsoft.DotNet.Interactive.Formatting;
using Octokit;
using NodaTime;
using NodaTime.Extensions;
using XPlot.Plotly;
var organization = "dotnet";
var repositoryName = "interactive";
var options = new ApiOptions();
var gitHubClient = new GitHubClient(new ProductHeaderValue("notebook"));<jupyter_output><empty_output><jupyter_text>[Generate a user token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) to get rid of public [api](https://github.com/octokit/octokit.net/blob/master/docs/getting-started.md) throttling policies for anonymous users<jupyter_code>var tokenAuth = new Credentials("your token");
gitHubClient.Credentials = tokenAuth;
var today = SystemClock.Instance.InUtc().GetCurrentDate();
var startOfTheMonth = today.With(DateAdjusters.StartOfMonth);
var startOfPreviousMonth = today.With(DateAdjusters.StartOfMonth) - Period.FromMonths(1);
var startOfTheYear = new LocalDate(today.Year, 1, 1).AtMidnight();

var currentYearIssuesRequest = new RepositoryIssueRequest {
     State = ItemStateFilter.All,
     Since = startOfTheYear.ToDateTimeUnspecified()
};

var pullRequestRequest = new PullRequestRequest {
    State = ItemStateFilter.All
};<jupyter_output><empty_output><jupyter_text>Perform github queries<jupyter_code>#!time
var branches = await gitHubClient.Repository.Branch.GetAll(organization, repositoryName);
var pullRequests = await gitHubClient.Repository.PullRequest.GetAllForRepository(organization, repositoryName, pullRequestRequest);
var forks = await gitHubClient.Repository.Forks.GetAll(organization, repositoryName);
var currentYearIssues = await gitHubClient.Issue.GetAllForRepository(organization, repositoryName, currentYearIssuesRequest);<jupyter_output><empty_output><jupyter_text>Branch data Pull request data<jupyter_code>var pullRequestCreatedThisMonth = pullRequests.Where(pr => pr.CreatedAt > startOfTheMonth.ToDateTimeUnspecified());
var pullRequestClosedThisMonth =pullRequests.Where(pr => (pr.MergedAt != null && pr.MergedAt > startOfTheMonth.ToDateTimeUnspecified()));
var contributorsCount = pullRequestClosedThisMonth.GroupBy(pr => pr.User.Login);

var pullRequestLifespan = pullRequests.GroupBy(pr =>
            {
                var lifeSpan = (pr.ClosedAt ?? today.ToDateTimeUnspecified()) - pr.CreatedAt;
                return Math.Max(0, Math.Ceiling(lifeSpan.TotalDays));
            })
            .Where(g => g.Key > 0)
            .OrderBy(g => g.Key)
            .ToDictionary(g => g.Key, g => g.Count());<jupyter_output><empty_output><jupyter_text>Fork data<jupyter_code>var forkCreatedThisMonth = forks.Where(fork => fork.CreatedAt >= startOfTheMonth.ToDateTimeUnspecified());
var forkCreatedPreviousMonth = forks.Where(fork => (fork.CreatedAt >= startOfPreviousMonth.ToDateTimeUnspecified()) && (fork.CreatedAt < startOfTheMonth.ToDateTimeUnspecified()));
var forkCreatedByMonth = forks.GroupBy(fork => new DateTime(fork.CreatedAt.Year, fork.CreatedAt.Month, 1));
var forkUpdateByMonth = forks.GroupBy(f => new DateTime(f.UpdatedAt.Year, f.UpdatedAt.Month,  1) ).Select(g => new {Date = g.Key, Count = g.Count()}).OrderBy(g => g.Date).ToArray();
var total = 0;
var forkCountByMonth = forkCreatedByMonth.OrderBy(g => g.Key).Select(g => new {Date = g.Key, Count = total += g.Count()}).ToArray();<jupyter_output><empty_output><jupyter_text>Issues data<jupyter_code>bool IsBug(Issue issue){
    return issue.Labels.FirstOrDefault(l => l.Name == "bug")!= null;
}

bool TargetsArea(Issue issue){
    return issue.Labels.FirstOrDefault(l => l.Name.StartsWith("Area-"))!= null;
}

string GetArea(Issue issue){
    return issue.Labels.FirstOrDefault(l => l.Name.StartsWith("Area-"))?.Name;
}

var openIssues = currentYearIssues.Where(IsBug).Where(issue => issue.State == "open");
var closedIssues = currentYearIssues.Where(IsBug).Where(issue => issue.State == "closed");
var oldestIssues = openIssues.OrderBy(issue => today.ToDateTimeUnspecified() - issue.CreatedAt).Take(20);
var createdCurrentMonth = currentYearIssues.Where(IsBug).Where(issue => issue.CreatedAt >= startOfTheMonth.ToDateTimeUnspecified());
var createdPreviousMonth = currentYearIssues.Where(IsBug).Where(issue => (issue.CreatedAt >= startOfPreviousMonth.ToDateTimeUnspecified()) && (issue.CreatedAt < startOfTheMonth.ToDateTimeUnspecified()));
var openFromPreviousMonth = openIssues.Where(issue => (issue.CreatedAt > startOfPreviousMonth.ToDateTimeUnspecified()) && (issue.CreatedAt < startOfTheMonth.ToDateTimeUnspecified()));
var createdByMonth = currentYearIssues.Where(IsBug).GroupBy(issue => new DateTime(issue.CreatedAt.Year, issue.CreatedAt.Month, 1)).OrderBy(g=>g.Key).ToDictionary(g => g.Key, g => g.Count());
var closedByMonth = closedIssues.GroupBy(issue => new DateTime((int) issue.ClosedAt?.Year, (int) issue.ClosedAt?.Month, 1)).OrderBy(g=>g.Key).ToDictionary(g => g.Key, g => g.Count());
var openIssueAge = openIssues.GroupBy(issue => new DateTime(issue.CreatedAt.Year, issue.CreatedAt.Month, issue.CreatedAt.Day)).ToDictionary(g => g.Key, g => g.Max(issue =>Math.Max(0, Math.Ceiling( (today.ToDateTimeUnspecified() - issue.CreatedAt).TotalDays))));
var openByMonth = new Dictionary<DateTime, int>();
var minDate = createdByMonth.Min(g => g.Key);
var maxCreatedAtDate = createdByMonth.Max(g => g.Key);
var maxClosedAtDate = closedByMonth.Max(g => g.Key);
var maxDate = maxCreatedAtDate > maxClosedAtDate ?maxCreatedAtDate : maxClosedAtDate;
var cursor = minDate;
var runningTotal = 0;
var issuesCreatedThisMonthByArea = currentYearIssues.Where(issue => issue.CreatedAt >= startOfTheMonth.ToDateTimeUnspecified()).Where(issue => IsBug(issue) && TargetsArea(issue)).GroupBy(issue => GetArea(issue)).ToDictionary(g => g.Key, g => g.Count());
var openIssueByArea = currentYearIssues.Where(issue => issue.State == "open").Where(issue => IsBug(issue) && TargetsArea(issue)).GroupBy(issue => GetArea(issue)).ToDictionary(g => g.Key, g => g.Count());

while (cursor <= maxDate )
{
    createdByMonth.TryGetValue(cursor, out var openCount);
    closedByMonth.TryGetValue(cursor, out var closedCount);
    runningTotal += (openCount - closedCount);
    openByMonth[cursor] = runningTotal;
    cursor = cursor.AddMonths(1);
}

var issueLifespan = currentYearIssues.Where(IsBug).GroupBy(issue =>
            {
                var lifeSpan = (issue.ClosedAt ?? today.ToDateTimeUnspecified()) - issue.CreatedAt;
                return Math.Max(0, Math.Round(Math.Ceiling(lifeSpan.TotalDays),0));
            })
            .Where(g => g.Key > 0)
            .OrderBy(g => g.Key)
            .ToDictionary(g => g.Key, g => g.Count());

display(new { 
    less_then_one_sprint = issueLifespan.Where(i=> i.Key < 21).Select(i => i.Value).Sum(),
    less_then_two_sprint = issueLifespan.Where(i=> i.Key >= 21 && i.Key < 42).Select(i => i.Value).Sum(),
    more_then_two_sprint = issueLifespan.Where(i=> i.Key >= 42).Select(i => i.Value).Sum()   
    });<jupyter_output><empty_output><jupyter_text>Activity dashboard<jupyter_code>Scattergl ScatterglDict<T1, T2>(Dictionary<T1, T2> dict, string name)
{
    return new Scattergl{
        name = name,
        x = dict.Select(pair => pair.Key),
        y = dict.Select(pair => pair.Value)
    };    
}

var issueChart = Chart.Plot(new[] {
    ScatterglDict(createdByMonth, "Created"), 
    ScatterglDict(openByMonth, "Open"), 
    ScatterglDict(closedByMonth, "Closed")
});

issueChart.WithTitle("Bugs by month");
display(issueChart);
// Helper function for some of the below charts.

Bar BarIEnumerableKeyValuePair<T1,T2>(IEnumerable<KeyValuePair<T1,T2>> seq, string name, string color)
{
    return new Bar
    {
        name = name,
        y = seq.OrderBy(issue => issue.Key).Select(issue => issue.Value),
        x = seq.OrderBy(issue => issue.Key).Select(issue => issue.Key),
        marker = new Marker{ color = color }  
    };    
}
var issueLifespanChart = Chart.Plot(new[] {
    BarIEnumerableKeyValuePair(issueLifespan.Where(issue => issue.Key < 7), "One week old", "green"), 
    BarIEnumerableKeyValuePair(issueLifespan.Where(issue => issue.Key >= 7 && issue.Key < 21), "One Sprint old", "yellow"), 
    BarIEnumerableKeyValuePair(issueLifespan.Where(issue => issue.Key >= 21), "More then a Sprint", "red")
});

issueLifespanChart.WithLayout(new Layout.Layout
            {
                title = "Bugs by life span",
                xaxis = new Xaxis {
                    title = "Number of days a bug stays open",
                    showgrid = false,
                    zeroline = false
                },
                yaxis = new Yaxis {                
                    showgrid = true,
                    zeroline = false
                }
            });

display(issueLifespanChart);
var openIssuesAgeChart = Chart.Plot(new[] {
    BarIEnumerableKeyValuePair(openIssueAge.Where(issue => issue.Value < 7), "Closed in a week", "green"), 
    BarIEnumerableKeyValuePair(openIssueAge.Where(issue => issue.Value >= 7 && issue.Value < 21), "Closed within a sprint", "yellow"), 
    BarIEnumerableKeyValuePair(openIssueAge.Where(issue => issue.Value >= 21), "Long standing", "red")
});

openIssuesAgeChart.WithLayout(new Layout.Layout
            {
                title = "Open bugs age",
                yaxis = new Yaxis {
                    title = "Number of days a bug stays open",
                    showgrid = true,
                    zeroline = false
                }
            });
display(openIssuesAgeChart);
var createdThisMonthAreaSeries = new Pie {
    values = issuesCreatedThisMonthByArea.Select(e => e.Value),
    labels = issuesCreatedThisMonthByArea.Select(e => e.Key),
};

var createdArea = Chart.Plot(new[] {createdThisMonthAreaSeries});

createdArea.WithLayout(new Layout.Layout
            {
                title = "Bugs created this month by Area",                
            });

display(createdArea);
var openAreaSeries = new Pie {
    values = openIssueByArea.Select(e => e.Value),
    labels = openIssueByArea.Select(e => e.Key),
};

var openArea = Chart.Plot(new[] {openAreaSeries});

openArea.WithLayout(new Layout.Layout
            {
                title = "Open bugs by Area",                
            });

display(openArea);
var prLifespanChart = Chart.Plot(new[] {
    BarIEnumerableKeyValuePair(pullRequestLifespan.Where(issue => issue.Key < 7), "One week", "green"), 
    BarIEnumerableKeyValuePair(pullRequestLifespan.Where(issue => issue.Key >= 7 && issue.Key < 21), "One Sprint", "yellow"), 
    BarIEnumerableKeyValuePair(pullRequestLifespan.Where(issue => issue.Key >= 21), "More than a Sprint", "red")
});

prLifespanChart.WithLayout(new Layout.Layout
            {
                title = "Pull Request by life span",
                xaxis = new Xaxis {
                    title = "Number of days a PR stays open",
                    showgrid = false,
                    zeroline = false
                },
                yaxis = new Yaxis {
                    title = "Number of PR",
                    showgrid = true,
                    zeroline = false
                }
            });
display(prLifespanChart);
var forkCreationSeries = new Scattergl
{
    name = "created by month",
    y = forkCreatedByMonth.Select(g => g.Count() ).ToArray(),
    x = forkCreatedByMonth.Select(g => g.Key ).ToArray()
};

var forkTotalSeries = new Scattergl
{
    name = "running total",
    y = forkCountByMonth.Select(g => g.Count ).ToArray(),
    x = forkCountByMonth.Select(g => g.Date ).ToArray()
};

var forkUpdateSeries = new Scattergl
{
    name = "last update by month",
    y = forkUpdateByMonth.Select(g => g.Count ).ToArray(),
    x = forkUpdateByMonth.Select(g => g.Date ).ToArray()
};



var chart = Chart.Plot(new[] {forkCreationSeries,forkTotalSeries,forkUpdateSeries});
chart.WithTitle("Fork activity");
display(chart);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13494284115436886, 'fraction_numerical': 0.0051962586937405065, 'mean_word_length': 3.7894333843797856, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 140, 'https://': 5, '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}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '13846', 'license': 'MIT', 'n_tokens_mistral': 4004, 'n_tokens_neox': 3827, 'n_words': 750, 'path': 'samples/notebooks/csharp/Samples/interactive-metrics.ipynb', 'repo_name': 'flcdrg/dotnet-interactive', 'size': '12509'}