Skip to content

Commit

Permalink
Add "binary.tag" option to specify the tag name separate from the rem…
Browse files Browse the repository at this point in the history
…ote path

Fixes bchr02#18
  • Loading branch information
thom-nic committed Jan 17, 2017
1 parent c239d3f commit fe41cef
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 48 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,18 @@ npm install -g node-pre-gyp-github
```

## Configuration
This module is intended to be used with node-pre-gyp. Therefore, be sure to configure and install node-pre-gyp first. After having done that, within **```package.json```** update the ```binary``` properties ```host``` and ```remote_path``` so it matches the following format:
This module is intended to be used with node-pre-gyp. Therefore, be sure to configure and install node-pre-gyp first. After having done that, within **```package.json```** update the `binary` section properties so they match the following format:

```
"host": "https://github.com/[owner]/[repo]/releases/download/",
"remote_path": "{version}"
"host": "https://github.com",
"remote_path": "/[owner]/[repo]/releases/download/",
"tag": "{version}"
```

Be sure to replace ```[owner]```, ```[repo]```, with actual values,
but DO NOT replace ```{version}``` with actual version.
Be sure to replace `[owner]`, `[repo]`, with actual values,
but DO NOT replace `{version}` with actual version.

***WARNING: Variable substitutions are not supported on the ```host``` property and on the ```remote_path``` only ```{version}``` placeholder is supported. The value of ```remote_path``` after substitution will become a release tag name. Do not use [forbidden git tag characters](https://git-scm.com/docs/git-check-ref-format) for ```version``` and ```remote_path``` properties.***
***WARNING: Variable substitutions are not supported on the `host` or `remote_path` property. Only `{version}` placeholder is supported for the `tag` property. The value of `tag` after substitution will become a release tag name. Do not use [forbidden git tag characters](https://git-scm.com/docs/git-check-ref-format) in your `package.version` or `package.binary.tag` properties.***

Within GitHub, create a new authorization:

Expand Down
54 changes: 35 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ NodePreGypGithub.prototype.release = {};
NodePreGypGithub.prototype.stage_dir = path.join(cwd,"build","stage");

NodePreGypGithub.prototype.init = function() {
var ownerRepo, hostPrefix;
var ownerRepo, hostPrefix, pathPrefix;

this.package_json = JSON.parse(fs.readFileSync(path.join(cwd,'package.json')));

if(!this.package_json.repository || !this.package_json.repository.url){
throw new Error('Missing repository.url in package.json');
}
Expand All @@ -47,17 +47,26 @@ NodePreGypGithub.prototype.init = function() {
}
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://github.com'
pathPrefix = '/' + 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 + '"');
}

else if('string' == typeof this.package_json.binary.tag ) {
if (this.package_json.binary.remote_path.substr(0, pathPrefix.length) !== pathPrefix){
throw new Error('binary.remote_path in package.json should begin with: "' + pathPrefix + '" when using binary.tag');
}
}
else if(! this.package_json.binary.host.match(pathPrefix)) {
throw new Error('binary.host in package.json should contain: "' + pathPrefix + '"');
}

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

};

NodePreGypGithub.prototype.authenticate_settings = function(){
Expand All @@ -80,13 +89,13 @@ NodePreGypGithub.prototype.createRelease = function(args, callback) {
'draft': true,
'prerelease': false
};

Object.keys(args).forEach(function(key) {
if(args.hasOwnProperty(key) && options.hasOwnProperty(key)) {
options[key] = args[key];
}
});

this.github.authenticate(this.authenticate_settings());
this.github.releases.createRelease(options, callback);
};
Expand All @@ -110,9 +119,9 @@ NodePreGypGithub.prototype.uploadAssets = function(){
consoleLog("Stage directory path: " + path.join(this.stage_dir));
fs.readdir(path.join(this.stage_dir), function(err, files){
if(err) throw err;

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;
Expand Down Expand Up @@ -141,18 +150,25 @@ NodePreGypGithub.prototype.publish = function(options) {
'repo': this.repo
}, function(err, data){
var release;

if(err) throw err;


// prefer `binary.tag` if present, before remote_path - see https://github.com/bchr02/node-pre-gyp-github/issues/18
if (this.package_json.binary.tag) {
options.tag_name = this.package_json.binary.tag.replace(/\{version\}/g, this.package_json.version);
// stage_dir is still based on remote_path, not tag:
this.stage_dir = path.join(this.stage_dir, (this.package_json.binary.remote_path || ''));
}
// when remote_path is set expect files to be in stage_dir / remote_path after substitution
if (this.package_json.binary.remote_path) {
// {version} substitution only takes place in `remote_path` if `package_json.binary.tag` is not present:
else if (this.package_json.binary.remote_path) {
options.tag_name = this.package_json.binary.remote_path.replace(/\{version\}/g, this.package_json.version);
this.stage_dir = path.join(this.stage_dir, options.tag_name);
} else {
// 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){
Expand All @@ -162,13 +178,13 @@ NodePreGypGithub.prototype.publish = function(options) {
}
else return [];
}.bind(this))();

this.release = release[0];

if(!release.length) {
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.");
Expand All @@ -185,4 +201,4 @@ NodePreGypGithub.prototype.publish = function(options) {
}.bind(this));
};

module.exports = NodePreGypGithub;
module.exports = NodePreGypGithub;
46 changes: 23 additions & 23 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var reset_index = function(index_string_ref) {
var reset_mocks = function() {
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}"}}';};
fs.readFileSync = function(){return '{"name":"test","version":"0.0.1","repository": {"url":"git+https://github.com/test/test.git"},"binary":{"host":"https://github.com","remote_path":"/test/test/releases/download/","tag":"{version}"}}';};
index.stage_dir = stage_dir;
index.github.authenticate = function(){};
index.github.releases.listReleases = function(options, cb){
Expand All @@ -28,9 +28,9 @@ if(!process.env.COVERALLS_SERVICE_NAME) console.log('To post to coveralls.io, be
if(!process.env.COVERALLS_REPO_TOKEN) console.log('To post to coveralls.io, be sure to set COVERALLS_REPO_TOKEN environment variable');

describe("Publishes packages to GitHub Releases", function() {

describe("Publishes without an error under all options", function() {

it("should publish a non-draft release without an error", function() {
var options = {'draft': false, 'verbose': false};
reset_mocks();
Expand All @@ -42,7 +42,7 @@ describe("Publishes packages to GitHub Releases", function() {
};
expect(function(){ index.publish(options); }).to.not.throw();
});

it("should publish a draft release without an error", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
Expand All @@ -51,46 +51,46 @@ describe("Publishes packages to GitHub Releases", function() {
};
expect(function(){ index.publish(options); }).to.not.throw();
});

});

describe("Throws an error when node-pre-gyp-github is not configured properly", function() {

it("should throw an error when missing repository.url in package.json", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
fs.readFileSync = function(){return '{}';};
expect(function(){ index.publish(options); }).to.throw("Missing repository.url in package.json");
});

it("should throw an error when a correctly formatted GitHub repository.url is not found in package.json", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
fs.readFileSync = function(){return '{"repository": {"url":"bad_format_url"}}';};
expect(function(){ index.publish(options); }).to.throw("A correctly formatted GitHub repository.url was not found within package.json");
});

it("should throw an error when missing binary.host in package.json", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
fs.readFileSync = function(){return '{"repository": {"url":"git+https://github.com/test/test.git"}}';};
expect(function(){ index.publish(options); }).to.throw("Missing binary.host in package.json");
});

it("should throw an error when binary.host does not begin with the correct url", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
fs.readFileSync = function(){return '{"repository": {"url":"git+https://github.com/test/test.git"},"binary":{"host":"bad_format_binary"}}';};
expect(function(){ index.publish(options); }).to.throw(/^binary.host in package.json should begin with:/i);
});

it("should throw an error when the NODE_PRE_GYP_GITHUB_TOKEN environment variable is not found", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
process.env.NODE_PRE_GYP_GITHUB_TOKEN = "";
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() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
Expand All @@ -99,7 +99,7 @@ describe("Publishes packages to GitHub Releases", function() {
};
expect(function(){ index.publish(options); }).to.throw('listReleases error');
});

it("should throw an error when github.releases.createRelease returns an error", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
Expand All @@ -111,7 +111,7 @@ describe("Publishes packages to GitHub Releases", function() {
};
expect(function(){ index.publish(options); }).to.throw('createRelease error');
});

it("should throw an error when the stage directory structure is missing", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
Expand All @@ -120,7 +120,7 @@ describe("Publishes packages to GitHub Releases", function() {
};
expect(function(){ index.publish(options); }).to.throw('readdir Error');
});

it("should throw an error when there are no files found within the stage directory", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
Expand All @@ -129,7 +129,7 @@ describe("Publishes packages to GitHub Releases", function() {
};
expect(function(){ index.publish(options); }).to.throw(/^No files found within the stage directory:/i);
});

it("should throw an error when a staged file already exists in the current release", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
Expand All @@ -141,23 +141,23 @@ describe("Publishes packages to GitHub Releases", function() {
};
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);
});

it("should throw an error when github.releases.uploadAsset returns an error", function() {
var options = {'draft': true, 'verbose': false};
reset_mocks();
fs.readdir = function(filename, cb) {
cb(null,["filename"]);
};
index.github.releases.uploadAsset = function(cfg,cb){
cb(new Error('uploadAsset error'));
cb(new Error('uploadAsset error'));
};
expect(function(){ index.publish(options); }).to.throw("uploadAsset error");
});

});

describe("Verify backwords compatible with any breaking changes made within the same MINOR version.", function() {

it("should publish even when package.json's binary.remote_path property is not provided and instead the version is hard coded within binary.host", function() {
var options = {'draft': false, 'verbose': false};
reset_mocks();
Expand All @@ -170,6 +170,6 @@ describe("Publishes packages to GitHub Releases", function() {
};
expect(function(){ index.publish(options); }).to.not.throw();
});

});
});
});

0 comments on commit fe41cef

Please sign in to comment.