Skip to content

Commit 503abbb

Browse files
committed
feat: support GH_TOKEN auth; support rate limit retries
1 parent 759c508 commit 503abbb

File tree

4 files changed

+86
-8
lines changed

4 files changed

+86
-8
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
List the Node.js versions supported by the package/repository
44

5+
## Setup
6+
7+
No setup is required, however if you do not have a `GH_TOKEN` environment limit, you will likely hit a request rate limit on Github API, which may result in very long wait times for retries.
8+
59
## Usage (command line)
610

711
```

lib/loader/octokit-wrapper.js

+23-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
'use strict';
22

33
const { Octokit } = require('@octokit/rest');
4+
const { throttling } = require('@octokit/plugin-throttling');
45

56
const Constants = require('../constants');
7+
const Logger = require('../logger');
8+
9+
10+
const internals = {
11+
Octokit: Octokit.plugin(throttling)
12+
};
13+
614

715
exports.create = () => {
816

9-
const octokit = new Octokit({
10-
userAgent: Constants.userAgent
11-
});
17+
const octokit = new internals.Octokit({
18+
auth: process.env.GH_TOKEN,
19+
userAgent: Constants.userAgent,
20+
throttle: {
21+
onRateLimit: (retryAfter, options) => {
22+
23+
Logger.warn(['loader'], 'Request quota exceeded for request %s %s. Will retry in %d seconds. Have you set a GH_TOKEN in env?', options.method, options.url, retryAfter);
1224

13-
// @todo: onRateLimit
14-
// @todo: auth
25+
return true;
26+
},
27+
onAbuseLimit: (retryAfter, options) => {
28+
29+
return false;
30+
}
31+
}
32+
});
1533

1634
return octokit;
1735
};

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
},
3737
"dependencies": {
3838
"@npmcli/arborist": "0.0.0-pre.21",
39+
"@octokit/plugin-throttling": "^3.2.2",
3940
"@octokit/rest": "^18.0.0",
4041
"@pkgjs/nv": "0.0.3",
4142
"debug": "^4.1.1",

test/index.js

+58-3
Original file line numberDiff line numberDiff line change
@@ -533,10 +533,9 @@ describe('detect-node-support', () => {
533533
content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64')
534534
})
535535
.get('/repos/pkgjs/detect-node-support/contents/.travis.yml')
536-
.reply(500);
536+
.reply(500, 'Simulated server error');
537537

538-
const err = await expect(NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' })).to.reject();
539-
expect(err.name).to.equal('HttpError');
538+
await expect(NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' })).to.reject('Simulated server error');
540539
});
541540

542541
it('throws when repository does not have a package.json', async () => {
@@ -585,6 +584,62 @@ describe('detect-node-support', () => {
585584
await expect(NodeSupport.detect({ repository: 'git+https://github.example.com/pkgjs/detect-node-support.git' }))
586585
.to.reject('Only github.com paths supported, feel free to PR at https://github.com/pkgjs/detect-node-support');
587586
});
587+
588+
it('retries when rate limited', async () => {
589+
590+
fixture.stubs.listRemote
591+
.returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n');
592+
593+
Nock('https://api.github.com')
594+
.get('/repos/pkgjs/detect-node-support/contents/package.json')
595+
.reply(200, {
596+
content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64')
597+
})
598+
.get('/repos/pkgjs/detect-node-support/contents/.travis.yml')
599+
.reply(403, null, {
600+
'x-ratelimit-limit': '60',
601+
'x-ratelimit-remaining': '0',
602+
'x-ratelimit-reset': `${Math.round(Date.now() / 1000) + 1}`
603+
})
604+
.get('/repos/pkgjs/detect-node-support/contents/.travis.yml')
605+
.reply(200, {
606+
content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64')
607+
});
608+
609+
const result = await NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' });
610+
611+
expect(result).to.equal({
612+
name: 'detect-node-support',
613+
version: '0.0.0-development',
614+
commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23',
615+
timestamp: 1580673602000,
616+
travis: {
617+
raw: ['10', '12', '14'],
618+
resolved: {
619+
'10': '10.20.1',
620+
'12': '12.17.0',
621+
'14': '14.3.0'
622+
}
623+
},
624+
engines: '>=10'
625+
});
626+
});
627+
628+
it('aborts on abuse limit', async () => {
629+
630+
fixture.stubs.listRemote
631+
.returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n');
632+
633+
Nock('https://api.github.com')
634+
.get('/repos/pkgjs/detect-node-support/contents/package.json')
635+
.reply(200, {
636+
content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64')
637+
})
638+
.get('/repos/pkgjs/detect-node-support/contents/.travis.yml')
639+
.reply(403, 'Abuse detected');
640+
641+
await expect(NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' })).to.reject(/Abuse detected/);
642+
});
588643
});
589644

590645
describe('packageName', () => {

0 commit comments

Comments
 (0)