summaryrefslogtreecommitdiff
path: root/scripts/publish_github_stats.js
blob: f79a5082d0134c4d09a63d5a16edc4c475e998ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env node

const assert = require('assert');
const jwt = require('jsonwebtoken');
const github = require('@octokit/rest')();
const zlib = require('zlib');
const AWS = require('aws-sdk');

const SIZE_CHECK_APP_ID = 14028;
const SIZE_CHECK_APP_INSTALLATION_ID = 229425;

// Error handling

process.on('unhandledRejection', error => {
  console.log(error);
  process.exit(1)
});

// Github authorization

const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY'];
if (!pk) {
  console.log('Fork PR; not publishing size.');
  process.exit(0);
}

const key = Buffer.from(pk, 'base64').toString('binary');
const payload = {
  exp: Math.floor(Date.now() / 1000) + 60,
  iat: Math.floor(Date.now() / 1000),
  iss: SIZE_CHECK_APP_ID
};

const token = jwt.sign(payload, key, {algorithm: 'RS256'});
github.authenticate({type: 'app', token});

// Metrics: Github statistics
let openIssuesTotal = 0;
let openIssuesTotalFromNonMembers = 0;
let openIssuesTotalCore = 0;
let openIssuesTotalAndroid = 0;
let openIssuesTotalIOS = 0;
let openIssuesTotalGLJSParity = 0;
let openPullRequestsTotal = 0;
let openPullRequestsTotalFromNonMembers = 0;
let openPullRequestsSinceLastMonth = 0;
let openPullRequestsSinceLastMonthFromNonMembers = 0;

function collectMetricsFromIssues(issues) {
  const oneMonthAgo = function() { let date = new Date(); date.setMonth(date.getMonth() - 1); return date; }();

  // Metrics
  issues.data.forEach(function (issue) {
    const issueCreatedAt = new Date(issue.created_at);
    const isMapboxAuthor = issue.author_association === "MEMBER";

    if (issue.pull_request) {
      openPullRequestsTotal++;
      if (!isMapboxAuthor) {
        openPullRequestsTotalFromNonMembers++;
      }
      if (issueCreatedAt >= oneMonthAgo) {
        openPullRequestsSinceLastMonth++;
        if (!isMapboxAuthor) {
          openPullRequestsSinceLastMonthFromNonMembers++;
        }
      }
    } else {
      openIssuesTotal++;
      if (!isMapboxAuthor) {
        openIssuesTotalFromNonMembers++;
      }
      issue.labels.forEach(function (label) {
        switch (label.name) {
          case "Core":
            openIssuesTotalCore++;
            break;
          case "Android":
            openIssuesTotalAndroid++;
            break;
          case "iOS":
            openIssuesTotalIOS++;
            break;
          case "GL JS parity":
            openIssuesTotalGLJSParity++;
            break;
          default:
            break;
        }
      });
    }
  });
}

function publishMetrics() {
  let metrics = {
    'created_at': new Date().toISOString().substring(0, 10),
    'open_issues_total': openIssuesTotal,
    'open_issues_total_from_non_members': openIssuesTotalFromNonMembers,
    'open_issues_total_core': openIssuesTotalCore,
    'open_issues_total_android': openIssuesTotalAndroid,
    'open_issues_total_ios': openIssuesTotalIOS,
    'open_issues_total_gl_js_parity': openIssuesTotalGLJSParity,
    'open_pull_requests_total': openPullRequestsTotal,
    'open_pull_requests_total_from_non_members': openPullRequestsTotalFromNonMembers,
    'open_pull_requests_since_last_month': openPullRequestsSinceLastMonth,
    'open_pull_requests_since_last_month_from_non_members': openPullRequestsSinceLastMonthFromNonMembers
  };

  var promise = new AWS.S3({region: 'us-east-1'}).putObject({
    Body: zlib.gzipSync(JSON.stringify(metrics)),
    Bucket: 'mapbox-loading-dock',
    Key: `raw/mobile_staging.github_stats/${metrics['created_at']}/METRIC.json.gz`,
    CacheControl: 'max-age=300',
    ContentEncoding: 'gzip',
    ContentType: 'application/json'
  }).promise();

  return Promise.all([promise]).then(data => {
    return console.log("Successfully uploaded Github Stats metrics to S3");
  }).catch(err => {
    console.log("Error uploading Github Stats metrics to S3 " + err.message);
    return err;
  });
}

function recursiveListForRepo(query) {
  assert(query);
  query.then(result => {
    collectMetricsFromIssues(result);
    if (github.hasNextPage(result)) {
      recursiveListForRepo(github.getNextPage(result));
    } else {
      publishMetrics();
    }
  }).catch(error => {
    console.log("Error fetching the repository issues list: " + err.message);
  });
}

github.apps.createInstallationToken({ installation_id: SIZE_CHECK_APP_INSTALLATION_ID })
  .then(({data}) => {
    github.authenticate({ type: 'token', token: data.token });
  })
  .then(() => {
    recursiveListForRepo(github.issues.listForRepo({ owner: 'mapbox', repo: 'mapbox-gl-native', state: 'open', per_page: 100 }));
  });