diff --git a/docs/_data/navigation.yml b/docs/_data/navigation.yml
index 096c1d83..d93dad60 100644
--- a/docs/_data/navigation.yml
+++ b/docs/_data/navigation.yml
@@ -43,6 +43,8 @@
url: "/housekeeping-git-requests"
- title: "API Requests"
url: "/housekeeping-api-requests"
+ - title: "Abandoned Organizations"
+ url: "/housekeeping-abandoned-orgs"
- title: "Forks"
url: "/housekeeping-forks"
- title: "Recommendations"
diff --git a/docs/demo-data/organizations-abandoned-detailed.tsv b/docs/demo-data/organizations-abandoned-detailed.tsv
new file mode 100644
index 00000000..b4600b38
--- /dev/null
+++ b/docs/demo-data/organizations-abandoned-detailed.tsv
@@ -0,0 +1,4 @@
+organization last push
+old-org 2015-03-31
+very-old-org 2015-08-19
+granpa-org 2016-01-08
diff --git a/docs/demo-data/organizations-abandoned.tsv b/docs/demo-data/organizations-abandoned.tsv
new file mode 100644
index 00000000..0f4ef555
--- /dev/null
+++ b/docs/demo-data/organizations-abandoned.tsv
@@ -0,0 +1,4 @@
+date abandoned organizations
+2018-01-25 84
+2018-01-24 90
+2018-01-23 92
diff --git a/docs/housekeeping-abandoned-orgs.html b/docs/housekeeping-abandoned-orgs.html
new file mode 100644
index 00000000..d2e7999c
--- /dev/null
+++ b/docs/housekeeping-abandoned-orgs.html
@@ -0,0 +1,26 @@
+---
+layout: default
+title: Forks
+permalink: /housekeeping-abandoned-orgs
+---
+
+
+
Abandoned Organizations
+
+
+
+ An organizations is considered abandoned if none of its repositories has received a push in the last year (ignoring archived repositories).
+
+
+ If the content still has value, then you could archive all repositories in these organizations to emphasize the fact that they are not maintained anymore.
+ If the content is not valuable anymore, then you could delete the organization to reduce clutter on your GitHub Enterprise appliance.
+
+
+
+
+
diff --git a/updater/reports/ReportOrgsAbandoned.py b/updater/reports/ReportOrgsAbandoned.py
new file mode 100644
index 00000000..a8476f13
--- /dev/null
+++ b/updater/reports/ReportOrgsAbandoned.py
@@ -0,0 +1,38 @@
+from .ReportDaily import *
+
+# Find the organizations that have not received a push for the longest time.
+# Only look at organizations that have not received a push for at least one
+# year. Only look at repositories that are still maintained (not archived!).
+class ReportOrgsAbandoned(ReportDaily):
+ def name(self):
+ return "organizations-abandoned"
+
+ def updateDailyData(self):
+ self.detailedHeader, self.detailedData = self.parseData(self.executeQuery(self.query()))
+ if len(self.data) == 0:
+ self.header = ["date", "abandoned organizations"]
+ self.data.append([str(self.yesterday()), len(self.detailedData)])
+ self.truncateData(self.timeRangeTotal())
+ self.sortDataByDate()
+
+ def query(self):
+ query = '''
+ SELECT
+ users.login AS "organization",
+ DATE(MAX(pushes.created_at)) AS "last push"
+ FROM
+ repositories
+ JOIN users ON repositories.owner_id = users.id
+ JOIN pushes ON pushes.repository_id = repositories.id
+ WHERE
+ users.type = "organization"
+ AND repositories.maintained = 1 ''' + \
+ self.andExcludedEntities("users.login") + '''
+ GROUP BY
+ users.id
+ HAVING
+ CAST(MAX(pushes.created_at) AS DATE) < "''' + str(self.daysAgo(365)) + '''"
+ ORDER BY
+ MAX(pushes.created_at)
+ '''
+ return query
diff --git a/updater/update-stats.py b/updater/update-stats.py
index 1b1c65df..67beffa8 100755
--- a/updater/update-stats.py
+++ b/updater/update-stats.py
@@ -16,6 +16,7 @@
from reports.ReportOrgActivity import *
from reports.ReportOrgCollaboration import *
from reports.ReportOrgOwners import *
+from reports.ReportOrgsAbandoned import *
from reports.ReportOrgsTotal import *
from reports.ReportPRByOrg import *
from reports.ReportPRByRepo import *
@@ -86,6 +87,7 @@ def main():
ReportOrgActivity(configuration, dataDirectory, metaStats).update()
ReportOrgCollaboration(configuration, dataDirectory, metaStats).update()
ReportOrgOwners(configuration, dataDirectory, metaStats).update()
+ ReportOrgsAbandoned(configuration, dataDirectory, metaStats).update()
ReportOrgsTotal(configuration, dataDirectory, metaStats).update()
ReportPRByOrg(configuration, dataDirectory, metaStats).update()
ReportPRByRepo(configuration, dataDirectory, metaStats).update()