Comparing version 0.10.1 to 0.11.0
30
cli.js
@@ -29,3 +29,3 @@ #! /usr/bin/env node | ||
var fs = require('fs'); | ||
var gutil = require('gulp-util'); | ||
var chalk = require('chalk'); | ||
@@ -47,6 +47,8 @@ // The scripts that implement the various commands/tasks we expose. | ||
configure() | ||
.catch(function(err) { | ||
gutil.log(gutil.colors.red.bold(err)); | ||
}) | ||
.then(process.exit); | ||
.then(function() { | ||
process.exit(0); | ||
}, function(err) { | ||
console.log(chalk.red.bold(err)); | ||
process.exit(1); | ||
}); | ||
}); | ||
@@ -71,3 +73,3 @@ | ||
if (err) { | ||
gutil.log('.gh-pages-cache is a temporary repository that we use to push changes to your gh-pages branch. We suggest you add it to your .gitignore.'); | ||
console.log(chalk.blue.bold('.gh-pages-cache is a temporary repository that we use to push changes to your gh-pages branch. We suggest you add it to your .gitignore.')); | ||
return; | ||
@@ -89,3 +91,4 @@ } | ||
.catch(function(err) { | ||
gutil.log(gutil.colors.red.bold(err)); | ||
console.log(chalk.red.bold(err)); | ||
process.exit(1); | ||
}); | ||
@@ -106,3 +109,4 @@ }); | ||
.catch(function(err) { | ||
gutil.log(gutil.colors.red.bold(err)); | ||
console.log(chalk.red.bold(err)); | ||
process.exit(1); | ||
}); | ||
@@ -118,4 +122,7 @@ }); | ||
}) | ||
.catch(function(err) { | ||
gutil.log(gutil.colors.red.bold(err)); | ||
.then(function() { | ||
process.exit(0); | ||
}, function(err) { | ||
console.log(chalk.red.bold(err)); | ||
process.exit(1); | ||
}); | ||
@@ -132,3 +139,4 @@ }); | ||
.catch(function(err) { | ||
gutil.log(gutil.colors.red.bold(err)); | ||
console.log(chalk.red.bold(err)); | ||
process.exit(1); | ||
}); | ||
@@ -135,0 +143,0 @@ }); |
@@ -27,3 +27,5 @@ /** | ||
var through2 = require('through2'); | ||
var gutil = require('gulp-util'); | ||
var chalk = require('chalk'); | ||
var changeCase = require('change-case'); | ||
var cli = require('cli'); | ||
@@ -46,6 +48,6 @@ function gitUrl(dir) { | ||
function templateConfigPrompt(defaultConfig) { | ||
gutil.log('The current template configuration is:'); | ||
gutil.log(templateConfigToString(defaultConfig)); | ||
console.log('Your app\'s configuration is:\n'); | ||
console.log(templateConfigToString(defaultConfig)); | ||
return promptly.confirm('Would you like to change any of the above configuration values?').then(function(fillInConfig) { | ||
return promptly.confirm('Would you like to change its configuration (y/N)?', { default: false }).then(function(fillInConfig) { | ||
if (!fillInConfig) { | ||
@@ -63,6 +65,8 @@ return defaultConfig; | ||
return prompt('Project name: ', 'name') | ||
.then(prompt.bind(null, 'Repository URL: ', 'repository')) | ||
.then(prompt.bind(null, 'Description: ', 'description')) | ||
.then(prompt.bind(null, 'License: ', 'license')) | ||
console.log('\n'); | ||
return prompt(chalk.bold('Name:'), 'name') | ||
.then(prompt.bind(null, chalk.bold('Repository:'), 'repository')) | ||
.then(prompt.bind(null, chalk.bold('Description:'), 'description')) | ||
.then(prompt.bind(null, chalk.bold('License:'), 'license')) | ||
.then(function() { | ||
@@ -87,5 +91,5 @@ return config; | ||
for (var key in config) { | ||
out.push(key + ': ' + config[key]); | ||
out.push(chalk.bold(changeCase.upperCaseFirst(key)) + ': ' + config[key]); | ||
} | ||
return out.join('\n'); | ||
return out.join('\n') + '\n'; | ||
} | ||
@@ -122,2 +126,4 @@ | ||
console.log('Bootstrapping current directory as Oghliner app…\n'); | ||
var rootDir = config.rootDir ? config.rootDir : '.'; | ||
@@ -132,2 +138,4 @@ return getDefaultTemplateConfig(rootDir) | ||
.then(function(templateConfig) { | ||
console.log('\nCreating files…'); | ||
return new Promise(function(resolve, reject) { | ||
@@ -142,7 +150,38 @@ var stream = gulp.src([__dirname + '/../templates/**']) | ||
.pipe(template(templateConfig)) | ||
.pipe(conflict(rootDir)) | ||
.pipe(conflict(rootDir, { | ||
logger: function(message, fileName, extraText) { | ||
console.log(chalk.green('✓ ') + message + ' ' + chalk.stripColor(fileName)); | ||
}, | ||
})) | ||
.pipe(gulp.dest(rootDir)) | ||
.pipe(install()) | ||
.on('end', function() { | ||
console.log('\n' + chalk.green('✓ ') + 'Creating files… done!'); | ||
cli.spinner(' Installing npm dependencies…'); | ||
}) | ||
.pipe(install({ | ||
log: function() { | ||
cli.spinner(chalk.red('× ') + 'Installing npm dependencies… error!\n', true); | ||
console.log(Array.prototype.slice.call(arguments).join('')); | ||
}, | ||
npmStdio: ['ignore', 'ignore', 'ignore'], | ||
})) | ||
.on('end', function() { | ||
cli.spinner(chalk.green('✓ ') + 'Installing npm dependencies… done!\n', true); | ||
}) | ||
.pipe(sink()); // Sink is required to trigger the finish event with install. | ||
stream.on('finish', resolve); | ||
stream.on('finish', function() { | ||
console.log( | ||
'Your app has been bootstrapped! Just commit the changes and push the commit\n' + | ||
'to the origin/master branch:\n\n' + | ||
chalk.bold('git add --all && git commit -m"initial version of Oghliner app"') + '\n' + | ||
chalk.bold('git push origin master') + '\n\n' + | ||
'Then you can build, offline, and deploy the app using ' + chalk.bold.italic('gulp') + ' commands.\n\n' + | ||
chalk.bold.blue('ℹ For more information about building, offlining and deployment, see:\n' + | ||
' https://mozilla.github.io/oghliner/') | ||
); | ||
resolve(); | ||
}); | ||
stream.on('error', reject); | ||
@@ -149,0 +188,0 @@ }); |
@@ -22,3 +22,5 @@ /** | ||
var chalk = require('chalk'); | ||
var childProcess = require('child_process'); | ||
var cli = require('cli'); | ||
var ghslug = promisify(require('github-slug')); | ||
@@ -70,2 +72,31 @@ var promptly = require('promisified-promptly'); | ||
// The active spinner message. Used by interruptSpinner to replace | ||
// the active spinner message with an interrupted version of it. | ||
var activeSpinnerMessage = null; | ||
function startSpinner(message) { | ||
cli.spinner(' ' + message); | ||
activeSpinnerMessage = message; | ||
} | ||
function stopSpinner(message, error) { | ||
var symbol = error ? chalk.bold.red('×') : chalk.bold.green('✓'); | ||
var result = error ? 'error' : 'done'; | ||
cli.spinner(symbol + ' ' + message + ' ' + result + '!', true); | ||
activeSpinnerMessage = null; | ||
} | ||
/** | ||
* Interrupt the active spinner, replacing the active spinner message with | ||
* an interrupted version of it. Used by handleCredentialErrors to interrupt | ||
* an active spinner before prompting the user to re-enter credentials. | ||
*/ | ||
function interruptSpinner() { | ||
if (!activeSpinnerMessage) { | ||
return; | ||
} | ||
cli.spinner(' ' + activeSpinnerMessage, true); | ||
activeSpinnerMessage = null; | ||
} | ||
module.exports = function() { | ||
@@ -103,4 +134,5 @@ // Save some values in the closure so we can use them across the promise chain | ||
process.stdout.write( | ||
'Your authentication code is incorrect or has expired.\n' + | ||
'Please try again.\n\n' | ||
'\n' + | ||
'Your authentication code is incorrect or has expired; please re-enter it.\n' + | ||
'\n' | ||
); | ||
@@ -122,5 +154,30 @@ } else { | ||
/** | ||
* Make a request that requires authorization to confirm that the credentials | ||
* are correct and trigger two-factor auth (if it's enabled). It doesn't | ||
* matter what request we make, only that it requires authorization, so here | ||
* we get all authorizations (and ignore the result). | ||
*/ | ||
function checkCredentials() { | ||
var message = 'Checking credentials…'; | ||
startSpinner(message); | ||
return github.authorization.getAll({}) | ||
.then(function() { | ||
stopSpinner(message); | ||
}) | ||
.catch(function(err) { | ||
stopSpinner(message, true); | ||
return handleCredentialErrors(err) | ||
.then(checkCredentials); | ||
}); | ||
} | ||
function handleCredentialErrors(err) { | ||
var error = JSON.parse(err.message); | ||
var error = err; | ||
try { | ||
error = JSON.parse(err.message); | ||
} catch (ex) {} | ||
interruptSpinner(); | ||
if (error.message === 'Bad credentials') { | ||
@@ -132,4 +189,5 @@ // We can say this because we know that the configuration flow prompts | ||
process.stdout.write( | ||
'The username and/or password you entered is incorrect.\n' + | ||
'Please try again…\n\n' | ||
'\n' + | ||
'The username and/or password you entered is incorrect; please re-enter them.\n' + | ||
'\n' | ||
); | ||
@@ -168,8 +226,13 @@ return promptCredentials(); | ||
// Perhaps they don't want to lose the existing token. | ||
process.stdout.write( | ||
'You already have the GitHub token "' + note + '".\n' + | ||
'Deleting it…\n' | ||
); | ||
return getTokenId(note, noteUrl).then(deleteToken).then(function() { | ||
return getTokenId(note, noteUrl) | ||
.then(deleteToken) | ||
.then(function() { | ||
return createToken(scopes, note, noteUrl); | ||
}) | ||
.then(function(res) { | ||
// Identify the token as having been deleted and recreated | ||
// so the caller can notify the user about that. | ||
res.isRecreated = true; | ||
return res; | ||
}); | ||
@@ -189,2 +252,6 @@ } | ||
.then(function(res) { | ||
if (res.length === 0) { | ||
throw new Error('Token not found'); | ||
} | ||
for (var i = 0; i < res.length; i++) { | ||
@@ -196,3 +263,3 @@ // XXX Should we ensure |res[i].note_url === noteUrl| too? | ||
} | ||
// XXX How do we determine that we've reached the end of the pages? | ||
return getTokenId(note, noteUrl, ++page); | ||
@@ -222,2 +289,3 @@ }) | ||
return ghslug('./') | ||
.then(function(res) { | ||
@@ -237,12 +305,15 @@ slug = res; | ||
'\n' + | ||
'Configuring ' + slug + ' to auto-deploy to GitHub Pages using Travis CI…\n' + | ||
'Configuring Travis to auto-deploy ' + slug + ' to GitHub Pages…\n' + | ||
'\n' + | ||
'To authorize Travis to push to the repository, and to check the status\n' + | ||
'of the repository in Travis, I\'ll need your GitHub username and password\n' + | ||
'(and two-factor authentication code, if appropriate) to create GitHub\n' + | ||
'personal access tokens.\n' + | ||
'\n' + | ||
'For more information about tokens, see: https://github.com/settings/tokens\n' + | ||
'To check the status of your repository in Travis and authorize Travis to push\n' + | ||
'to it, I\'ll create GitHub personal access tokens, for which I need your GitHub\n' + | ||
'username and password (and two-factor authentication code, if appropriate).\n' + | ||
'\n' | ||
); | ||
process.stdout.write(chalk.blue( | ||
'ℹ For more information about GitHub personal access tokens, see:\n' + | ||
' https://github.com/settings/tokens\n' + | ||
'\n' | ||
)); | ||
}) | ||
@@ -252,15 +323,8 @@ | ||
.then(function() { | ||
// NB: The GitHub authorization API always requires basic authentication, | ||
// so it isn't possible to request a token that gives us access to it. | ||
// Otherwise we'd do that first and then use that token to get the others. | ||
.then(checkCredentials) | ||
process.stdout.write('Creating GitHub token for Travis to push to the repository…\n'); | ||
// NB: The GitHub authorization API always requires basic authentication, | ||
// so it isn't possible to request a token that gives us access to it. | ||
// Otherwise we'd do that first and then use that token to get the others. | ||
return createToken(['public_repo'], 'Oghliner token for ' + slug, noteUrl) | ||
.then(function(res) { | ||
token = res.token; | ||
}); | ||
}) | ||
.then(function() { | ||
@@ -271,3 +335,4 @@ // Create a temporary GitHub token to get a Travis token that we can use | ||
process.stdout.write('Creating temporary GitHub token for getting Travis token…\n'); | ||
var message = 'Creating temporary GitHub token for getting Travis token…'; | ||
startSpinner(message); | ||
@@ -277,2 +342,4 @@ return createToken(['read:org', 'user:email', 'repo_deployment', 'repo:status', 'write:repo_hook'], | ||
.then(function(res) { | ||
stopSpinner(message); | ||
tempToken = res.token; | ||
@@ -287,3 +354,4 @@ | ||
.then(function() { | ||
process.stdout.write('Getting Travis token…\n'); | ||
var message = 'Getting Travis token…'; | ||
startSpinner(message); | ||
@@ -296,2 +364,4 @@ return travis.authenticate({ github_token: tempToken }) | ||
// caches it in the Travis instance. | ||
stopSpinner(message); | ||
}); | ||
@@ -303,22 +373,67 @@ }) | ||
process.stdout.write('Deleting temporary GitHub token for getting Travis token…\n'); | ||
var message = 'Deleting temporary GitHub token for getting Travis token…'; | ||
startSpinner(message); | ||
return deleteToken(tempTokenId); | ||
return deleteToken(tempTokenId) | ||
.then(function() { | ||
stopSpinner(message); | ||
}); | ||
}) | ||
.then(function() { | ||
var message = 'Creating permanent GitHub token for Travis to push to the repository…'; | ||
startSpinner(message); | ||
return createToken(['public_repo'], 'Oghliner token for ' + slug, noteUrl) | ||
.then(function(res) { | ||
token = res.token; | ||
stopSpinner(message); | ||
res.isRecreated && process.stdout.write(chalk.blue( | ||
'\n' + | ||
'ℹ You had an existing token for this app, so we deleted and recreated it.\n' + | ||
'\n' | ||
)); | ||
}); | ||
}) | ||
.then(function() { | ||
function ensureActiveInTravis() { | ||
process.stdout.write('Checking the status of your repository in Travis…\n'); | ||
var message = 'Checking the status of your repository in Travis…'; | ||
startSpinner(message); | ||
return travis.hooks.get() | ||
.then(function(res) { | ||
stopSpinner(message); | ||
return res.hooks; | ||
}) | ||
.then(function(hooks) { | ||
var hook; | ||
for (var i = 0; i < res.hooks.length; i++) { | ||
hook = res.hooks[i]; | ||
for (var i = 0; i < hooks.length; i++) { | ||
hook = hooks[i]; | ||
if (hook.owner_name === user && hook.name === repo) { | ||
if (hook.active) { | ||
process.stdout.write('Good news, your repository is already active in Travis!\n'); | ||
process.stdout.write( | ||
'\n' + | ||
'Good news, your repository is active in Travis!\n' + | ||
'\n' | ||
); | ||
return; | ||
} | ||
process.stdout.write('Your repository isn\'t active in Travis yet. Activating it…\n'); | ||
return promisify(travis.hooks(hook.id).put)({ hook: { active: true } }); | ||
var message = 'Your repository isn\'t active in Travis yet; activating it…'; | ||
startSpinner(message); | ||
return promisify(travis.hooks(hook.id).put)({ hook: { active: true } }) | ||
.then(function(res) { | ||
if (res.result) { | ||
stopSpinner(message); | ||
} else { | ||
stopSpinner(message, true); | ||
process.stdout.write(chalk.yellow( | ||
'\n' + | ||
'⚠ Travis failed to activate your repository, so you\'ll need to do so\n' + | ||
' manually in Travis by going to https://travis-ci.org/profile and pressing\n' + | ||
' the toggle button next to the name of the repository.\n' + | ||
'\n' | ||
)); | ||
} | ||
}); | ||
} | ||
@@ -338,3 +453,2 @@ } | ||
function travisAwaitSyncing() { | ||
process.stdout.write('Waiting for Travis to finish syncing…\n'); | ||
return new Promise(function(resolve, reject) { setTimeout(resolve, 5000); }) | ||
@@ -352,13 +466,43 @@ .then(travisIsSyncing) | ||
if (err.message === 'repository not found') { | ||
process.stdout.write('I didn\'t find your repository in Travis. Syncing Travis with GitHub…\n'); | ||
var message = 'I didn\'t find your repository in Travis; syncing Travis with GitHub…'; | ||
startSpinner(message); | ||
return travis.users.sync.post() | ||
.then(travisAwaitSyncing) | ||
.then(function() { | ||
stopSpinner(message); | ||
}) | ||
.then(ensureActiveInTravis) | ||
.catch(function(err) { | ||
// Ignore the exception if Travis is already syncing. The status code | ||
// of the error is 409 and its message is 'Sync already in progress. | ||
// Try again later.', but instead of relying on that we simply perform | ||
// an explicit check. | ||
// If we got 'repository not found' again, then we successfully | ||
// waited for Travis to sync and re-invoked ensureActiveInTravis. | ||
// But Travis still doesn't know anything about the repository. | ||
// So there's nothing more we can do except re-throw the error. | ||
if (err.message === 'repository not found') { | ||
throw err; | ||
} | ||
// Otherwise, the error happened in travis.users.sync.post | ||
// (or possibly travisAwaitSyncing), and there is more we can do | ||
// to recover from it. | ||
// | ||
// We ignore the exception if Travis is still syncing. In that case, | ||
// travis.users.sync.post will return an error with status code 409 | ||
// and message 'Sync already in progress. Try again later.', | ||
// but instead of relying on that we simply perform an explicit check. | ||
// | ||
return travisIsSyncing().then(function(isSyncing) { | ||
if (!isSyncing) { | ||
if (isSyncing) { | ||
return travisAwaitSyncing() | ||
.then(function() { | ||
stopSpinner(message); | ||
}) | ||
.then(ensureActiveInTravis).catch(function() { | ||
// Throw the original error. | ||
throw err; | ||
}); | ||
} else { | ||
// Check again if it's active on Travis (in case it finished syncing | ||
// right before we checked) | ||
stopSpinner(message); | ||
return ensureActiveInTravis().catch(function() { | ||
@@ -371,4 +515,2 @@ // Throw the original error. | ||
}) | ||
.then(travisAwaitSyncing) | ||
.then(ensureActiveInTravis); | ||
} | ||
@@ -379,36 +521,23 @@ throw err; | ||
.then(function(res) { | ||
// We'll only get a *res* argument if the previous step requested activation | ||
// from Travis. If the repository was already active, this step is a noop. | ||
if (res) { | ||
if (res.result) { | ||
process.stdout.write('Your repository has been activated in Travis!\n'); | ||
} else { | ||
process.stdout.write( | ||
'Travis failed to activate your repository, so you\'ll need to do so\n' + | ||
'manually in Travis by going to https://travis-ci.org/profile and pressing\n' + | ||
'the toggle button next to the name of the repository.\n\n' | ||
); | ||
} | ||
} | ||
}) | ||
.then(function() { | ||
process.stdout.write('Encrypting GitHub token…\n'); | ||
return travisEncrypt(slug, 'GH_TOKEN=' + token, undefined, undefined); | ||
var message = 'Encrypting permanent GitHub token…'; | ||
startSpinner(message); | ||
return travisEncrypt(slug, 'GH_TOKEN=' + token, undefined, undefined) | ||
.then(function(blob) { | ||
stopSpinner(message); | ||
return blob; | ||
}); | ||
}) | ||
.then(function(blob) { | ||
process.stdout.write('Writing encrypted GitHub token to .travis.yml file…\n'); | ||
var message = 'Writing configuration to .travis.yml file…'; | ||
startSpinner(message); | ||
var travisYml; | ||
var hasTravisYml = false; | ||
try { | ||
travisYml = readYaml.sync('.travis.yml'); | ||
hasTravisYml = true; | ||
} catch(err) { | ||
if (err.code === 'ENOENT') { | ||
process.stdout.write('You don\'t have a .travis.yml file. Creating one for you…\n'); | ||
process.stdout.write('Setting "language" to "node_js"…\n'); | ||
process.stdout.write('Setting "node_js" to "[ "0.12" ]"…\n'); | ||
process.stdout.write('Setting "install" to "npm install"…\n'); | ||
process.stdout.write('Setting "script" to "gulp"…\n'); | ||
travisYml = { | ||
@@ -447,3 +576,2 @@ language: 'node_js', | ||
command = 'git config --global user.name "' + name + '"'; | ||
process.stdout.write('Adding before_script command: ' + command + '…\n'); | ||
travisYml.before_script.push(command); | ||
@@ -456,3 +584,2 @@ } | ||
command = 'git config --global user.email "' + email + '"'; | ||
process.stdout.write('Adding before_script command: ' + command + '…\n'); | ||
travisYml.before_script.push(command); | ||
@@ -468,3 +595,2 @@ } | ||
if (!travisYml.after_success.some(function(v) { return v.indexOf(command) !== -1; })) { | ||
process.stdout.write('Adding after_success command: ' + command + '…\n'); | ||
travisYml.after_success.push(command); | ||
@@ -474,5 +600,16 @@ } | ||
writeYaml.sync('.travis.yml', travisYml); | ||
stopSpinner(message); | ||
if (!hasTravisYml) { | ||
process.stdout.write(chalk.yellow( | ||
'\n' + | ||
'⚠ You didn\'t already have a .travis.yml file, so I created one for you.\n' + | ||
' For more information about the file, see:\n' + | ||
' http://docs.travis-ci.com/user/customizing-the-build/\n' | ||
)); | ||
} | ||
return hasTravisYml; | ||
}) | ||
.then(function() { | ||
.then(function(hasTravisYml) { | ||
process.stdout.write( | ||
@@ -482,6 +619,24 @@ '\n' + | ||
'in .travis.yml and push the commit to the origin/master branch:\n' + | ||
'\n' | ||
); | ||
if (hasTravisYml) { | ||
process.stdout.write( | ||
chalk.bold( | ||
'git commit -m"configure Travis to auto-deploy to GitHub Pages" .travis.yml\n' + | ||
'git push origin master\n' | ||
) | ||
); | ||
} else { | ||
process.stdout.write( | ||
chalk.bold( | ||
'git add .travis.yml\n' + | ||
'git commit -m"configure Travis to auto-deploy to GitHub Pages" .travis.yml\n' + | ||
'git push origin master\n' | ||
) | ||
); | ||
} | ||
process.stdout.write( | ||
'\n' + | ||
'git commit -m"configure Travis to auto-deploy to GitHub Pages" .travis.yml\n' + | ||
'git push origin master\n' + | ||
'\n' + | ||
'Then visit https://travis-ci.org/' + slug + '/builds to see the build status.\n' + | ||
@@ -488,0 +643,0 @@ '\n' |
@@ -25,3 +25,3 @@ /** | ||
var gitconfiglocal = require('gitconfiglocal'); | ||
var gutil = require('gulp-util'); | ||
var chalk = require('chalk'); | ||
var fs = require('fs'); | ||
@@ -32,2 +32,3 @@ var fse = require('fs-extra'); | ||
var temp = require('temp').track(); | ||
var cli = require('cli'); | ||
@@ -39,3 +40,3 @@ function getCommitMessage() { | ||
if (errorText) { | ||
gutil.log(gutil.colors.red.bold('Fatal error from `git log`. You must have one commit before deploying.')); | ||
console.log(chalk.red.bold('Fatal error from `git log`. You must have one commit before deploying.')); | ||
throw new Error(errorText); | ||
@@ -47,2 +48,12 @@ } | ||
var lastMessage; | ||
function ghPagesLogger(message) { | ||
if (lastMessage) { | ||
cli.spinner(chalk.bold.green('✓ ') + lastMessage + '… done!', true); | ||
} | ||
cli.spinner(' ' + message); | ||
lastMessage = message; | ||
} | ||
module.exports = function(config) { | ||
@@ -79,3 +90,3 @@ return new Promise(function(resolve, reject) { | ||
gutil.log('Deploying "' + commitMessage + '"'); | ||
console.log('Deploying "' + commitMessage.split('\n')[0] + '" to GitHub Pages…\n'); | ||
@@ -90,3 +101,3 @@ if (cloneDir) { | ||
if (!err && stat.isDirectory()) { | ||
gutil.log(gutil.colors.yellow.bold('With the current value of the \'rootDir\' option, the entire node_modules directory is going to be deployed. Please make sure this is what you really want.')); | ||
console.log(chalk.yellow.bold('With the current value of the \'rootDir\' option, the entire node_modules directory is going to be deployed. Please make sure this is what you really want.')); | ||
} | ||
@@ -103,3 +114,3 @@ | ||
// less informative (https://github.com/mozilla/oghliner/pull/58#issuecomment-147550610). | ||
ghPagesConfig.logger = ('GH_TOKEN' in process.env) ? function() {} : gutil.log; | ||
ghPagesConfig.logger = ('GH_TOKEN' in process.env) ? function() {} : ghPagesLogger; | ||
@@ -125,2 +136,6 @@ if ('GH_TOKEN' in process.env) { | ||
ghPages.publish(rootDir, ghPagesConfig, function(err) { | ||
if (lastMessage) { | ||
cli.spinner(chalk.bold.green('✓ ') + lastMessage + '… done!\n', true); | ||
} | ||
if (err) { | ||
@@ -127,0 +142,0 @@ reject(err); |
@@ -21,9 +21,27 @@ /** | ||
var path = require('path'); | ||
var gutil = require('gulp-util'); | ||
var fse = require('fs-extra'); | ||
var cli = require('cli'); | ||
var chalk = require('chalk'); | ||
var spinnerMessage; | ||
function startSpinner(message) { | ||
spinnerMessage = message; | ||
cli.spinner(' ' + message); | ||
} | ||
function stopSpinner(error) { | ||
var symbol = error ? chalk.bold.red('× ') : chalk.bold.green('✓ '); | ||
var result = error ? 'error' : 'done'; | ||
cli.spinner(symbol + spinnerMessage + ' ' + result + '!\n', true); | ||
} | ||
module.exports = function(config) { | ||
var dir = config.dir || './'; | ||
return new Promise(function(resolve, reject) { | ||
var dir = config.dir || './'; | ||
return new Promise(function(resolve, reject) { | ||
console.log('Integrating Oghliner into the app in the current directory…\n'); | ||
startSpinner('Copying offline-manager.js to ' + dir + '…'); | ||
fs.stat(dir, function(err, stat) { | ||
@@ -46,8 +64,19 @@ if (err) { | ||
} else { | ||
gutil.log(gutil.colors.blue( | ||
'Your app needs to load the script offline-manager.js in order to register the service\n' + | ||
'worker that offlines your app. To load the script, add this line to your app\'s HTML\n' + | ||
'page(s)/template(s):\n\n' + | ||
'\t<script src="' + dest + '"></script>' | ||
)); | ||
stopSpinner(); | ||
console.log( | ||
'Oghliner has been integrated into the app!\n\n' + | ||
'The app needs to load the script offline-manager.js in order to register\n' + | ||
'the service worker that offlines the app. To load the script, add this line\n' + | ||
'to the app\'s HTML page(s)/template(s):\n\n' + | ||
chalk.bold('<script src="' + dest + '"></script>') + '\n\n' + | ||
'And commit the changes and push the commit to the origin/master branch:\n\n' + | ||
chalk.bold('git commit -m"integrate Oghliner" --all') + '\n' + | ||
chalk.bold('git push origin master') + '\n\n' + | ||
'Then you can offline and deploy the app using the ' + chalk.bold.italic('offline') + ' and ' + chalk.bold.italic('deploy') + ' commands.\n\n' + | ||
chalk.bold.blue('ℹ For more information about offlining and deployment, see:\n' + | ||
' https://mozilla.github.io/oghliner/') | ||
); | ||
resolve(); | ||
@@ -57,3 +86,6 @@ } | ||
}); | ||
}).catch(function(err) { | ||
stopSpinner(err); | ||
throw err; | ||
}); | ||
}; |
@@ -25,3 +25,3 @@ /** | ||
var swPrecache = promisify(require('sw-precache')); | ||
var gutil = require('gulp-util'); | ||
var chalk = require('chalk'); | ||
var ghslug = promisify(require('github-slug')); | ||
@@ -34,2 +34,4 @@ var glob = require('glob'); | ||
console.log('Offlining ' + chalk.bold(rootDir) + ' to ' + chalk.bold(path.join(rootDir, 'offline-worker.js')) + '…\n'); | ||
// Ensure root directory ends with slash so we strip leading slash from paths | ||
@@ -75,3 +77,3 @@ // of files to cache, so they're relative paths, and the offline worker | ||
if (stat.isFile() && stat.size > 2 * 1024 * 1024 && staticFileGlobs.indexOf(file) === -1) { | ||
gutil.log(gutil.colors.yellow.bold(file + ' is bigger than 2 MiB. Are you sure you want to cache it? To suppress this warning, explicitly include the file in the fileGlobs list.')); | ||
console.log(chalk.yellow.bold(file + ' is bigger than 2 MiB. Are you sure you want to cache it? To suppress this warning, explicitly include the file in the fileGlobs list.')); | ||
} | ||
@@ -81,2 +83,18 @@ }); | ||
var importScripts = config.importScripts || []; | ||
importScripts.forEach(function(script) { | ||
var stat; | ||
try { | ||
stat = fs.statSync(path.join(rootDir, script)); | ||
} catch (ex) { | ||
console.log(chalk.red.bold(script + ' doesn\'t exist.')); | ||
throw ex; | ||
} | ||
if (!stat.isFile()) { | ||
console.log(chalk.red.bold(script + ' is not a file.')); | ||
throw new Error(script + ' is not a file.'); | ||
} | ||
}); | ||
return swPrecache.write(path.join(rootDir, 'offline-worker.js'), { | ||
@@ -86,4 +104,10 @@ staticFileGlobs: staticFileGlobs, | ||
verbose: true, | ||
logger: gutil.log, | ||
importScripts: config.importScripts || [], | ||
logger: function(message) { | ||
if (message.indexOf('Caching') === 0) { | ||
message = chalk.bold.green('✓ ') + message.replace('static resource ', '') | ||
} | ||
console.log(message); | ||
}, | ||
importScripts: importScripts, | ||
cacheId: cacheId, | ||
@@ -90,0 +114,0 @@ ignoreUrlParametersMatching: config.ignoreUrlParametersMatching || [/./], |
{ | ||
"name": "oghliner", | ||
"version": "0.10.1", | ||
"version": "0.11.0", | ||
"description": "template and tool for deploying Offline Web Apps to GitHub Pages", | ||
@@ -34,2 +34,5 @@ "main": "index.js", | ||
"dependencies": { | ||
"chalk": "^1.1.1", | ||
"change-case": "^2.3.0", | ||
"cli": "^0.11.1", | ||
"commander": "^2.8.1", | ||
@@ -41,3 +44,3 @@ "fs-extra": "^0.26.0", | ||
"github-slug": "^1.0.0", | ||
"glob": "^5.0.15", | ||
"glob": "^5.0.15 || ^6.0.1", | ||
"gulp": "^3.9.0", | ||
@@ -47,6 +50,5 @@ "gulp-conflict": "^0.4.0", | ||
"gulp-gh-pages": "^0.5.2", | ||
"gulp-install": "^0.6.0", | ||
"gulp-install": "https://github.com/marco-c/gulp-install/tarball/56f8ebf87f14651f586d6377dea75c2f3d1b1691", | ||
"gulp-rename": "^1.2.2", | ||
"gulp-template": "^3.0.0", | ||
"gulp-util": "^3.0.6", | ||
"mozilla-tabzilla": "^0.5.1", | ||
@@ -71,3 +73,3 @@ "promisified-promptly": "^1.0.0", | ||
"mocha": "^2.3.3", | ||
"nock": "^2.15.0", | ||
"nock": "^2.17.0", | ||
"readline-sync": "^1.2.21", | ||
@@ -74,0 +76,0 @@ "rewire": "^2.3.4", |
HTTP dependency
Supply chain riskContains a dependency which resolves to a remote HTTP URL which could be used to inject untrusted code and reduce overall package reliability.
Found 1 instance in 1 package
74021
1219
28
1
+ Addedchalk@^1.1.1
+ Addedchange-case@^2.3.0
+ Addedcli@^0.11.1
+ Addedcamel-case@1.2.2(transitive)
+ Addedchange-case@2.3.1(transitive)
+ Addedcli@0.11.3(transitive)
+ Addedconstant-case@1.1.2(transitive)
+ Addeddot-case@1.1.2(transitive)
+ Addedexit@0.1.2(transitive)
+ Addedglob@6.0.4(transitive)
+ Addedis-lower-case@1.1.3(transitive)
+ Addedis-upper-case@1.1.2(transitive)
+ Addedlower-case@1.1.4(transitive)
+ Addedlower-case-first@1.0.2(transitive)
+ Addedparam-case@1.1.2(transitive)
+ Addedpascal-case@1.1.2(transitive)
+ Addedpath-case@1.1.2(transitive)
+ Addedsentence-case@1.1.3(transitive)
+ Addedsnake-case@1.1.2(transitive)
+ Addedswap-case@1.1.2(transitive)
+ Addedtitle-case@1.1.2(transitive)
+ Addedupper-case@1.1.3(transitive)
+ Addedupper-case-first@1.1.2(transitive)
- Removedgulp-util@^3.0.6
- Removedgulp-install@0.6.0(transitive)
Updatedglob@^5.0.15 || ^6.0.1