Skip to content

Commit 63875e2

Browse files
unknownunknown
authored andcommitted
full functionality looking alright
1 parent 544f75b commit 63875e2

File tree

3 files changed

+113
-58
lines changed

3 files changed

+113
-58
lines changed

index.js

Lines changed: 95 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,66 +3,82 @@ var fs = require('fs');
33
var request = require('request');
44
var log = require('npmlog');
55

6-
var requestOpts = require('./util').requestOpts;
7-
/**
8-
* Upload a tarball packaged by node-pre-gyp as an asset to a github release
9-
*
10-
* @param {Object} opts - A options object as return by node-pre-gyp's versioning.evaluate()
11-
* @param {Object} config - A config object as built by node-pre-gyp using the rc configuration module
12-
* @param {Function} callback - No particular return, just err or no err
13-
*/
14-
exports.publish = function(opts, config, callback) {
6+
// initialize options for a HTTP request
7+
var requestOpts = function(opts, config) {
8+
var requestOpts = {
9+
headers: {
10+
'User-Agent': 'node-pre-gyp-github-hosting'
11+
}
12+
};
13+
if (config.githubToken) requestOpts.headers.Authorization = 'token ' + config.githubToken;
14+
var proxyUrl = opts.proxy || process.env.http_proxy || process.env.HTTP_PROXY || process.env.npm_config_proxy;
15+
if (proxyUrl) requestOpts.proxy = proxyUrl;
1516

16-
// first fetch the list of releases
17+
return requestOpts;
18+
};
19+
20+
var getReleaseFromVersion = function(opts, config, callback) {
1721
var listOpts = requestOpts(opts, config);
22+
listOpts.headers.Accept = 'application/vnd.github.manifold-preview';
1823
listOpts.url = 'https://api.github.com/repos/' + opts.repo + '/releases';
1924

2025
request(listOpts, function(err, response, body) {
2126
if (err) return callback(err);
27+
log.http(response.statusCode, listOpts.url);
2228
if (response.statusCode !== 200) return callback(new Error('Cannot list assets from ' + listOpts.url + ': ' + response.statusCode));
23-
2429
var releases = JSON.parse(body);
25-
var currentRelease;
30+
var release;
2631
for (var i in releases) {
27-
// remember the release that matches the required version
2832
if (releases[i].tag_name === opts.version || releases[i].tag_name === 'v' + opts.version) {
29-
currentRelease = releases[i];
30-
}
31-
// fail if an asset matching current upload already exists
32-
for (var j in releases[i].assets) {
33-
if (releases[i].assets[i].name === opts.package_name) {
34-
log.error('publish', 'Cannot publish over existing version');
35-
log.error('publish', "Update the 'version' field in package.json and try again");
36-
log.error('publish', 'If the previous version was published in error see:');
37-
log.error('publish', '\t node-pre-gyp unpublish');
38-
return callback(new Error('Failed publishing to github'));
39-
}
33+
release = releases[i];
4034
}
4135
}
36+
callback(null, release);
37+
});
38+
};
4239

43-
if (!currentRelease) return callback(new Error('Cannot publish over non-existing github release'));
40+
/**
41+
* Upload a tarball packaged by node-pre-gyp as an asset to a github release
42+
*
43+
* @param {Object} opts - A options object as return by node-pre-gyp's versioning.evaluate()
44+
* @param {Object} config - A config object as built by node-pre-gyp using the rc configuration module
45+
* @param {Function} callback - No particular return, just err or no err
46+
*/
47+
exports.publish = function(opts, config, callback) {
48+
49+
if (!config.githubToken) return callback(new Error('Authentication token required to publish an asset to github'));
50+
51+
getReleaseFromVersion(opts, config, function(err, release) {
52+
if (!release) return callback(new Error('Cannot publish over non-existing github release'));
53+
54+
for (var i in release.assets) {
55+
if (release.assets[i].name === opts.package_name) {
56+
log.error('publish', 'Cannot publish over existing version');
57+
log.error('publish', "Update the 'version' field in package.json and try again");
58+
log.error('publish', 'If the previous version was published in error see:');
59+
log.error('publish', '\t node-pre-gyp unpublish');
60+
return callback(new Error('Failed publishing to github'));
61+
}
62+
}
4463

45-
// then actually upload the asset on the release
4664
var postOpts = requestOpts(opts, config);
47-
postOpts.url = currentRelease.upload_url.replace('{?name}', '');
65+
postOpts.url = release.upload_url.replace('{?name}', '');
4866
postOpts.qs = {
4967
name: opts.package_name
5068
};
5169
postOpts.method = 'POST';
52-
delete postOpts.headers.Accept;
5370
postOpts.headers['Content-Type'] = 'application/tar';
5471
fs.readFile(opts.staged_tarball, function(err, data) {
5572
if (err) return callback(err);
5673
postOpts.body = data;
5774
request(postOpts, function(err, response) {
5875
if (err) return callback(err);
59-
if (response.statusCode !== 201) return callback(new Error('Cannot upload to github: ' + response.statusCode));
76+
log.http(response.statusCode, postOpts.url);
77+
if (response.statusCode !== 201) return callback(new Error('Cannot upload to ' + postOpts.url + ': ' + response.statusCode));
6078
console.log('[' + opts.name + '] Success: published to ' + postOpts.url);
6179
callback();
6280
});
6381
});
64-
65-
6682
});
6783
};
6884

@@ -72,9 +88,35 @@ exports.publish = function(opts, config, callback) {
7288
* @param {Object} opts - An options object as return by node-pre-gyp's versioning.evaluate()
7389
* @param {Function} callback - No particular return, just err or no err
7490
*/
75-
exports.unpublish = function(opts, callback) {
76-
// TODO
77-
callback();
91+
exports.unpublish = function(opts, config, callback) {
92+
if (!config.githubToken) return callback(new Error('Authentication token required to unpublish an asset to github'));
93+
94+
getReleaseFromVersion(opts, config, function(err, release) {
95+
if (!release) return callback(new Error('Cannot unpublish over non-existing github release'));
96+
97+
var asset;
98+
for (var i in release.assets) {
99+
if (release.assets[i].name === opts.package_name) {
100+
asset = release.assets[i];
101+
}
102+
}
103+
104+
if (!asset) {
105+
console.log('[' + opts.name + '] Not found: ' + opts.package_name);
106+
return callback();
107+
}
108+
109+
var delOpts = requestOpts(opts, config);
110+
delOpts.url = asset.url;
111+
delOpts.method = 'DELETE';
112+
request(delOpts, function(err, response) {
113+
if (err) return callback(err);
114+
log.http(response.statusCode, delOpts.url);
115+
if (response.statusCode !== 204) return callback(new Error('Cannot delete ' + delOpts.url + ': ' + response.statusCode));
116+
console.log('[' + opts.name + '] Success: unpublished ' + delOpts.url);
117+
callback();
118+
});
119+
});
78120
};
79121

80122
/**
@@ -83,7 +125,23 @@ exports.unpublish = function(opts, callback) {
83125
* @param {Object} opts - An options object as return by node-pre-gyp's versioning.evaluate()
84126
* @param {Function} callback - called with a request object (https://github.com/mikeal/request) that will be used as a stream by node-pre-gyp
85127
*/
86-
exports.download = function(opts, callback) {
87-
// TODO
88-
callback();
128+
exports.download = function(opts, config, callback) {
129+
getReleaseFromVersion(opts, config, function(err, release) {
130+
if (!release) return callback(new Error('Cannot unpublish over non-existing github release'));
131+
132+
var asset;
133+
for (var i in release.assets) {
134+
if (release.assets[i].name === opts.package_name) {
135+
asset = release.assets[i];
136+
}
137+
}
138+
139+
if (!asset) return callback(new Error('Pre-built binary not available for your system'));
140+
141+
var getOpts = requestOpts(opts, config);
142+
getOpts.url = asset.url;
143+
getOpts.headers.Accept = 'application/octet-stream';
144+
delete getOpts.headers.Authorization;
145+
callback(null, request(getOpts));
146+
});
89147
};

test/index.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
var fs = require('fs');
12
var should = require('should');
23

34
var githubHosting = require('../index.js');
@@ -18,16 +19,26 @@ var config = {
1819
};
1920

2021
describe('Github hosting for node-pre-gyp', function() {
21-
it('should define the 3 expected functions', function() {
22-
githubHosting.publish.should.be.type('function');
23-
githubHosting.unpublish.should.be.type('function');
24-
githubHosting.download.should.be.type('function');
22+
before(function(callback) {
23+
githubHosting.unpublish(opts, config, callback);
2524
});
2625

27-
it('should upload a package on a matching release', function(callback) {
28-
githubHosting.publish(opts, config, function(err){
26+
it('should publish a package', function(callback) {
27+
githubHosting.publish(opts, config, callback);
28+
});
29+
30+
it('should download a package', function(callback) {
31+
githubHosting.download(opts, config, function(err, req) {
2932
should.not.exist(err);
30-
callback();
33+
req.on('data', function(data){
34+
should.equal(data.toString('utf8'), 'package example');
35+
callback();
36+
});
37+
req.on('error', callback);
3138
});
3239
});
40+
41+
it('should unpublish a package', function(callback) {
42+
githubHosting.unpublish(opts, config, callback);
43+
});
3344
});

util.js

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)