Merge pull request #109 from emmagarland/githubcontributors

Github contributors list
This commit is contained in:
Sebastiaan Janssen
2017-06-05 20:57:11 +02:00
committed by GitHub
16 changed files with 516 additions and 10 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
"gulp-clean": "0.3.x", "gulp-clean": "0.3.x",
"gulp-combine-media-queries": "0.2.x", "gulp-combine-media-queries": "0.2.x",
"gulp-concat": "2.2.x", "gulp-concat": "2.2.x",
"gulp-imagemin": "0.6.x", "gulp-imagemin": "3.3.x",
"gulp-jshint": "^2.0.4", "gulp-jshint": "^2.0.4",
"gulp-minify-css": "1.1.x", "gulp-minify-css": "1.1.x",
"gulp-rename": "1.2.x", "gulp-rename": "1.2.x",
@@ -0,0 +1,94 @@
#github-contributors {
&:not(.all) {
.contributor {
&:nth-child(n+17) {
display: none;
}
@media (max-width: $md) {
&:nth-child(n+13) {
display: none;
}
}
@media (max-width: $xs) {
&:nth-child(n+10) {
display: none;
}
}
}
}
&.all {
.button {
display: none;
}
}
.loadmore {
margin: 20px auto;
width: 100%;
text-align: center;
}
}
.github-contributors small.link-list {
font-style: italic;
font-weight: normal;
text-transform: none;
}
.contributor {
margin-bottom: 15px;
.avatar {
position: relative;
flex: 0 0 23%;
margin-right: 20px;
@media (min-width: $md) {
flex: 0 0 15%;
}
img {
border: 3px solid #98d768;
width: 100%;
max-width: 112px;
height: auto;
}
}
.counts {
position: absolute;
top: 2px;
left: 2px;
right: 2px;
text-align: center;
color: #fff;
font-size: 12px;
line-height: 12px;
background: rgba(0,0,0,0.25);
border-radius: 50%;
bottom: 6px;
padding-top: 23px;
opacity: 0;
transition: opacity 0.25s;
}
&:hover .counts {
opacity: 1;
}
.contrib-count {
position: absolute;
left: 25px;
bottom: 0px;
text-align: center;
right: 25px;
color: #425a2e;
font-weight: bold;
background: darken($color-our, 4%);
border-radius: 15px;
z-index: 5;
}
}
+1 -1
View File
@@ -60,7 +60,7 @@
@import 'sections/forum'; @import 'sections/forum';
@import 'sections/people'; @import 'sections/people';
@import 'sections/events'; @import 'sections/events';
@import 'sections/contributors';
/** /**
/* Pages /* Pages
+2
View File
@@ -476,6 +476,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Content> </Content>
<Content Include="config\formHandlers.config" /> <Content Include="config\formHandlers.config" />
<Content Include="config\githubhq.txt" />
<Content Include="config\githubpull.config" /> <Content Include="config\githubpull.config" />
<Content Include="config\grid.editors.config.js" /> <Content Include="config\grid.editors.config.js" />
<Content Include="config\Lang\cs-CZ.user.xml" /> <Content Include="config\Lang\cs-CZ.user.xml" />
@@ -4343,6 +4344,7 @@
<Content Include="Views\Partials\Grid\Bootstrap3-Fluid.cshtml" /> <Content Include="Views\Partials\Grid\Bootstrap3-Fluid.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap2.cshtml" /> <Content Include="Views\Partials\Grid\Bootstrap2.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap2-Fluid.cshtml" /> <Content Include="Views\Partials\Grid\Bootstrap2-Fluid.cshtml" />
<Content Include="Views\Partials\Home\GitHubContributors.cshtml" />
<Content Include="Views\Partials\Home\Meetups.cshtml" /> <Content Include="Views\Partials\Home\Meetups.cshtml" />
<None Include="web.Debug.config"> <None Include="web.Debug.config">
<DependentUpon>web.config</DependentUpon> <DependentUpon>web.config</DependentUpon>
@@ -1,6 +1,6 @@
@using OurUmbraco.Our.Models @using OurUmbraco.Our.Models
@using Skybrud.Social.Meetup.Models.Events @using Skybrud.Social.Meetup.Models.Events
@inherits OurUmbracoTemplatePage @inherits OurUmbracoTemplatePage
@{ @{
var homeNotificationText = Model.Content.GetPropertyValue<string>("homeOnlyBanner"); var homeNotificationText = Model.Content.GetPropertyValue<string>("homeOnlyBanner");
var showHomeNotification = string.IsNullOrWhiteSpace(homeNotificationText) == false; var showHomeNotification = string.IsNullOrWhiteSpace(homeNotificationText) == false;
@@ -40,7 +40,7 @@
<!-- Search end --> <!-- Search end -->
<style> <style>
.bannertext p{ .bannertext p {
line-height: 1.4rem; line-height: 1.4rem;
} }
</style> </style>
@@ -61,6 +61,7 @@
{ {
@ForumActivity() @ForumActivity()
@Meetups() @Meetups()
@GitHubContributors()
@TwitterSearch() @TwitterSearch()
@Html.Partial("home/documentation") @Html.Partial("home/documentation")
} }
@@ -69,6 +70,7 @@ else
@Html.Partial("home/documentation") @Html.Partial("home/documentation")
@ForumActivity() @ForumActivity()
@Meetups() @Meetups()
@GitHubContributors()
@TwitterSearch() @TwitterSearch()
} }
@@ -130,6 +132,43 @@ else
</section> </section>
} }
@helper GitHubContributors()
{
<section class="github-contributors forum">
<div class="container">
<div class="row">
<div class="col-md-12">
<h1 class="text-center">GitHub Contributions</h1>
<p>
Contributions to Umbraco GitHub repositories
<small class="link-list">
Contributions to default branches for
<a href="https://github.com/umbraco/Umbraco-CMS" target="_blank" title="Umbraco-CMS">Umbraco-CMS</a>,
<a href="https://github.com/umbraco/UmbracoDocs" target="_blank" title="UmbracoDocs">UmbracoDocs</a>,
<a href="https://github.com/umbraco/OurUmbraco" target="_blank" title="OurUmbraco">OurUmbraco</a>,
<a href="https://github.com/umbraco/Umbraco.Deploy.Contrib" target="_blank" title="Umbraco.Deploy.Contrib">Umbraco.Deploy.Contrib</a>,
<a href="https://github.com/umbraco/Umbraco.Courier.Contrib" target="_blank" title="Umbraco.Courier.Contrib">Umbraco.Courier.Contrib</a> and
<a href="https://github.com/umbraco/Umbraco.Deploy.ValueConnectors" target="_blank" title="Umbraco.Deploy.ValueConnectors">Umbraco.Deploy.ValueConnectors</a> repos
</small>
</p>
</div>
<div class="col-md-12">
<small>GitHub contributors</small>
</div>
<div class="col-md-12 flex forum-thread" id="github-contributors">
<h2>Loading GitHub contributors...</h2>
</div>
<div class="col-md-12 goto-forum">
<a class="button green" href="https://github.com/umbraco" target="_blank">Contribute to Umbraco on GitHub &rarr;</a>
</div>
</div>
</div>
</section>
}
@helper Meetups() { @helper Meetups() {
<section class="forum"> <section class="forum">
<div class="container"> <div class="container">
@@ -1,9 +1,14 @@
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function () {
function loadAllGitHubContributors() {
$('#github-contributors').addClass('all');
}
$(document).ready(function() {
try { try {
$("#twitter-search").load("@Url.Action("TwitterSearchResult", "TwitterSearch", new { numberOfResults = 6 })"); $("#twitter-search").load("@Url.Action("TwitterSearchResult", "TwitterSearch", new {numberOfResults = 6})");
} } catch (errTwitter) {
catch (errTwitter) {
console.log("Couldn't load Twitter feed", errTwitter.message); console.log("Couldn't load Twitter feed", errTwitter.message);
} }
@@ -17,10 +22,16 @@
} }
try { try {
$("#forum-activity").load("@Url.Action("LatestActivity", "LatestActivity", new { numberOfTopics = 6 })"); $("#forum-activity").load("@Url.Action("LatestActivity", "LatestActivity", new {numberOfTopics = 6})");
} catch (errForum) {
console.log("Couldn't load latest forum activity", errForum.message);
}
try {
$("#github-contributors").load("@Url.Action("GitHubGetContributorsResult", "GitHubContributor")");
} }
catch (errForum) { catch (errForum) {
console.log("Couldn't load latest forum activity", errForum.message); console.log("Couldn't load latest GitHub contributor activity", errForum.message);
} }
}); });
</script> </script>
@@ -0,0 +1,35 @@
@model OurUmbraco.Community.Models.GitHubContributorsModel
@if (Model.Contributors.Any())
{
foreach (var contributor in Model.Contributors)
{
var author = contributor.Author;
if (author != null)
{
<a href="@author.HtmlUrl" class="contributor" target="_blank" title="@author.Login">
<div class="avatar">
<img alt="@author.Login" src="@author.AvatarUrl&s=112" />
<span class="contrib-count" title="@(contributor.TotalCommits + " " + (contributor.TotalCommits == 1 ? "contribution" : "contributions"))">
@contributor.TotalCommits
</span>
<div class="counts">
Additions<br />
<strong>@contributor.TotalAdditions</strong><br />
<br />
Deletions<br />
<strong>@contributor.TotalDeletions</strong>
</div>
</div>
</a>
}
}
<div class="loadmore">
<a class="button transparent" href="#" onclick="loadAllGitHubContributors(); return false;">Load more</a>
</div>
}
else
{
<h2>Could not load recent GitHub contributors.</h2>
}
+16
View File
@@ -0,0 +1,16 @@
Aaen
clausjensen
emilwangaa
hartvig
hemraker
madsrasmussen
mikkelhm
nul800sebastiaan
perploug
Shazwazza
simonbusborg
sitereactor
sofietoft
umbracoci
warrenbuckley
zpqrtbnk
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using OurUmbraco.Community.Models;
using OurUmbraco.Our.Api;
using RestSharp;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Web.Mvc;
namespace OurUmbraco.Community.Controllers
{
public class GitHubContributorController : SurfaceController
{
/// <summary>
/// Repositories to include in the combination of contributions
/// </summary>
private readonly string[] Repositories =
{
"Umbraco-CMS",
"UmbracoDocs",
"OurUmbraco",
"Umbraco.Deploy.Contrib",
"Umbraco.Courier.Contrib",
"Umbraco.Deploy.ValueConnectors"
};
/// <summary>
/// Gets data for all GitHub contributors for all listed Umbraco repositories,
/// excluding the GitHub IDs of the HQ contributors from the text file list
/// </summary>
/// <returns></returns>
public ActionResult GitHubGetContributorsResult()
{
var model = new GitHubContributorsModel();
try
{
string configPath = Server.MapPath("~/config/githubhq.txt");
if (!System.IO.File.Exists(configPath))
{
LogHelper.Debug<GitHubContributorController>("Config file was not found: " + configPath);
return PartialView("~/Views/Partials/Home/GitHubContributors.cshtml", model);
}
string[] login = System.IO.File.ReadAllLines(configPath).Where(x => x.Trim() != "").Distinct().ToArray();
var contributors = ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<List<GitHubGlobalContributorModel>>("UmbracoGitHubContributors",
() =>
{
var githubController = new GitHubController();
var gitHubContributors = new List<GitHubContributorModel>();
foreach (var repo in Repositories)
{
var response = githubController.GetAllRepoContributors(repo);
if (response.StatusCode == HttpStatusCode.OK &&
response.ResponseStatus == ResponseStatus.Completed)
{
gitHubContributors.AddRange(response.Data);
}
else
{
LogHelper.Warn<IGitHubContributorsModel>(string.Format("Invalid HTTP response for repository {0}", repo));
}
}
var filteredContributors = gitHubContributors
.Where(g => !login.Contains(g.Author.Login))
.GroupBy(g => g.Author.Id)
.OrderByDescending(c => c.Sum(g => g.Total));
List<GitHubGlobalContributorModel> temp = new List<GitHubGlobalContributorModel>();
foreach (var group in filteredContributors)
{
temp.Add(new GitHubGlobalContributorModel(group));
}
return temp;
}, TimeSpan.FromDays(1));
model.Contributors = contributors;
}
catch (Exception ex)
{
LogHelper.Error<IGitHubContributorsModel>("Could not get GitHub Contributors", ex);
}
return PartialView("~/Views/Partials/Home/GitHubContributors.cshtml", model);
}
}
}
@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Linq;
using OurUmbraco.Community.Models;
namespace OurUmbraco.Community.Controllers
{
public class GitHubGlobalContributorModel
{
public List<GitHubContributorModel> Items { get; set; }
public int Id
{
get { return Author.Id; }
}
public int TotalCommits
{
get { return Items.Sum(x => x.Total); }
}
public int TotalAdditions
{
get { return Items.Sum(x => x.TotalAdditions); }
}
public int TotalDeletions
{
get { return Items.Sum(x => x.TotalDeletions); }
}
public Author Author
{
get { return Items.First().Author; }
}
public GitHubGlobalContributorModel(IEnumerable<GitHubContributorModel> items)
{
Items = items.ToList();
}
}
}
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using OurUmbraco.Community.Controllers;
namespace OurUmbraco.Community.Models
{
public class GitHubContributorsModel : IGitHubContributorsModel
{
public List<GitHubGlobalContributorModel> Contributors { get; set; }
}
}
@@ -0,0 +1,117 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace OurUmbraco.Community.Models
{
[DataContract]
public class GitHubContributorModel : IGitHubContributorModel
{
private List<Week> _weeks;
public int Total { get; set; }
public int TotalAdditions { get; set; }
public int TotalDeletions { get; set; }
[DataMember(Name = "weeks")]
public List<Week> Weeks
{
get { return _weeks; }
set
{
_weeks = value;
int totalAdditions = 0;
int totalDeletions = 0;
foreach (var week in _weeks)
{
totalDeletions += week.D;
totalAdditions += week.A;
}
TotalAdditions = totalAdditions;
TotalDeletions = totalDeletions;
}
}
public Author Author { get; set; }
}
[DataContract]
public class Week
{
/// <summary>
/// Timestamp
/// </summary>
public int W { get; set; }
/// <summary>
/// Additions
/// </summary>
public int A { get; set; }
/// <summary>
/// Deletions
/// </summary>
public int D { get; set; }
/// <summary>
/// Commits
/// </summary>
public int C { get; set; }
}
[DataContract]
public class Author
{
public string Login { get; set; }
public int Id { get; set; }
[DataMember(Name = "avatar_url")]
public string AvatarUrl { get; set; }
[DataMember(Name = "gravatar_id")]
public string GravatarId { get; set; }
public string Url { get; set; }
[DataMember(Name = "html_url")]
public string HtmlUrl { get; set; }
[DataMember(Name = "followers_url")]
public string FollowersUrl { get; set; }
[DataMember(Name = "following_url")]
public string FollowingsUrl { get; set; }
[DataMember(Name = "gists_url")]
public string GistsUrl { get; set; }
[DataMember(Name = "starred_url")]
public string StarredUrl { get; set; }
[DataMember(Name = "subscriptions_url")]
public string SubscriptionsUrl { get; set; }
[DataMember(Name = "organizations_url")]
public string OrganizationsUrl { get; set; }
[DataMember(Name = "repos_url")]
public string ReposUrl { get; set; }
[DataMember(Name = "events_url")]
public string EventsUrl { get; set; }
[DataMember(Name = "received_events_url")]
public string ReceivedEventsUrl { get; set; }
public string Type { get; set; }
[DataMember(Name = "site_admin")]
public bool SiteAdmin { get; set; }
}
}
@@ -0,0 +1,6 @@
namespace OurUmbraco.Community.Models
{
public interface IGitHubContributorModel
{
}
}
@@ -0,0 +1,6 @@
namespace OurUmbraco.Community.Models
{
public interface IGitHubContributorsModel
{
}
}
+27
View File
@@ -0,0 +1,27 @@
using System.Collections.Generic;
using OurUmbraco.Community.Models;
using RestSharp;
namespace OurUmbraco.Our.Api
{
public class GitHubController
{
private const string RepositoryOwner = "Umbraco";
private const string GitHubApiClient = "https://api.github.com";
private const string UserAgent = "OurUmbraco";
/// <summary>
/// Get all contributors from GitHub Umbraco repositories
/// </summary>
/// <param name="repo"></param>
/// <returns></returns>
public IRestResponse<List<GitHubContributorModel>> GetAllRepoContributors(string repo)
{
var client = new RestClient(GitHubApiClient);
var request = new RestRequest(string.Format("/repos/{0}/{1}/stats/contributors", RepositoryOwner, repo), Method.GET);
client.UserAgent = UserAgent;
var response = client.Execute<List<GitHubContributorModel>>(request);
return response;
}
}
}
+7
View File
@@ -403,10 +403,16 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CamelCaseFormatter.cs" /> <Compile Include="CamelCaseFormatter.cs" />
<Compile Include="Community\Controllers\GitHubContributorController.cs" />
<Compile Include="Community\Controllers\MeetupsController.cs" /> <Compile Include="Community\Controllers\MeetupsController.cs" />
<Compile Include="Community\Controllers\GitHubGlobalContributorModel.cs" />
<Compile Include="Community\Controllers\TwitterSearchController.cs" /> <Compile Include="Community\Controllers\TwitterSearchController.cs" />
<Compile Include="Community\Models\GitHubContributorModel.cs" />
<Compile Include="Community\Models\IGitHubContributorModel.cs" />
<Compile Include="Community\Models\MeetupEventsModel.cs" /> <Compile Include="Community\Models\MeetupEventsModel.cs" />
<Compile Include="Community\Models\MeetupItem.cs" /> <Compile Include="Community\Models\MeetupItem.cs" />
<Compile Include="Community\Models\GitHubContributorsModel.cs" />
<Compile Include="Community\Models\IGitHubContributorsModel.cs" />
<Compile Include="Community\Models\TweetsModel.cs" /> <Compile Include="Community\Models\TweetsModel.cs" />
<Compile Include="CustomDateTimeConvertor.cs" /> <Compile Include="CustomDateTimeConvertor.cs" />
<Compile Include="Documentation\Busineslogic\ConventionExtensions.cs" /> <Compile Include="Documentation\Busineslogic\ConventionExtensions.cs" />
@@ -519,6 +525,7 @@
<Compile Include="NotificationsWeb\Services\NotificationService.cs" /> <Compile Include="NotificationsWeb\Services\NotificationService.cs" />
<Compile Include="NotificationsWeb\Singleton.cs" /> <Compile Include="NotificationsWeb\Singleton.cs" />
<Compile Include="Our\Api\CommunityController.cs" /> <Compile Include="Our\Api\CommunityController.cs" />
<Compile Include="Our\Api\GitHubController.cs" />
<Compile Include="Our\Api\SearchController.cs" /> <Compile Include="Our\Api\SearchController.cs" />
<Compile Include="Our\Api\YouTrackApiController.cs" /> <Compile Include="Our\Api\YouTrackApiController.cs" />
<Compile Include="Our\Businesslogic\ProjectContributor.cs" /> <Compile Include="Our\Businesslogic\ProjectContributor.cs" />