Skip to content
This repository was archived by the owner on Aug 11, 2021. It is now read-only.

Commit 738449d

Browse files
lazywithclassiarna
authored andcommitted
metrics: Add sendAnonymousCLIMetrics
Fixes: #138 Credit: @lazywithclass Credit: @iarna Reviewed-By: @iarna PR-URL: #139
1 parent 0e0a707 commit 738449d

File tree

6 files changed

+134
-21
lines changed

6 files changed

+134
-21
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,20 @@ Publish a package to the registry.
183183

184184
Note that this does not create the tarball from a folder.
185185

186+
### client.sendAnonymousCLIMetrics(uri, params, cb)
187+
188+
- `uri` {String} Base URL for the registry.
189+
- `params` {Object} Object containing per-request properties.
190+
- `metricId` {String} A uuid unique to this dataset.
191+
- `metrics` {Object} The metrics to share with the registry, with the following properties:
192+
- `from` {Date} When the first data in this report was collected.
193+
- `to` {Date} When the last data in this report was collected. Usually right now.
194+
- `successfulInstalls` {Number} The number of successful installs in this period.
195+
- `failedInstalls` {Number} The number of installs that ended in error in this period.
196+
- `cb` {Function}
197+
198+
PUT a metrics object to the `/-/npm/anon-metrics/v1/` endpoint on the registry.
199+
186200
### client.star(uri, params, cb)
187201

188202
* `uri` {String} The complete registry URI for the package to star.

index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,22 @@ function RegClient (config) {
5454
// lib/group-name/operation.js -> client.groupName.operation
5555
var stat = fs.statSync(entry)
5656
if (stat.isDirectory()) {
57-
var groupName = f.replace(/-([a-z])/, dashToCamel)
57+
var groupName = f.replace(/-([a-z])/gi, dashToCamel)
5858
fs.readdirSync(entry).forEach(function (f) {
5959
if (!f.match(/\.js$/)) return
6060

6161
if (!client[groupName]) {
6262
// keep client.groupName.operation from stomping client.operation
6363
client[groupName] = Object.create(client)
6464
}
65-
var name = f.replace(/\.js$/, '').replace(/-([a-z])/, dashToCamel)
65+
var name = f.replace(/\.js$/, '').replace(/-([a-z])/gi, dashToCamel)
6666
client[groupName][name] = require(join(entry, f))
6767
})
6868
return
6969
}
7070

7171
if (!f.match(/\.js$/)) return
72-
var name = f.replace(/\.js$/, '').replace(/-([a-z])/, dashToCamel)
72+
var name = f.replace(/\.js$/, '').replace(/-([a-z])/gi, dashToCamel)
7373
client[name] = require(entry)
7474
})
7575
}

lib/request.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,25 @@ function regRequest (uri, params, cb_) {
4242
return cb(new Error('trying to change user document without writing(?!)'))
4343
}
4444

45-
// new users can *not* use auth, because they don't *have* auth yet
46-
if (isUserChange) {
47-
this.log.verbose('request', 'updating existing user; sending authorization')
48-
params.authed = true
49-
} else if (isNewUser) {
50-
this.log.verbose('request', "new user, so can't send auth")
51-
params.authed = false
52-
} else if (alwaysAuth) {
53-
this.log.verbose('request', 'always-auth set; sending authorization')
54-
params.authed = true
55-
} else if (isWrite) {
56-
this.log.verbose('request', 'sending authorization for write operation')
57-
params.authed = true
58-
} else {
59-
// most of the time we don't want to auth
60-
this.log.verbose('request', 'no auth needed')
61-
params.authed = false
45+
if (params.authed == null) {
46+
// new users can *not* use auth, because they don't *have* auth yet
47+
if (isUserChange) {
48+
this.log.verbose('request', 'updating existing user; sending authorization')
49+
params.authed = true
50+
} else if (isNewUser) {
51+
this.log.verbose('request', "new user, so can't send auth")
52+
params.authed = false
53+
} else if (alwaysAuth) {
54+
this.log.verbose('request', 'always-auth set; sending authorization')
55+
params.authed = true
56+
} else if (isWrite) {
57+
this.log.verbose('request', 'sending authorization for write operation')
58+
params.authed = true
59+
} else {
60+
// most of the time we don't want to auth
61+
this.log.verbose('request', 'no auth needed')
62+
params.authed = false
63+
}
6264
}
6365

6466
var self = this

lib/send-anonymous-CLI-metrics.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module.exports = send
2+
3+
var assert = require('assert')
4+
var url = require('url')
5+
6+
function send (registryUrl, params, cb) {
7+
assert(typeof registryUrl === 'string', 'must pass registry URI')
8+
assert(params && typeof params === 'object', 'must pass params')
9+
assert(typeof cb === 'function', 'must pass callback')
10+
11+
var uri = url.resolve(registryUrl, '-/npm/anon-metrics/v1/' +
12+
encodeURIComponent(params.metricId))
13+
14+
this.request(uri, {
15+
method: 'PUT',
16+
body: JSON.stringify(params.metrics),
17+
authed: false
18+
}, cb)
19+
}

test/lib/server.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ server._expect = {}
1212

1313
function handler (req, res) {
1414
req.connection.setTimeout(1000)
15-
1615
// If we got authorization, make sure it's the right password.
1716
if (req.headers.authorization && req.headers.authorization.match(/^Basic/)) {
1817
var auth = req.headers.authorization.replace(/^Basic /, '')

test/send-anon-metrics.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
var test = require('tap').test
2+
3+
var common = require('./lib/common.js')
4+
var client = common.freshClient()
5+
var server = require('./lib/server.js')
6+
7+
function nop () {}
8+
9+
var metricId = 'this-is-a-uuid'
10+
var from = new Date()
11+
var to = new Date()
12+
var metricInfo = {
13+
metricId: metricId,
14+
metrics: [{
15+
from: from.toISOString(),
16+
to: to.toISOString(),
17+
successfulInstalls: 0,
18+
failedInstalls: 1
19+
}]
20+
}
21+
22+
test('sendAnonymousCLIMetrics call contract', function (t) {
23+
t.throws(function () {
24+
client.sendAnonymousCLIMetrics(undefined, metricInfo, nop)
25+
}, 'requires a URI')
26+
27+
t.throws(function () {
28+
client.sendAnonymousCLIMetrics([], metricInfo, nop)
29+
}, 'requires URI to be a string')
30+
31+
t.throws(function () {
32+
client.sendAnonymousCLIMetrics(common.registry, undefined, nop)
33+
}, 'requires params object')
34+
35+
t.throws(function () {
36+
client.sendAnonymousCLIMetrics(common.registry, '', nop)
37+
}, 'params must be object')
38+
39+
t.throws(function () {
40+
client.sendAnonymousCLIMetrics(common.registry, metricInfo, undefined)
41+
}, 'requires callback')
42+
43+
t.throws(function () {
44+
client.sendAnonymousCLIMetrics(common.registry, metricInfo, 'callback')
45+
}, 'callback must be function')
46+
47+
t.end()
48+
})
49+
50+
test('sendAnonymousCLIMetrics', function (t) {
51+
server.expect('PUT', '/-/npm/anon-metrics/v1/' + metricId, function (req, res) {
52+
t.is(req.method, 'PUT')
53+
var b = ''
54+
req.setEncoding('utf8')
55+
req.on('data', function (d) {
56+
b += d
57+
})
58+
59+
req.on('end', function () {
60+
var d = JSON.parse(b)
61+
t.isDeeply(d, metricInfo.metrics, 'PUT received metrics')
62+
63+
res.statusCode = 200
64+
res.json({})
65+
})
66+
})
67+
68+
client.sendAnonymousCLIMetrics(common.registry, metricInfo, function (err, res) {
69+
t.ifError(err, 'no errors')
70+
t.isDeeply(res, {}, 'result ok')
71+
server.close()
72+
t.end()
73+
})
74+
})
75+
76+
test('cleanup', function (t) {
77+
server.close()
78+
t.end()
79+
})

0 commit comments

Comments
 (0)