Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reports for issues and comments by day #216

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/_data/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
url: "/"
- title: "Contributors"
url: "/users-contributors"
- title: "Issues & Comments"
url: "/users-communication"
- title: "Activity"
url: "/users-activity"
- title: "Git Versions"
Expand Down
163 changes: 163 additions & 0 deletions docs/users-communication.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
---
layout: default
title: Issues & Comments
permalink: /users-communication
---

<div id="issues" class="chart-placeholder">
<h3>Issues</h3>
<canvas
data-url="{{ site.dataURL }}/issues.tsv"
data-type="history"
data-config='{
"views":
[
{
"label": "2 m",
"tooltip": "Show the last 2 months",
"aggregate": false,
"series":
[
"issues created",
"issues closed",
"issues updated"
],
"visibleSeries":
[
"issues created",
"issues closed",
"issues updated"
],
"slice": [0, 61]
},
{
"label": "2 y",
"tooltip": "Show the last 2 years",
"aggregate":
{
"period": "week",
"method": "sum"
},
"series":
[
"issues created",
"issues closed",
"issues updated"
],
"visibleSeries":
[
"issues created",
"issues closed",
"issues updated"
],
"slice": [0, 106],
"default": true
},
{
"label": "all",
"tooltip": "Show all data",
"aggregate":
{
"period": "week",
"method": "sum"
},
"series":
[
"issues created",
"issues closed",
"issues updated"
],
"visibleSeries":
[
"issues created",
"issues closed",
"issues updated"
]
}
]
}'></canvas>
<div class="info-box">
<p>
<i>Issues</i> shows how many GitHub issues were created, updated, or closed. <i>issues updated</i> excludes creating or closing an issue.
</p>
</div>
</div>

<div id="comments" class="chart-placeholder">
<h3>Comments</h3>
<canvas
data-url="{{ site.dataURL }}/comments.tsv"
data-type="history"
data-config='{
"views":
[
{
"label": "2 m",
"tooltip": "Show the last 2 months",
"aggregate": false,
"series":
[
"issue comments",
"pull request comments",
"commit comments"
],
"visibleSeries":
[
"issue comments",
"pull request comments",
"commit comments"
],
"slice": [0, 61]
},
{
"label": "2 y",
"tooltip": "Show the last 2 years",
"aggregate":
{
"period": "week",
"method": "sum"
},
"series":
[
"issue comments",
"pull request comments",
"commit comments"
],
"visibleSeries":
[
"issue comments",
"pull request comments",
"commit comments"
],
"slice": [0, 106],
"default": true
},
{
"label": "all",
"tooltip": "Show all data",
"aggregate":
{
"period": "week",
"method": "sum"
},
"series":
[
"issue comments",
"pull request comments",
"commit comments"
],
"visibleSeries":
[
"issue comments",
"pull request comments",
"commit comments"
]
}
]
}'></canvas>
<div class="info-box">
<p>
<i>Comments</i> shows how many comments ware created for issues, pull requests, and commits. <i>pull request comments</i> includes comments on the PR as well as the ones for reviews.
</p>
</div>
</div>
47 changes: 47 additions & 0 deletions updater/reports/ReportComments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from .ReportDailySQL import *

# Lists how many issues got created, closed, were commented on, and number of comments per day
class ReportComments(ReportDailySQL):
def name(self):
return "comments"

def updateDailyData(self):
self.header, newData = self.parseData(self.executeQuery(self.query(self.timeRangeToUpdate())))
self.data.extend(newData)
self.truncateData(self.timeRangeTotal())
self.sortDataByDate()

# Collects the issues closed in time range
def subquery(self, timeRange, table, extra_from=None, extra_where=None):
return '''
SELECT
DATE_FORMAT(''' + table + '''.created_at, "%Y-%m-%d") AS date,
COUNT(*) AS count
FROM
''' + table + '''
JOIN users ON users.id = ''' + table + '''.user_id ''' + (("\n\t\t\t\t\t" + extra_from) if extra_from else '') + '''
WHERE
CAST(''' + table + '''.created_at AS DATE) BETWEEN
"''' + str(timeRange[0]) + '''" AND "''' + str(timeRange[1]) + '''"
''' + self.andExcludedUsers("users.login") + (("\n\t\t\t\t\t" + extra_where) if extra_where else '') + '''
GROUP BY
date_format(''' + table + '''.created_at, "%Y-%m-%d")'''

# Collects the number of issues created, closed, commented, and number of comments
def query(self, timeRange):
# `alldays` is used as a basis for LEFT JOIN, to prevent issues when querying multiple days, e.g. for initial run of the new report
return '''
SELECT
alldays.date AS date,
IFNULL(i_issues.count, 0) AS "issue comments",
IFNULL(pr_issues.count, 0) AS "pull request issue comments",
IFNULL(reviews.count, 0) AS "pull request review comments",
IFNULL(pr_issues.count, 0) + IFNULL(reviews.count, 0) AS "pull request comments",
IFNULL(commits.count, 0) AS "commit comments"
FROM
(''' + self.allDaysToUpdateUnion(timeRange) + ''') AS alldays
LEFT JOIN (''' + self.subquery(timeRange, "issue_comments", "JOIN issues ON issues.id = issue_comments.issue_id", "AND issues.pull_request_id IS NULL") + ''') AS i_issues ON alldays.date = i_issues.date
LEFT JOIN (''' + self.subquery(timeRange, "issue_comments", "JOIN issues ON issues.id = issue_comments.issue_id", "AND issues.pull_request_id IS NOT NULL") + ''') AS pr_issues ON alldays.date = pr_issues.date
LEFT JOIN (''' + self.subquery(timeRange, "commit_comments") + ''') AS commits ON alldays.date = commits.date
LEFT JOIN (''' + self.subquery(timeRange, "pull_request_review_comments") + ''') AS reviews ON alldays.date = reviews.date
ORDER BY date DESC'''
17 changes: 17 additions & 0 deletions updater/reports/ReportDailySQL.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from .ReportDaily import *

# A daily report that also updates days in the past, given by timeRangeToUpdate
class ReportDailySQL(ReportDaily):

def allDaysToUpdateUnion(self, timeRange):
# This method creates a table column of every single date in timeRange.
# It enables querying all results for timeRange in one single SQL query.
# Furthermore the result will include 0 for days without results, which
# makes the graphs look nicer especially on newly provisioned systems.
younger = max(timeRange)
older = min(timeRange)
snipped = "SELECT '" + str(younger) + "' AS date"
while (younger > older):
younger -= datetime.timedelta(1)
snipped += " UNION SELECT '" + str(younger) + "'"
return snipped
45 changes: 45 additions & 0 deletions updater/reports/ReportIssues.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from .ReportDailySQL import *

# Lists how many issues got created, closed, and were updated per day
class ReportIssues(ReportDailySQL):
def name(self):
return "issues"

def updateDailyData(self):
self.header, newData = self.parseData(self.executeQuery(self.query(self.timeRangeToUpdate())))
self.data.extend(newData)
self.truncateData(self.timeRangeTotal())
self.sortDataByDate()

# Collects the issues closed in time range
def subquery(self, timeRange, type, extra=None):
return '''
SELECT
DATE_FORMAT(issues.''' + type + ''', "%Y-%m-%d") AS date,
COUNT(*) AS count
FROM
issues
JOIN users ON users.id = issues.user_id
WHERE
issues.pull_request_id IS NULL AND
CAST(issues.''' + type + ''' AS DATE) BETWEEN
"''' + str(timeRange[0]) + '''" AND "''' + str(timeRange[1]) + '''"
''' + self.andExcludedUsers("users.login") + (("\n\t\t\t\t\t" + extra) if extra else '') + '''
GROUP BY
date_format(issues.''' + type + ''', "%Y-%m-%d")'''

# Collects the number of issues created, closed, commented, and number of comments
def query(self, timeRange):
# `alldays` is used as a basis for LEFT JOIN, to prevent issues when querying multiple days, e.g. for initial run of the new report
return '''
SELECT
alldays.date AS date,
IFNULL(created.count, 0) AS "issues created",
IFNULL(updated.count, 0) AS "issues updated",
IFNULL(closed.count, 0) AS "issues closed"
FROM
(''' + self.allDaysToUpdateUnion(timeRange) + ''') AS alldays
LEFT JOIN (''' + self.subquery(timeRange, "created_at") + ''') AS created ON alldays.date = created.date
LEFT JOIN (''' + self.subquery(timeRange, "updated_at", "AND issues.created_at != issues.updated_at AND issues.closed_at != issues.updated_at") + ''') AS updated ON alldays.date = updated.date
LEFT JOIN (''' + self.subquery(timeRange, "closed_at") + ''') AS closed ON alldays.date = closed.date
ORDER BY date DESC'''
4 changes: 4 additions & 0 deletions updater/update-stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
from reports.ReportTeamsTotal import *
from reports.ReportTokenlessAuth import *
from reports.ReportUsers import *
from reports.ReportIssues import *
from reports.ReportComments import *

def writeMeta(dataDirectory):
outputFilePath = os.path.join(dataDirectory, "meta.tsv")
Expand Down Expand Up @@ -104,6 +106,8 @@ def main():
ReportTeamsTotal(configuration, dataDirectory, metaStats).update()
ReportTokenlessAuth(configuration, dataDirectory, metaStats).update()
ReportUsers(configuration, dataDirectory, metaStats).update()
ReportIssues(configuration, dataDirectory, metaStats).update()
ReportComments(configuration, dataDirectory, metaStats).update()

# Write meta infos
writeMeta(dataDirectory)
Expand Down