Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 1 addition & 34 deletions lib/cli/publish.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,10 @@
#! /usr/bin/env node

var program = require('commander');
var cliPrompt = require('prompt');

var dasherize = require('../utils/string').dasherize;
var ui = require('../ui');

cliPrompt.message = '';
cliPrompt.delimiter = '';

var promptSchema = {
properties: {
username: {
description: 'GitHub username: ',
message: 'A username is required.',
required: true
},
password: {
description: 'GitHub password: ',
message: 'A password is required.',
required: true,
hidden: true
}
}
};

program
.arguments('<addonName>')
.usage('<addonName> -u <username> -p <password>')
Expand All @@ -48,20 +28,7 @@ function runPublishTask() {
}

if (program.addonName) {
if(program.username && program.password) {
runPublishTask();
} else {
cliPrompt.start();
cliPrompt.get(promptSchema, function(error, result) {
if (error) {
return ui.error(error);
} else {
program.username = result.username;
program.password = result.password;
runPublishTask();
}
});
}
runPublishTask();
} else {
program.outputHelp();
}
103 changes: 79 additions & 24 deletions lib/tasks/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ var GitHubAPI = require('github');

var Promise = require('../ext/promise');
var ui = require('../ui');
var gitHubCredentials = require('../utils/github-credentials');
var promptForCredentials = require('../utils/credentials-prompt');

function createGitSignature(options) {
var millisecondsFromStandardEpoch = Date.now();
var secondsFromStandardEpoch = Math.floor(millisecondsFromStandardEpoch / 1000);

return git.Signature.create('ember-micro', options.username, secondsFromStandardEpoch, 60);
function createGitSignature(repo) {
return git.Signature.default(repo);
}

function createLocalRepo(options) {
Expand Down Expand Up @@ -42,16 +41,15 @@ function addExistingFilesToLocalRepo(localRepo) {
}

function createInitialCommitOnLocalRepo(options, localRepo, oid) {
var signature = createGitSignature(options);

var signature = createGitSignature(localRepo);
return localRepo.createCommit("HEAD", signature, signature, "Initial commit", oid, []);
}

function createRemoteRepo(gitHubApi, repoName) {
function createRemoteRepo(github, repoName) {
ui.write('Creating remote repository...');

return new Promise(function(resolve, reject) {
gitHubApi.repos.create({
github.repos.create({
name: repoName
}, function(err, result) {
if (err) {
Expand All @@ -72,7 +70,12 @@ function pushToRepo(options, localRepo, remote) {

remote.setCallbacks({
credentials: function() {
return git.Cred.userpassPlaintextNew(options.username, options.password);
// the code here is misleading, but it works
// usually, we pass in a username and password to the function,
// but passing in the two parameters bellow makes the functio work with an
// oauth token as well. there is no properly named function
// available that does this.
return git.Cred.userpassPlaintextNew(options.token, 'x-oauth-basic');
}
});

Expand All @@ -84,33 +87,85 @@ function pushToRepo(options, localRepo, remote) {
return remote.push(refSpecs, pushOptions, signature, message);
}

function initializeGitHubAPI() {
return new GitHubAPI({
function initializeGitHub(options) {
var github = new GitHubAPI({
version: '3.0.0',
});

if (options.username && options.password) {
authenticateWithUserProvidedCredentials(github,options);
return createToken(github).then(function(token) {
options.token = token;
return gitHubCredentials.setToken(token);
}).then(function() {
return github;
});
} else {
return gitHubCredentials.getToken().then(function(token) {
options.token = token;
authenticateWithToken(github, token);
return github;
}).catch(function() {
return promptForCredentials().then(function(credentials) {
options.username = credentials.username;
options.password = credentials.password;
authenticateWithUserProvidedCredentials(github,credentials);
return createToken(github).then(function(token) {
options.token = token;
return gitHubCredentials.setToken(token);
}).then(function() {
return github;
});
});
});
}
}

function authenticateWithToken(github, token) {
github.authenticate({
type: 'oauth',
token: token,
});
}

function authenticateGitHubAPI(gitHubApi, options) {
gitHubApi.authenticate({
function authenticateWithUserProvidedCredentials(github, options) {
github.authenticate({
type: 'basic',
username: options.username,
password: options.password
});
}

function createToken(github) {
return new Promise(function(resolve, reject) {
github.authorization.create({
scopes: ['user', 'public_repo', 'repo', 'repo:status', 'gist'],
note: 'ember-micro-addon@' + Date.now(),
note_url: 'https://github.com/coderly/ember-micro-addon',
headers: {
'X-GitHub-OTP': 'two-factor-code'
},
}, function(err, res) {
if (err) {
reject(err);
} else {
resolve(res.token);
}
});
});
}

module.exports = function(options) {
options.workingDirectory = path.join(process.cwd(), options.addonName);

var gitHubApi = initializeGitHubAPI();

authenticateGitHubAPI(gitHubApi, options);

ui.write('Publishing ' + options.addonName + ' to GitHub...');
return createLocalRepo(options).then(function(localRepo) {
return createRemoteRepo(gitHubApi, options.addonName).then(function(remoteRepo) {
return addRemoteOrigin(localRepo, remoteRepo);
}).then(function(remoteResult) {
return pushToRepo(options, localRepo, remoteResult);
return initializeGitHub(options).then(function(github) {
ui.write('Publishing ' + options.addonName + ' to GitHub...');
return createLocalRepo(options).then(function(localRepo) {
return createRemoteRepo(github, options.addonName).then(function(remoteRepo) {
return addRemoteOrigin(localRepo, remoteRepo);
}).then(function(remoteResult) {
return pushToRepo(options, localRepo, remoteResult);
});
});
});

Expand Down
35 changes: 35 additions & 0 deletions lib/utils/credentials-prompt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
var cliPrompt = require('prompt');

cliPrompt.message = '';
cliPrompt.delimiter = '';

var promptSchema = {
properties: {
username: {
description: 'GitHub username: ',
message: 'A username is required.',
required: true
},
password: {
description: 'GitHub password: ',
message: 'A password is required.',
required: true,
hidden: true
}
}
};

var Promise = require('../ext/promise');

module.exports = function promptForCredentials() {
cliPrompt.start();
return new Promise(function(resolve, reject) {
cliPrompt.get(promptSchema, function(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
};
37 changes: 37 additions & 0 deletions lib/utils/github-credentials.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* jshint node:true*/

var storage = require('node-persist');
var path = require('path');

var TOKEN_KEY = 'ember-micro-github-token';
var CREDENTIAL_FOLDER = '.ember-micro-addon-credentials';

var Promise = require('../ext/promise');
var setItem = Promise.denodeify(storage.setItem);
var getItem = Promise.denodeify(storage.getItem);


var cachedToken;

function getUserHome() {
var userHome = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
return path.join(userHome, CREDENTIAL_FOLDER);
}

storage.initSync({ dir: getUserHome() });

module.exports = {
setToken: function(token) {
cachedToken = token;
return setItem(TOKEN_KEY, token);
},
getToken: function() {
return new Promise(function(resolve) {
if (cachedToken) {
resolve(cachedToken);
} else {
return getItem(TOKEN_KEY).then(resolve);
}
});
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"fs-extra": "^0.19.0",
"github": "^0.2.4",
"lodash": "^3.9.3",
"node-persist": "0.0.4",
"nodegit": "^0.4.1",
"prompt": "^0.2.14",
"rsvp": "^3.0.18"
Expand Down