diff --git a/index.js b/index.js index 9c7879c..b1c0f94 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,7 @@ var path = require("path"); var fs = require('fs'); -var GitHubApi = require("github"); +var mime = require("mime-types"); var cwd = process.cwd(); var verbose; @@ -11,25 +11,8 @@ var consoleLog = function(x){ }; function NodePreGypGithub() {} - -NodePreGypGithub.prototype.github = new GitHubApi({ // set defaults - // required - version: "3.0.0", - // optional - debug: false, - protocol: "https", - host: "api.github.com", - pathPrefix: "", // for some GHEs; none for GitHub - timeout: 5000, - headers: {} -}); - -NodePreGypGithub.prototype.owner = ""; -NodePreGypGithub.prototype.repo = ""; -NodePreGypGithub.prototype.package_json = {}; -NodePreGypGithub.prototype.release = {}; +NodePreGypGithub.prototype.octokit = require("@octokit/rest"); NodePreGypGithub.prototype.stage_dir = path.join(cwd,"build","stage"); - NodePreGypGithub.prototype.init = function() { var ownerRepo, hostPrefix; @@ -39,25 +22,30 @@ NodePreGypGithub.prototype.init = function() { throw new Error('Missing repository.url in package.json'); } else { - ownerRepo = this.package_json.repository.url.match(/github\.com\/(.*)(?=\.git)/i); + ownerRepo = this.package_json.repository.url.match(/https?:\/\/([^\/]+)\/(.*)(?=\.git)/i); if(ownerRepo) { - ownerRepo = ownerRepo[1].split('/'); + this.host = ownerRepo[1]; + ownerRepo = ownerRepo[2].split('/'); this.owner = ownerRepo[0]; this.repo = ownerRepo[1]; } else throw new Error('A correctly formatted GitHub repository.url was not found within package.json'); } - hostPrefix = 'https://github.com/' + this.owner + '/' + this.repo + '/releases/download/'; + hostPrefix = 'https://' + this.host + '/' + this.owner + '/' + this.repo + '/releases/download/'; if(!this.package_json.binary || 'object' !== typeof this.package_json.binary || 'string' !== typeof this.package_json.binary.host){ throw new Error('Missing binary.host in package.json'); } else if (this.package_json.binary.host.substr(0, hostPrefix.length) !== hostPrefix){ throw new Error('binary.host in package.json should begin with: "' + hostPrefix + '"'); } - - this.github.headers = {"user-agent": (this.package_json.name) ? this.package_json.name : "node-pre-gyp-github"}; // GitHub is happy with a unique user agent - + + this.octokit = NodePreGypGithub.prototype.octokit({ + baseUrl: 'https://' + this.host + '/api/v3', + headers: { + "user-agent": (this.package_json.name) ? this.package_json.name : "node-pre-gyp-github" + } + }); }; NodePreGypGithub.prototype.authenticate_settings = function(){ @@ -71,6 +59,7 @@ NodePreGypGithub.prototype.authenticate_settings = function(){ NodePreGypGithub.prototype.createRelease = function(args, callback) { var options = { + 'host': this.host, 'owner': this.owner, 'repo': this.repo, 'tag_name': this.package_json.version, @@ -86,19 +75,21 @@ NodePreGypGithub.prototype.createRelease = function(args, callback) { options[key] = args[key]; } }); - - this.github.authenticate(this.authenticate_settings()); - this.github.releases.createRelease(options, callback); + this.octokit.authenticate(this.authenticate_settings()); + this.octokit.repos.createRelease(options, callback); }; NodePreGypGithub.prototype.uploadAsset = function(cfg){ - this.github.authenticate(this.authenticate_settings()); - this.github.releases.uploadAsset({ + this.octokit.authenticate(this.authenticate_settings()); + this.octokit.repos.uploadAsset({ + url: this.release.upload_url, owner: this.owner, id: this.release.id, repo: this.repo, name: cfg.fileName, - filePath: cfg.filePath + file: cfg.filePath, + contentType: mime.contentType(cfg.fileName) || 'application/octet-stream', + contentLength: fs.statSync(cfg.filePath).size, }, function(err){ if(err) throw err; consoleLog('Staged file ' + cfg.fileName + ' saved to ' + this.owner + '/' + this.repo + ' release ' + this.release.tag_name + ' successfully.'); @@ -114,19 +105,19 @@ NodePreGypGithub.prototype.uploadAssets = function(){ if(!files.length) throw new Error('No files found within the stage directory: ' + this.stage_dir); files.forEach(function(file){ - asset = this.release.assets.filter(function(element, index, array){ - return element.name === file; + if(this.release && this.release.assets) { + asset = this.release.assets.filter(function(element, index, array){ + return element.name === file; + }); + if(asset.length) { + throw new Error("Staged file " + file + " found but it already exists in release " + this.release.tag_name + ". If you would like to replace it, you must first manually delete it within GitHub."); + } + } + consoleLog("Staged file " + file + " found. Proceeding to upload it."); + this.uploadAsset({ + fileName: file, + filePath: path.join(this.stage_dir, file) }); - if(asset.length) { - throw new Error("Staged file " + file + " found but it already exists in release " + this.release.tag_name + ". If you would like to replace it, you must first manually delete it within GitHub."); - } - else { - consoleLog("Staged file " + file + " found. Proceeding to upload it."); - this.uploadAsset({ - fileName: file, - filePath: path.join(this.stage_dir, file) - }); - } }.bind(this)); }.bind(this)); }; @@ -135,13 +126,12 @@ NodePreGypGithub.prototype.publish = function(options) { options = (typeof options === 'undefined') ? {} : options; verbose = (typeof options.verbose === 'undefined' || options.verbose) ? true : false; this.init(); - this.github.authenticate(this.authenticate_settings()); - this.github.releases.listReleases({ + this.octokit.authenticate(this.authenticate_settings()); + this.octokit.repos.getReleases({ 'owner': this.owner, 'repo': this.repo }, function(err, data){ var release; - if(err) throw err; // when remote_path is set expect files to be in stage_dir / remote_path after substitution @@ -152,37 +142,27 @@ NodePreGypGithub.prototype.publish = function(options) { // This is here for backwards compatibility for before binary.remote_path support was added in version 1.2.0. options.tag_name = this.package_json.version; } - - release = (function(){ // create a new array containing only those who have a matching version. - if(data) { - data = data.filter(function(element, index, array){ - return element.tag_name === options.tag_name; - }.bind(this)); - return data; - } - else return []; - }.bind(this))(); - - this.release = release[0]; - - if(!release.length) { + release = data.data.filter(function(element, index, array){ + return element.tag_name === options.tag_name; + }); + if(release.length === 0) { this.createRelease(options, function(err, release) { if(err) throw err; - - this.release = release; - if (release.draft) { - consoleLog('Release ' + release.tag_name + " not found, so a draft release was created. YOU MUST MANUALLY PUBLISH THIS DRAFT WITHIN GITHUB FOR IT TO BE ACCESSIBLE."); + this.release = release.data; + if (this.release.draft) { + consoleLog('Release ' + this.release.tag_name + " not found, so a draft release was created. YOU MUST MANUALLY PUBLISH THIS DRAFT WITHIN GITHUB FOR IT TO BE ACCESSIBLE."); } else { consoleLog('Release ' + release.tag_name + " not found, so a new release was created and published."); } - this.uploadAssets(); + this.uploadAssets(this.release.upload_url); }.bind(this)); } else { + this.release = release[0]; this.uploadAssets(); } }.bind(this)); }; -module.exports = NodePreGypGithub; \ No newline at end of file +module.exports = NodePreGypGithub; diff --git a/package.json b/package.json index a99be2a..0644e05 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,10 @@ "releases" ], "dependencies": { - "github": "^0.2.4", - "commander": "^2.9.0" + "@octokit/rest": "^15.9.5", + "commander": "^2.9.0", + "mime-types": "^2.1.19", + "sinon": "^6.1.4" }, "devDependencies": { "chai": "^3.5.0", diff --git a/test/test.js b/test/test.js index 7071d7c..0564081 100644 --- a/test/test.js +++ b/test/test.js @@ -5,23 +5,31 @@ var fs = require("fs"); var Index = require('../index.js'); var index = new Index(); var stage_dir = index.stage_dir; +var Octokit = require("@octokit/rest"); +var octokit = Octokit(); +var sinon = require('sinon') var reset_index = function(index_string_ref) { delete require.cache[require.resolve(index_string_ref)]; return require(index_string_ref); }; + +var sandbox = sinon.createSandbox(); + var reset_mocks = function() { + sandbox.restore(); process.env.NODE_PRE_GYP_GITHUB_TOKEN = "secret"; fs = reset_index('fs'); fs.readFileSync = function(){return '{"name":"test","version":"0.0.1","repository": {"url":"git+https://github.com/test/test.git"},"binary":{"host":"https://github.com/test/test/releases/download/","remote_path":"{version}"}}';}; index.stage_dir = stage_dir; - index.github.authenticate = function(){}; - index.github.releases.listReleases = function(options, cb){ - cb(null, [{"tag_name":"0.0.0","assets":[{"name":"filename"}]}]); - }; - index.github.releases.createRelease = function(options, cb){ - cb(null,{"tag_name":"0.0.1","draft":true,"assets":[{}]}); - }; - index.github.releases.uploadAsset = function(cfg,cb){cb();}; + Index.prototype.octokit = function() {return octokit;}; + sandbox.stub(octokit, 'authenticate'); + sandbox.stub(octokit.repos, 'getReleases').callsFake(function(options, cb){ + cb(null, {data: [{"tag_name":"0.0.0","assets":[{"name":"filename"}]}]}); + }); + sandbox.stub(octokit.repos, 'createRelease').callsFake(function(options, cb){ + cb(null,{data: {"tag_name":"0.0.1","draft":true,"assets":[{}]}}); + }); + sandbox.stub(octokit.repos, 'uploadAsset').callsFake(function(cfg,cb){cb();}); }; if(!process.env.COVERALLS_SERVICE_NAME) console.log('To post to coveralls.io, be sure to set COVERALLS_SERVICE_NAME environment variable'); @@ -37,9 +45,8 @@ describe("Publishes packages to GitHub Releases", function() { fs.readdir = function(filename, cb) { cb(null,["filename"]); }; - index.github.releases.createRelease = function(options, cb){ - cb(null,{"tag_name":"0.0.1","draft":false,"assets":[{}]}); - }; + fs.statSync = function() {return 0;} + index.publish(options) expect(function(){ index.publish(options); }).to.not.throw(); }); @@ -91,22 +98,24 @@ describe("Publishes packages to GitHub Releases", function() { expect(function(){ index.publish(options); }).to.throw("NODE_PRE_GYP_GITHUB_TOKEN environment variable not found"); }); - it("should throw an error when github.releases.listReleases returns an error", function() { + it("should throw an error when octokit.repos.getReleases returns an error", function() { var options = {'draft': true, 'verbose': false}; reset_mocks(); - index.github.releases.listReleases = function(options, cb){ - cb(new Error('listReleases error')); - }; - expect(function(){ index.publish(options); }).to.throw('listReleases error'); + + octokit.repos.getReleases.restore(); + sandbox.stub(octokit.repos, 'getReleases').callsFake(function(options, cb){ + cb(new Error('getReleases error')); + }); + expect(function(){ index.publish(options); }).to.throw('getReleases error'); }); it("should throw an error when github.releases.createRelease returns an error", function() { var options = {'draft': true, 'verbose': false}; reset_mocks(); - index.github.releases.listReleases = function(options, cb){ - cb(null,null); + octokit.repos.getReleases = function(options, cb){ + cb(null,{data: []}); }; - index.github.releases.createRelease = function(options, cb){ + octokit.repos.createRelease = function(options, cb){ cb(new Error('createRelease error')); }; expect(function(){ index.publish(options); }).to.throw('createRelease error'); @@ -136,8 +145,8 @@ describe("Publishes packages to GitHub Releases", function() { fs.readdir = function(filename, cb) { cb(null,["filename"]); }; - index.github.releases.listReleases = function(options, cb){ - cb(null, [{"tag_name":"0.0.1","assets":[{"name":"filename"}]}]); + octokit.repos.getReleases = function(options, cb){ + cb(null, {data: [{"tag_name":"0.0.1","assets":[{"name":"filename"}]}]}); }; expect(function(){ index.publish(options); }).to.throw(/^Staged file .* found but it already exists in release .*. If you would like to replace it, you must first manually delete it within GitHub./i); }); @@ -148,7 +157,7 @@ describe("Publishes packages to GitHub Releases", function() { fs.readdir = function(filename, cb) { cb(null,["filename"]); }; - index.github.releases.uploadAsset = function(cfg,cb){ + octokit.repos.uploadAsset = function(cfg,cb){ cb(new Error('uploadAsset error')); }; expect(function(){ index.publish(options); }).to.throw("uploadAsset error"); @@ -165,11 +174,12 @@ describe("Publishes packages to GitHub Releases", function() { fs.readdir = function(filename, cb) { cb(null,["filename"]); }; - index.github.releases.createRelease = function(options, cb){ - cb(null,{"tag_name":"0.0.1","draft":false,"assets":[{}]}); + fs.statSync = function() {return 0;} + octokit.reposcreateRelease = function(options, cb){ + cb(null,{data: {"tag_name":"0.0.1","draft":false,"assets":[{}]}}); }; expect(function(){ index.publish(options); }).to.not.throw(); }); }); -}); \ No newline at end of file +});