Compare commits

...

88 Commits

Author SHA1 Message Date
Adam Stankiewicz
b15acd2fea Add info file 2015-03-20 21:08:11 -07:00
Adam Stankiewicz
9dab389b50 Merge pull request #1722 from kant/patch-1
Update year of copyright
2015-03-06 21:05:03 -08:00
Darío Hereñú
260b4adb8c Update year of copyright 2015-03-06 14:30:00 -03:00
Adam Stankiewicz
182d92f9bd test: Fix SvnResolver tests on all platforms 2015-02-28 23:56:17 -08:00
Adam Stankiewicz
61a68a9e38 test: Replace dejavu repo with pure (dejavu moved) 2015-02-28 19:52:40 -08:00
Sindre Sorhus
b6e33d70c8 Update README.md 2015-03-01 02:58:15 +08:00
Sindre Sorhus
7a26bf1a10 bump chalk
https://github.com/sindresorhus/chalk/releases/tag/v1.0.0
2015-02-23 15:07:56 +07:00
Sindre Sorhus
df1a87eb4e Merge pull request #1672 from therewasaguy/master
Update License Year to 2015
2015-01-21 16:37:52 +08:00
Jason Sigal
e203b1aa9a Update License Year to 2015
Happy new year!
2015-01-20 17:31:41 -05:00
Adam Stankiewicz
f458114c5b Enable OSX Travis build 2015-01-12 17:51:40 +01:00
Paul Irish
8db09d2fed Close #1655 PR: extend mocha timeout to 30s for travis.. 2015-01-12 16:02:05 +08:00
Sindre Sorhus
0ce7053598 bump dev deps 2015-01-12 10:09:33 +08:00
Sindre Sorhus
6a96815c44 bump insight 2015-01-12 10:04:25 +08:00
Sindre Sorhus
d7b0db41f4 bump update-notifier 2015-01-12 08:27:39 +08:00
Adam Stankiewicz
9c9f3e7055 Merge pull request #1654 from bower/alexanderGugel-save-exact
Add --save-exact flag
2015-01-11 17:32:53 +01:00
Alexander Gugel
2f6d680b6c Add --save-exact flag 2015-01-11 17:12:19 +01:00
Adam Stankiewicz
639f7939a3 Add info about Windows git configuration for testing 2015-01-11 03:33:23 +01:00
Adam Stankiewicz
95ce9cbf0c Remove node@0.11 from Windows builds 2015-01-11 03:28:12 +01:00
Adam Stankiewicz
1e0ef941c7 Add link to AppVeyor badge 2015-01-11 03:24:18 +01:00
Adam Stankiewicz
7e5bd64885 Fix AppVeyor badge 2015-01-11 03:15:33 +01:00
Adam Stankiewicz
de023bc6ea Update badges 2015-01-11 03:13:01 +01:00
Adam Stankiewicz
c7df6f50ca Add AppVeyor config for Windows CI 2015-01-11 03:08:43 +01:00
Adam Stankiewicz
df71d251f0 Disable SVN testing for unsuppoted hosts (e.g. AppVeyor) 2015-01-11 03:08:41 +01:00
Adam Stankiewicz
0b9acc18cc Test reading commands arguments 2015-01-10 12:56:15 +01:00
Adam Stankiewicz
58a7de3136 Prevent loading cli module in headless mode 2015-01-10 05:53:21 +01:00
Adam Stankiewicz
5bb77b1e03 [refactor] Prepare command argv readers for testing 2015-01-10 05:49:42 +01:00
Adam Stankiewicz
e351322ce4 More tests for lookup command and little refactor 2015-01-10 04:47:43 +01:00
Adam Stankiewicz
6b53ccc8bd Add tests for init command and fix it
In non-interactive mode error has been thrown in wrong way.
2015-01-09 03:18:53 +01:00
Adam Stankiewicz
33842b6f92 Remove dummy completion command 2015-01-09 02:29:18 +01:00
Adam Stankiewicz
5e747b2cfd Add tests for search and lookup commands 2015-01-09 02:22:05 +01:00
Adam Stankiewicz
3f8de0efb9 Add tests for cache clean command 2015-01-09 01:47:45 +01:00
Adam Stankiewicz
63da3e4595 Add tests for cache list command 2015-01-08 09:44:06 +01:00
Adam Stankiewicz
a04b69dc6a Test and fix link command 2015-01-08 05:09:32 +01:00
Adam Stankiewicz
3be4764d54 Add tests for prune command 2015-01-07 03:32:55 +01:00
Adam Stankiewicz
2d4fec01b1 Refactor some tests to promise style 2015-01-07 02:04:34 +01:00
Adam Stankiewicz
85c50eb542 Inject credentials to ENV for Travis 2015-01-06 20:56:27 +01:00
Adam Stankiewicz
ee62d00c96 Add tests for "version" command 2015-01-06 20:49:17 +01:00
Adam Stankiewicz
52a32f0887 Add tests for JsonRenderer 2015-01-06 17:59:45 +01:00
Adam Stankiewicz
dd30be90ad Fix StandardRenderer tests so they work on Travis 2015-01-06 16:03:58 +01:00
Adam Stankiewicz
4cb027eb73 Add tests for StandardRenderer 2015-01-06 15:56:10 +01:00
Adam Stankiewicz
8e0b8f2faf [test] Force monochrome color for test cases 2015-01-06 03:12:32 +01:00
Adam Stankiewicz
39491b78b1 Test register prompt as on dumb terminal (fixes travis) 2015-01-06 02:24:39 +01:00
Adam Stankiewicz
7c82da8389 Add tests for register command 2015-01-06 02:13:30 +01:00
Adam Stankiewicz
d5c13603a0 Merge pull request #1644 from pkollitsch/typo
Fix for #1639, missing line break in CLI input
2015-01-05 22:45:15 +01:00
Patrick Kollitsch
aad253bfad Fix for #1639, missing line break in CLI input 2015-01-05 12:52:31 +07:00
Adam Stankiewicz
dac055e2ef Add timeout in hope to catch stdout on travis 2015-01-05 06:51:09 +01:00
Adam Stankiewicz
85df5b9983 Add test for bower binary nad standard renderer 2015-01-05 06:47:01 +01:00
Adam Stankiewicz
537cd42097 Add tests for info command 2015-01-05 06:07:01 +01:00
Adam Stankiewicz
9d06fce5f9 Add few more tests for home command 2015-01-05 05:31:12 +01:00
Adam Stankiewicz
c029e1005f Add tests for "bower home" command 2015-01-05 05:19:54 +01:00
Adam Stankiewicz
b245a3d611 Remove unnecessary asserts from list test 2015-01-05 04:00:51 +01:00
Adam Stankiewicz
11d89c4268 fix: Tests helper regression 2015-01-05 03:48:59 +01:00
Adam Stankiewicz
6be84ab93e Add test case for #1584 2015-01-05 03:40:34 +01:00
Adam Stankiewicz
2f2c4d6740 Add tests for help command and fix it 2015-01-05 03:31:28 +01:00
Sindre Sorhus
06f4d0c117 package.json - use caret version specifier 2015-01-05 00:01:29 +07:00
Sindre Sorhus
b5e557ffb0 bump decompress-zip 2015-01-05 00:00:05 +07:00
Sindre Sorhus
8bd6c4a335 Merge pull request #1640 from laurelnaiad/update-deps
update package.json dependencies
2015-01-04 23:58:41 +07:00
Sindre Sorhus
29eaff9edc Merge pull request #1614 from joneshf/answer-colon
Remove erroneous colon.
2015-01-04 23:56:01 +07:00
Sindre Sorhus
08afaf7fa5 Merge pull request #1584 from vlajos/typofixes20141102
typo fixes
2015-01-04 23:54:32 +07:00
Daphne Maddox
45bab9fe71 update package.json dependencies
Update dependencies in package.json to (mostly) latest available
versions.

Updating these dependencies removes warnings when bower is installed
as a devDependency in other packages and keep the code fresh.

Methodology:

- `npm install`
- `npm test` (all tests pass)
- `npm-check-updates -u`
- `npm test` (find errors, suspect semver, back off to `~2.3.0` in
package.json)
- `rm -rf node_modules` (and .gitignored files)
- `npm install`
- `npm test` (all pass, deem updated version compatible)
- revert to package.json from `master`
- `npm install` (install the old dependencies)
- switch back to updated package.json
- `npm install` (upgrade dependencies in place)
- `npm test` (all tests still pass, deem upgrades safe)

As to the `semver` dependency, it seems that updating to 4.x requires
handling breaking changes, which is TODO.

Closes #1622
2015-01-03 11:24:21 -08:00
Sindre Sorhus
514eb8f0e3 better homedir detection 2014-12-22 22:56:27 +07:00
Ricardo Polo
a7baa58c22 Close #1620 PR: Showing --no-color in help. Fixes #78 2014-12-10 21:09:27 +07:00
Adam Stankiewicz
e548d8b1a5 Merge pull request #1618 from fracmak/bower_list_tests
Added unit tests of bower.commands.list()
2014-12-05 11:58:49 +01:00
Merrifield, Jay
92ff0fe624 Added unit tests of bower.commands.list() 2014-12-04 23:29:03 -05:00
joneshf
a464f5a88e Remove erroneous colon. 2014-11-29 12:22:58 -08:00
Veres Lajos
962a565d30 typo fixes 2014-11-02 22:40:58 +00:00
Sindre Sorhus
7db50391f2 Merge pull request #1576 from darabos/patch-1
Add extra newline at the end of help-cache.std
2014-10-27 23:07:41 +07:00
Daniel Darabos
8b0d55a729 Add extra newline at the end of help-cache.std
Without this newline, the template is rendered without a newline at the end. So when you run `grunt help cache`, the output does not have a newline at the end and the shell prompt will be printed at the end of the last line.
2014-10-27 14:00:13 +01:00
Sindre Sorhus
de6f341f41 bump to latest chalk 2014-10-16 11:52:46 +02:00
Adam Stankiewicz
c9fb530dbf Merge pull request #1557 from ISNIT0/master
Added return character
2014-10-06 14:38:33 +02:00
ISNIT0
836bcd09ec Added return character
https://github.com/bower/bower/issues/1554
2014-10-06 12:58:04 +01:00
Sindre Sorhus
52a6836872 Merge pull request #1548 from bower/fix/readable
[fix] Ensure extracted files are readable, update tar-fs
2014-09-28 23:40:29 +02:00
Adam Stankiewicz
c00cadb37a [fix] Ensure extracted files are readable, update tar-fs 2014-09-28 18:21:24 +02:00
Adam Stankiewicz
b26c072f0d Bump version to 1.3.12 and update changelog 2014-09-28 17:37:40 +02:00
Adam Stankiewicz
c99482f59d [doc] Explain why env in test/helpers.js is needed 2014-09-28 15:58:59 +02:00
Adam Stankiewicz
4aa0f567c3 Merge pull request #1529 from bower/analytics_fix
fix broken analytics tracking introduced in #1507 & changed default
2014-09-27 09:57:29 +02:00
Ray Shan
4656021902 fix broken analytics tracking introduced in #1507 2014-09-26 22:33:43 +02:00
Adam Stankiewicz
3df6144b77 Downgrade mout to 0.9.0, closes #1525 2014-09-23 20:12:19 +02:00
Adam Stankiewicz
c620004168 Update tar-fs version, fixes #1537 2014-09-23 16:26:26 +02:00
Sindre Sorhus
893ff3e9d7 Merge pull request #1535 from zhiyelee/linebreak
add linebreak
2014-09-22 11:59:24 +02:00
zhiyelee
eec9a3cb8f add linebreak 2014-09-22 11:23:31 +08:00
Sindre Sorhus
d3c8042102 Merge pull request #1532 from BiAiB/fix-zero-major-dependencies
Fix 0.x dependencies to prevent breaking API updates
2014-09-19 14:14:05 +02:00
Rodolphe Gohard
e590b44c77 Fix 0.x dependencies to prevent breaking API updates
Semver states
> Major version zero (0.y.z) is for initial development.
> Anything may change at any time. The public API should
> not be considered stable.
We already had a case where a tmp package update (0.0.24)
broke bower install. This can happen again with  0.x
dependencies that can introduce breaking API changes
anytime.
2014-09-19 12:04:41 +02:00
Adam Stankiewicz
e97bf479fb Merge pull request #1527 from LaurentGoderre/v1.3.11
Bump and update changelog
2014-09-18 02:26:50 +02:00
Laurent Goderre
fe2f71c9b8 Bump and update changelog 2014-09-17 11:12:17 -04:00
Adam Stankiewicz
ee6c483dd4 Merge pull request #1519 from LaurentGoderre/fix-1518
Fix update command not installing missing packages
2014-09-16 22:39:49 +02:00
Laurent Goderre
e83ab86f1f Added update test cases 2014-09-16 16:23:38 -04:00
Laurent Goderre
ef237fc521 Added the missing install command to the update task
Fixes #1518
2014-09-16 16:23:25 -04:00
73 changed files with 3104 additions and 490 deletions

View File

@@ -1,9 +1,25 @@
language: node_js
node_js:
- '0.10'
- '0.11'
env:
- NODE_VERSION=0.10
- NODE_VERSION=0.11
install:
- test $TRAVIS_OS_NAME = "osx" && brew install nvm && source $(brew --prefix nvm)/nvm.sh || test $TRAVIS_OS_NAME = "linux"
- nvm install $NODE_VERSION
- node --version
- npm --version
- git --version
- svn --version | head -n 1
- npm install -g grunt-cli
- npm install
os:
- osx
- linux
matrix:
allow_failures:
- node_js: '0.11'
- os: osx
- env: "NODE_VERSION=0.11"
script:
- grunt travis

View File

@@ -1,5 +1,18 @@
# Changelog
## 1.3.12 - 2014-09-28
- [stability] Fix versions for unstable dependencies ([#1532](https://github.com/bower/bower/pull/1532))
- [fix] Update tar-fs to support old tar format ([#1537](https://github.com/bower/bower/issues/1537))
- [fix] Make analytics work again ([#1529](https://github.com/bower/bower/pull/1529))
- [fix] Always disable analytics for non-interactive mode ([#1529](https://github.com/bower/bower/pull/1529))
- [fix] Bower init can create private packages again ([#1522](https://github.com/bower/bower/issues/1522))
- [fix] Show again missing newline for bower search output ([#1538](https://github.com/bower/bower/issues/1538))
## 1.3.11 - 2014-09-17
- [fix] Restore install missing dependencies on update ([1519](https://github.com/bower/bower/pull/1519))
## 1.3.10 - 2014-09-13
- [fix] Back down concurrency from 50 to 5 ([#1483](https://github.com/bower/bower/pull/1483))

View File

@@ -20,7 +20,7 @@ module.exports = function (grunt) {
simplemocha: {
options: {
reporter: 'spec',
timeout: '5000'
timeout: '10000'
},
full: {
src: ['test/test.js']
@@ -40,7 +40,7 @@ module.exports = function (grunt) {
command: 'node test/packages.js --force && node test/packages-svn.js --force'
},
cover: {
command: 'STRICT_REQUIRE=1 node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- -R dot test/test.js'
command: 'STRICT_REQUIRE=1 node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- --timeout 30000 -R dot test/test.js'
},
coveralls: {
command: 'node node_modules/.bin/coveralls < test/reports/lcov.info'

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014 Twitter and other contributors
Copyright (c) 2015 Twitter and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

3
LOCKING.md Normal file
View File

@@ -0,0 +1,3 @@
This is stub for feature mentioned in #505.
You can send PR against this branch (feature/shrinkwrap).

View File

@@ -1,6 +1,6 @@
# Bower
[![Build Status](https://travis-ci.org/bower/bower.svg?branch=master)](https://travis-ci.org/bower/bower) [![Coverage Status](https://coveralls.io/repos/bower/bower/badge.png?branch=master)](https://coveralls.io/r/bower/bower?branch=master)
[![Build Status](https://travis-ci.org/bower/bower.svg?branch=master)](https://travis-ci.org/bower/bower) [![Windows Build](https://ci.appveyor.com/api/projects/status/jr6vfra8w84plh2g/branch/master?svg=true)](https://ci.appveyor.com/project/sheerun/bower/history) [![Coverage Status](https://img.shields.io/coveralls/bower/bower.svg)](https://coveralls.io/r/bower/bower?branch=master)
<img align="right" height="300" src="http://bower.io/img/bower-logo.png">
@@ -114,6 +114,12 @@ review the [guidelines for contributing](CONTRIBUTING.md).
* [Pull requests](CONTRIBUTING.md#pull-requests)
Note that on Windows for tests to pass you need to configure Git before cloning:
```
git config --global core.autocrlf input
```
## Bower Team
Bower is made by lots of people across the globe, contributions large and small. Our thanks to everyone who has played a part.
@@ -124,7 +130,6 @@ Bower is made by lots of people across the globe, contributions large and small.
* [@wibblymat](https://github.com/wibblymat)
* [@paulirish](https://github.com/paulirish)
* [@benschwarz](https://github.com/benschwarz)
* [@sindresorhus](https://github.com/sindresorhus)
* [@svnlto](https://github.com/svnlto)
* [@sheerun](https://github.com/sheerun)
@@ -136,6 +141,6 @@ Bower is made by lots of people across the globe, contributions large and small.
## License
Copyright (c) 2014 Twitter and other contributors
Copyright (c) 2015 Twitter and other contributors
Licensed under the MIT License

40
appveyor.yml Normal file
View File

@@ -0,0 +1,40 @@
# Thanks for Grunt for template of this file!
# http://www.appveyor.com/docs/appveyor-yml
# Fix line endings in Windows. (runs before repo cloning)
init:
- git config --global core.autocrlf input
# Test against these versions of Node.js.
environment:
matrix:
- nodejs_version: "0.10"
# - nodejs_version: "0.11"
# Allow failing jobs for bleeding-edge Node.js versions.
matrix:
allow_failures:
- nodejs_version: "0.11"
# Install scripts. (runs after repo cloning)
install:
# Get the latest stable version of Node 0.STABLE.latest
- ps: Install-Product node $env:nodejs_version
# Install subversion
- choco install svn
# Install bower
- npm install
# Post-install test scripts.
test_script:
# Output useful info for debugging.
- node --version
- npm --version
- cmd: npm test
# Don't actually build.
build: off
# Set build version format here instead of in the admin panel.
version: "{build}"

View File

@@ -6,7 +6,7 @@ process.bin = process.title = 'bower';
var Q = require('q');
var mout = require('mout');
var Logger = require('bower-logger');
var osenv = require('osenv');
var userHome = require('user-home');
var bower = require('../lib');
var pkg = require('../package.json');
var cli = require('../lib/util/cli');
@@ -125,18 +125,15 @@ analytics.setup(bower.config).then(function () {
});
// Warn if HOME is not SET
if (!osenv.home()) {
logger.warn('no-home', 'HOME not set, user configuration will not be loaded');
if (!userHome) {
logger.warn('no-home', 'HOME environment variable not set. User config will not be loaded.');
}
if (bower.config.interactive) {
var updateNotifier = require('update-notifier');
// Check for newer version of Bower
var notifier = updateNotifier({
packageName: pkg.name,
packageVersion: pkg.version
});
var notifier = updateNotifier({pkg: pkg});
if (notifier.update && levels.info >= loglevel) {
notifier.notify();

View File

@@ -6,7 +6,6 @@ var rimraf = require('rimraf');
var endpointParser = require('bower-endpoint-parser');
var PackageRepository = require('../../core/PackageRepository');
var semver = require('../../util/semver');
var cli = require('../../util/cli');
var defaultConfig = require('../../config');
function clean(logger, endpoints, options, config) {
@@ -33,8 +32,7 @@ function clean(logger, endpoints, options, config) {
return Q.all([
clearPackages(decEndpoints, config, logger),
clearLinks(names, config, logger),
!names ? clearCompletion(config, logger) : null
clearLinks(names, config, logger)
])
.spread(function (entries) {
return entries;
@@ -172,34 +170,16 @@ function clearLinks(names, config, logger) {
});
}
function clearCompletion(config, logger) {
var dir = config.storage.completion;
return Q.nfcall(fs.stat, dir)
.then(function () {
return Q.nfcall(rimraf, dir)
.then(function () {
logger.info('deleted', 'Completion cache', {
file: dir
});
});
}, function (error) {
if (error.code !== 'ENOENT') {
throw error;
}
});
}
// -------------------
clean.line = function (logger, argv) {
clean.readOptions = function (argv) {
var cli = require('../../util/cli');
var options = cli.readOptions(argv);
var endpoints = options.argv.remain.slice(2);
return clean(logger, endpoints, options);
};
clean.completion = function () {
// TODO:
delete options.argv;
return [endpoints, options];
};
module.exports = clean;

View File

@@ -1,6 +1,5 @@
var mout = require('mout');
var PackageRepository = require('../../core/PackageRepository');
var cli = require('../../util/cli');
var defaultConfig = require('../../config');
function list(logger, packages, options, config) {
@@ -31,14 +30,14 @@ function list(logger, packages, options, config) {
// -------------------
list.line = function (logger, argv) {
list.readOptions = function (argv) {
var cli = require('../../util/cli');
var options = cli.readOptions(argv);
var packages = options.argv.remain.slice(2);
return list(logger, packages, options);
};
list.completion = function () {
// TODO:
delete options.argv;
return [packages, options];
};
module.exports = list;

View File

@@ -1,21 +0,0 @@
var Q = require('q');
var cli = require('../util/cli');
function completion(config) {
return new Q();
}
// -------------------
completion.line = function (logger, argv) {
var options = cli.readOptions(argv);
var name = options.argv.remain[1];
return completion(logger, name);
};
completion.completion = function () {
// TODO:
};
module.exports = completion;

View File

@@ -1,10 +1,9 @@
var Q = require('q');
var path = require('path');
var fs = require('graceful-fs');
var cli = require('../util/cli');
var createError = require('../util/createError');
function help(logger, name) {
function help(logger, name, config) {
var json;
if (name) {
@@ -18,7 +17,7 @@ function help(logger, name) {
})
.then(function (exists) {
if (!exists) {
throw createError('Unknown command: ' + name, 'EUNKOWNCMD', {
throw createError('Unknown command: ' + name, 'EUNKNOWNCMD', {
command: name
});
}
@@ -29,14 +28,12 @@ function help(logger, name) {
// -------------------
help.line = function (logger, argv) {
help.readOptions = function (argv) {
var cli = require('../util/cli');
var options = cli.readOptions(argv);
var name = options.argv.remain.slice(1).join(' ');
return help(logger, name);
};
help.completion = function () {
// TODO
return [name];
};
module.exports = help;

View File

@@ -1,7 +1,6 @@
var Project = require('../core/Project');
var open = require('opn');
var endpointParser = require('bower-endpoint-parser');
var cli = require('../util/cli');
var createError = require('../util/createError');
var defaultConfig = require('../config');
@@ -48,15 +47,12 @@ function home(logger, name, config) {
// -------------------
home.line = function (logger, argv) {
home.readOptions = function (argv) {
var cli = require('../util/cli');
var options = cli.readOptions(argv);
var name = options.argv.remain[1];
return home(logger, name);
};
home.completion = function () {
// TODO:
return [name];
};
module.exports = home;

View File

@@ -24,7 +24,12 @@ function commandFactory(id) {
function runFromArgv(argv) {
return withLogger(function (logger) {
return require(id).line.call(undefined, logger, argv);
var command = require(id);
var commandArgs = command.readOptions(argv);
commandArgs.unshift(logger);
return command.apply(undefined, commandArgs);
});
}
@@ -44,6 +49,7 @@ function commandFactory(id) {
}
command.line = runFromArgv;
return command;
}
@@ -53,7 +59,6 @@ module.exports = {
clean: commandFactory('./cache/clean'),
list: commandFactory('./cache/list'),
},
completion: commandFactory('./completion'),
help: commandFactory('./help'),
home: commandFactory('./home'),
info: commandFactory('./info'),

View File

@@ -2,11 +2,14 @@ var mout = require('mout');
var Q = require('q');
var endpointParser = require('bower-endpoint-parser');
var PackageRepository = require('../core/PackageRepository');
var cli = require('../util/cli');
var Tracker = require('../util/analytics').Tracker;
var defaultConfig = require('../config');
function info(logger, endpoint, property, config) {
if (!endpoint) {
return;
}
var repository;
var decEndpoint;
var tracker;
@@ -53,20 +56,13 @@ function getPkgMeta(repository, decEndpoint, property) {
// -------------------
info.line = function (logger, argv) {
info.readOptions = function (argv) {
var cli = require('../util/cli');
var options = cli.readOptions(argv);
var pkg = options.argv.remain[1];
var property = options.argv.remain[2];
if (!pkg) {
return new Q();
}
return info(logger, pkg, property);
};
info.completion = function () {
// TODO:
return [pkg, property];
};
module.exports = info;

View File

@@ -7,7 +7,6 @@ var Project = require('../core/Project');
var defaultConfig = require('../config');
var GitHubResolver = require('../core/resolvers/GitHubResolver');
var GitFsResolver = require('../core/resolvers/GitFsResolver');
var cli = require('../util/cli');
var cmd = require('../util/cmd');
var createError = require('../util/createError');
@@ -18,12 +17,9 @@ function init(logger, config) {
// This command requires interactive to be enabled
if (!config.interactive) {
process.nextTick(function () {
logger.emit('error', createError('Register requires an interactive shell', 'ENOINT', {
details: 'Note that you can manually force an interactive shell with --config.interactive'
}));
throw createError('Register requires an interactive shell', 'ENOINT', {
details: 'Note that you can manually force an interactive shell with --config.interactive'
});
return logger;
}
project = new Project(config, logger);
@@ -320,13 +316,8 @@ function setDependencies(project, json, answers) {
// -------------------
init.line = function (logger, argv) {
var options = cli.readOptions(argv);
return init(logger, options);
};
init.completion = function () {
// TODO:
init.readOptions = function (argv) {
return [];
};
module.exports = init;

View File

@@ -1,6 +1,5 @@
var endpointParser = require('bower-endpoint-parser');
var Project = require('../core/Project');
var cli = require('../util/cli');
var Tracker = require('../util/analytics').Tracker;
var defaultConfig = require('../config');
@@ -29,22 +28,22 @@ function install(logger, endpoints, options, config) {
// -------------------
install.line = function (logger, argv) {
var options = install.options(argv);
return install(logger, options.argv.remain.slice(1), options);
};
install.readOptions = function (argv) {
var cli = require('../util/cli');
install.options = function (argv) {
return cli.readOptions({
var options = cli.readOptions({
'force-latest': { type: Boolean, shorthand: 'F'},
'production': { type: Boolean, shorthand: 'p' },
'save': { type: Boolean, shorthand: 'S' },
'save-dev': { type: Boolean, shorthand: 'D' }
'save-dev': { type: Boolean, shorthand: 'D' },
'save-exact': { type: Boolean, shorthand: 'E' }
}, argv);
};
install.completion = function () {
// TODO:
var packages = options.argv.remain.slice(1);
delete options.argv;
return [packages, options];
};
module.exports = install;

View File

@@ -3,14 +3,13 @@ var rimraf = require('rimraf');
var Q = require('q');
var Project = require('../core/Project');
var createLink = require('../util/createLink');
var cli = require('../util/cli');
var defaultConfig = require('../config');
function link(logger, name, localName) {
function link(logger, name, localName, config) {
if (name) {
return linkTo(logger, name, localName);
return linkTo(logger, name, localName, config);
} else {
return linkSelf(logger);
return linkSelf(logger, config);
}
}
@@ -50,7 +49,7 @@ function linkTo(logger, name, localName, config) {
localName = localName || name;
src = path.join(config.storage.links, name);
dst = path.join(process.cwd(), config.directory, localName);
dst = path.join(config.cwd, config.directory, localName);
// Delete destination folder if any
return Q.nfcall(rimraf, dst)
@@ -73,15 +72,13 @@ function linkTo(logger, name, localName, config) {
// -------------------
link.line = function (logger, argv) {
link.readOptions = function (argv) {
var cli = require('../util/cli');
var options = cli.readOptions(argv);
var name = options.argv.remain[1];
var localName = options.argv.remain[2];
return link(logger, name, localName);
};
link.completion = function () {
// TODO:
return [name, localName];
};
module.exports = link;

View File

@@ -3,7 +3,6 @@ var mout = require('mout');
var Q = require('q');
var Project = require('../core/Project');
var semver = require('../util/semver');
var cli = require('../util/cli');
var defaultConfig = require('../config');
function list(logger, options, config) {
@@ -151,20 +150,17 @@ function normalize(src) {
// -------------------
list.line = function (logger, argv) {
var options = list.options(argv);
return list(logger, options);
};
list.readOptions = function (argv) {
var cli = require('../util/cli');
list.options = function (argv) {
return cli.readOptions({
var options = cli.readOptions({
'paths': { type: Boolean, shorthand: 'p' },
'relative': { type: Boolean, shorthand: 'r' }
}, argv);
};
list.completion = function () {
// TODO:
delete options.argv;
return [options];
};
module.exports = list;

View File

@@ -1,9 +1,12 @@
var Q = require('q');
var RegistryClient = require('bower-registry-client');
var cli = require('../util/cli');
var defaultConfig = require('../config');
function lookup(logger, name, config) {
if (!name) {
return new Q(null);
}
var registryClient;
config = defaultConfig(config);
@@ -24,19 +27,12 @@ function lookup(logger, name, config) {
// -------------------
lookup.line = function (logger, argv) {
var options = cli.readOptions(argv);
lookup.readOptions = function (argv) {
var cli = require('../util/cli');
var options = cli.readOptions(argv);
var name = options.argv.remain[1];
if (!name) {
return new Q();
} else {
return lookup(logger, name);
}
};
lookup.completion = function () {
// TODO:
return [name];
};
module.exports = lookup;

View File

@@ -1,6 +1,5 @@
var mout = require('mout');
var Project = require('../core/Project');
var cli = require('../util/cli');
var defaultConfig = require('../config');
function prune(logger, options, config) {
@@ -41,19 +40,16 @@ function clean(project, options, removed) {
// -------------------
prune.line = function (logger, argv) {
var options = prune.options(argv);
return prune(logger, options);
};
prune.readOptions = function (argv) {
var cli = require('../util/cli');
prune.options = function (argv) {
return cli.readOptions({
var options = cli.readOptions({
'production': { type: Boolean, shorthand: 'p' },
}, argv);
};
prune.completion = function () {
// TODO:
delete options.argv;
return [options];
};
module.exports = prune;

View File

@@ -4,7 +4,6 @@ var chalk = require('chalk');
var PackageRepository = require('../core/PackageRepository');
var Config = require('bower-config');
var Tracker = require('../util/analytics').Tracker;
var cli = require('../util/cli');
var createError = require('../util/createError');
var defaultConfig = require('../config');
var GitHubResolver = require('../core/resolvers/GitHubResolver');
@@ -19,18 +18,17 @@ function register(logger, name, url, config) {
force = config.force;
tracker = new Tracker(config);
name = (name || '').trim();
url = (url || '').trim();
// Bypass any cache
config.offline = false;
config.force = true;
// Trim name
name = name.trim();
return Q.try(function () {
// Verify name
// TODO: Verify with the new spec regexp?
if (!name) {
throw createError('Please type a name', 'EINVNAME');
// Verify name and url
if (!name || !url) {
throw createError('Usage: bower register <name> <url>', 'EINVFORMAT');
}
// The public registry only allows git:// endpoints
@@ -104,20 +102,14 @@ function convertUrl(url, logger) {
// -------------------
register.line = function (logger, argv) {
register.readOptions = function (argv) {
var cli = require('../util/cli');
var options = cli.readOptions(argv);
var name = options.argv.remain[1];
var url = options.argv.remain[2];
if (!name || !url) {
return new Q();
} else {
return register(logger, name, url);
}
};
register.completion = function () {
// TODO:
return [name, url];
};
module.exports = register;

View File

@@ -1,6 +1,5 @@
var Q = require('q');
var RegistryClient = require('bower-registry-client');
var cli = require('../util/cli');
var Tracker = require('../util/analytics').Tracker;
var defaultConfig = require('../config');
@@ -26,14 +25,12 @@ function search(logger, name, config) {
// -------------------
search.line = function (logger, argv) {
search.readOptions = function (argv) {
var cli = require('../util/cli');
var options = cli.readOptions(argv);
var name = options.argv.remain.slice(1).join(' ');
return search(logger, name, options);
};
search.completion = function () {
// TODO:
return [name];
};
module.exports = search;

View File

@@ -1,11 +1,14 @@
var mout = require('mout');
var Q = require('q');
var Project = require('../core/Project');
var cli = require('../util/cli');
var Tracker = require('../util/analytics').Tracker;
var defaultConfig = require('../config');
function uninstall(logger, names, options, config) {
if (!names.length) {
return new Q();
}
var project;
var tracker;
@@ -99,26 +102,19 @@ function clean(project, names, removed) {
// -------------------
uninstall.line = function (logger, argv) {
var options = uninstall.options(argv);
var names = options.argv.remain.slice(1);
uninstall.readOptions = function (argv) {
var cli = require('../util/cli');
if (!names.length) {
return new Q();
} else {
return uninstall(logger, names, options);
}
};
uninstall.options = function (argv) {
return cli.readOptions({
var options = cli.readOptions({
'save': { type: Boolean, shorthand: 'S' },
'save-dev': { type: Boolean, shorthand: 'D' }
}, argv);
};
uninstall.completion = function () {
// TODO:
var names = options.argv.remain.slice(1);
delete options.argv;
return [names, options];
};
module.exports = uninstall;

View File

@@ -1,5 +1,4 @@
var Project = require('../core/Project');
var cli = require('../util/cli');
var defaultConfig = require('../config');
function update(logger, names, options, config) {
@@ -19,21 +18,19 @@ function update(logger, names, options, config) {
// -------------------
update.line = function (logger, argv) {
var options = update.options(argv);
var names = options.argv.remain.slice(1);
return update(logger, names, options);
};
update.readOptions = function (argv) {
var cli = require('../util/cli');
update.options = function (argv) {
return cli.readOptions({
var options = cli.readOptions({
'force-latest': { type: Boolean, shorthand: 'F' },
'production': { type: Boolean, shorthand: 'p' }
}, argv);
};
update.completion = function () {
// TODO:
var names = options.argv.remain.slice(1);
delete options.argv;
return [names, options];
};
module.exports = update;

View File

@@ -5,13 +5,13 @@ var path = require('path');
var Q = require('q');
var execFile = require('child_process').execFile;
var Project = require('../core/Project');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var createError = require('../util/createError');
function version(logger, versionArg, options, config) {
var project;
options = options || {};
config = defaultConfig(config);
project = new Project(config, logger);
@@ -19,10 +19,11 @@ function version(logger, versionArg, options, config) {
}
function bump(project, versionArg, message) {
var cwd = project._config.cwd || process.cwd();
var newVersion;
var doGitCommit = false;
return checkGit()
return checkGit(cwd)
.then(function (hasGit) {
doGitCommit = hasGit;
})
@@ -34,7 +35,7 @@ function bump(project, versionArg, message) {
.then(project.saveJson.bind(project))
.then(function () {
if (doGitCommit) {
return gitCommitAndTag(newVersion, message);
return gitCommitAndTag(cwd, newVersion, message);
}
})
.then(function () {
@@ -56,12 +57,12 @@ function getNewVersion(currentVersion, versionArg) {
return newVersion;
}
function checkGit() {
var gitDir = path.join(process.cwd(), '.git');
function checkGit(cwd) {
var gitDir = path.join(cwd, '.git');
return Q.nfcall(fs.stat, gitDir)
.then(function (stat) {
if (stat.isDirectory()) {
return checkGitStatus();
return checkGitStatus(cwd);
}
return false;
}, function () {
@@ -70,14 +71,14 @@ function checkGit() {
});
}
function checkGitStatus() {
function checkGitStatus(cwd) {
return Q.nfcall(which, 'git')
.fail(function (err) {
err.code = 'ENOGIT';
throw err;
})
.then(function () {
return Q.nfcall(execFile, 'git', ['status', '--porcelain'], {env: process.env});
return Q.nfcall(execFile, 'git', ['status', '--porcelain'], {env: process.env, cwd: cwd});
})
.then(function (value) {
var stdout = value[0];
@@ -98,34 +99,29 @@ function filterModifiedStatusLines(stdout) {
});
}
function gitCommitAndTag(newVersion, message) {
function gitCommitAndTag(cwd, newVersion, message) {
var tag = 'v' + newVersion;
message = message || tag;
message = message.replace(/%s/g, newVersion);
return Q.nfcall(execFile, 'git', ['add', 'bower.json'], {env: process.env})
return Q.nfcall(execFile, 'git', ['add', 'bower.json'], {env: process.env, cwd: cwd})
.then(function () {
return Q.nfcall(execFile, 'git', ['commit', '-m', message], {env: process.env});
return Q.nfcall(execFile, 'git', ['commit', '-m', message], {env: process.env, cwd: cwd});
})
.then(function () {
return Q.nfcall(execFile, 'git', ['tag', tag, '-am', message], {env: process.env});
return Q.nfcall(execFile, 'git', ['tag', tag, '-am', message], {env: process.env, cwd: cwd});
});
}
// -------------------
version.line = function (logger, argv) {
var options = version.options(argv);
return version(logger, options.argv.remain[1], options);
};
version.readOptions = function (argv) {
var cli = require('../util/cli');
version.options = function (argv) {
return cli.readOptions({
var options = cli.readOptions({
'message': { type: String, shorthand: 'm'}
}, argv);
};
version.completion = function () {
// TODO:
return [options.argv.remain[1], options];
};
module.exports = version;

View File

@@ -1,7 +1,6 @@
var tty = require('tty');
var object = require('mout').object;
var bowerConfig = require('bower-config');
var cli = require('./util/cli');
var cachedConfigs = {};
@@ -34,15 +33,19 @@ function readCachedConfig(cwd) {
}
// Merge common CLI options into the config
object.mixIn(config, cli.readOptions({
force: { type: Boolean, shorthand: 'f' },
offline: { type: Boolean, shorthand: 'o' },
verbose: { type: Boolean, shorthand: 'V' },
quiet: { type: Boolean, shorthand: 'q' },
loglevel: { type: String, shorthand: 'l' },
json: { type: Boolean, shorthand: 'j' },
silent: { type: Boolean, shorthand: 's' }
}));
if (process.bin === 'bower') {
var cli = require('./util/cli');
object.mixIn(config, cli.readOptions({
force: { type: Boolean, shorthand: 'f' },
offline: { type: Boolean, shorthand: 'o' },
verbose: { type: Boolean, shorthand: 'V' },
quiet: { type: Boolean, shorthand: 'q' },
loglevel: { type: String, shorthand: 'l' },
json: { type: Boolean, shorthand: 'j' },
silent: { type: Boolean, shorthand: 's' }
}));
}
return config;
}

View File

@@ -775,7 +775,7 @@ Manager.prototype._electSuitable = function (name, semvers, nonSemvers) {
choices = picks.map(function (pick, index) { return index + 1; });
return Q.nfcall(this._logger.prompt.bind(this._logger), {
type: 'input',
message: 'Answer:',
message: 'Answer',
validate: function (choice) {
choice = Number(mout.string.trim(choice.trim(), '!'));
@@ -827,7 +827,7 @@ Manager.prototype._storeResolution = function (pick) {
*
* It is used in two situations:
* * checks if resolved component matches dependency constraint
* * checks if not resolved component matches alredy fetched component
* * checks if not resolved component matches already fetched component
*
* If candidate matches already resolved component, it won't be downloaded.
*

View File

@@ -93,6 +93,10 @@ Project.prototype.install = function (decEndpoints, options, config) {
jsonEndpoint = endpointParser.decomposed2json(decEndpoint);
if (that._options.saveExact) {
jsonEndpoint[decEndpoint.name] = decEndpoint.pkgMeta.version;
}
if (that._options.save) {
that._json.dependencies = mout.object.mixIn(that._json.dependencies || {}, jsonEndpoint);
}
@@ -192,6 +196,9 @@ Project.prototype.update = function (names, options) {
.then(function () {
return that._manager.preinstall(that._json);
})
.then(function () {
return that._manager.install(that._json);
})
.then(function (installed) {
// Save JSON, might contain changes to resolutions
return that.saveJson()

View File

@@ -3,6 +3,7 @@ var Q = require('q');
var which = require('which');
var LRU = require('lru-cache');
var mout = require('mout');
var path = require('path');
var Resolver = require('./Resolver');
var semver = require('../../util/semver');
var createError = require('../../util/createError');
@@ -86,13 +87,13 @@ SvnResolver.prototype._export = function () {
});
if (resolution.type === 'commit') {
promise = cmd('svn', ['export', '--force', this._source + '/trunk', '-r' + resolution.commit, this._tempDir]);
promise = cmd('svn', ['export', '--force', this._source + path.normalize('/trunk'), '-r' + resolution.commit, this._tempDir]);
} else if (resolution.type === 'branch' && resolution.branch === 'trunk') {
promise = cmd('svn', ['export', '--force', this._source + '/trunk', this._tempDir]);
promise = cmd('svn', ['export', '--force', this._source + path.normalize('/trunk'), this._tempDir]);
} else if (resolution.type === 'branch') {
promise = cmd('svn', ['export', '--force', this._source + '/branches/' + resolution.branch, this._tempDir]);
promise = cmd('svn', ['export', '--force', this._source + path.normalize('/branches/' + resolution.branch), this._tempDir]);
} else {
promise = cmd('svn', ['export', '--force', this._source + '/tags/' + resolution.tag, this._tempDir]);
promise = cmd('svn', ['export', '--force', this._source + path.normalize('/tags/' + resolution.tag), this._tempDir]);
}
// Throttle the progress reporter to 1 time each sec
@@ -324,7 +325,7 @@ SvnResolver.tags = function (source) {
return Q.resolve(value);
}
value = cmd('svn', ['list', source + '/tags', '--verbose'])
value = cmd('svn', ['list', source + path.normalize('/tags'), '--verbose'])
.spread(function (stout) {
var tags = SvnResolver.parseSubversionListOutput(stout.toString());

View File

@@ -23,7 +23,7 @@ function StandardRenderer(command, config) {
};
this._command = command;
this._config = config;
this._config = config || {};
if (this.constructor._wideCommands.indexOf(command) === -1) {
this._compact = true;
@@ -79,7 +79,7 @@ StandardRenderer.prototype.error = function (err) {
/*jshint camelcase:true*/
this._write(process.stderr, str);
console.trace();
this._write(process.stderr, new Error().stack);
// Print bower version, node version and system info.
this._write(process.stderr, chalk.yellow('\nSystem info:\n'));

View File

@@ -5,66 +5,91 @@ var analytics = module.exports;
var insight;
var enableAnalytics = false;
// Insight takes long to load, and often causes problems
// in non-interactive environment, so we load it lazily
//
// Insight is used in two cases:
//
// 1. Read insight configuration (whether track user actions)
// 2. Track user actions (Tracker.track method)
//
// We don't want to instantiate Insight in non-interactive mode
// because it takes time to read config and configstore has concurrency issues:
//
// https://github.com/yeoman/configstore/issues/20
function ensureInsight () {
if (!insight) {
var Insight = require('insight');
var pkg = require('../../package.json');
insight = new Insight({
trackingCode: 'UA-43531210-1',
packageName: pkg.name,
packageVersion: pkg.version
pkg: require('../../package.json')
});
}
}
// Initializes the application-wide insight singleton and asks for the
// permission on the CLI during the first run.
//
// This method is called only from bin/bower. Programmatic API skips it.
analytics.setup = function setup (config) {
var deferred = Q.defer();
// if `analytics` hasn't been explicitly set
if (config.analytics == null) {
// No need for asking if analytics is set in bower config
if (config.analytics === undefined) {
ensureInsight();
// if there is a stored value
if (insight.optOut !== undefined) {
// set analytics to the stored value
config.analytics = !insight.optOut;
deferred.resolve();
} else {
if (config.interactive) {
// For non-interactive call from bin/bower we disable analytics
if (config.interactive) {
if (insight.optOut !== undefined) {
deferred.resolve(!insight.optOut);
} else {
insight.askPermission(null, function(err, optIn) {
// optIn callback param was exactly opposite before 0.4.3
// so we force at least insight@0.4.3 in package.json
config.analytics = optIn;
deferred.resolve();
deferred.resolve(optIn);
});
} else {
// no specified value, no stored value, and can't prompt for one
// so set analytics to true
config.analytics = true;
deferred.resolve();
}
} else {
// no specified value, no stored value, and can't prompt for one
// most likely CI environment; defaults to false to reduce data noise
deferred.resolve(false);
}
} else {
// use the specified value
deferred.resolve();
deferred.resolve(config.analytics);
}
return deferred.promise;
return deferred.promise.then(function (enabled) {
enableAnalytics = enabled;
return enabled;
});
};
var Tracker = analytics.Tracker = function Tracker(config) {
if (!config.analytics) {
this.track = function noop() {};
function analyticsEnabled () {
// Allow for overriding analytics default
if (config && config.analytics !== undefined) {
return config.analytics;
}
// TODO: let bower pass this variable from bin/bower instead closure
return enableAnalytics;
}
if (analyticsEnabled()) {
ensureInsight();
} else {
this.track = function noop () {};
this.trackDecomposedEndpoints = function noop () {};
this.trackPackages = function noop () {};
this.trackNames = function noop () {};
}
};
Tracker.prototype.track = function track() {
ensureInsight();
insight.track.apply(insight, arguments);
};

View File

@@ -99,7 +99,7 @@ function executeCmd(command, args, options) {
fullCommand += args.length ? ' ' + args.join(' ') : '';
// Build the error instance
error = createError('Failed to execute "' + fullCommand + '", exit code of #' + code, 'ECMDERR', {
error = createError('Failed to execute "' + fullCommand + '", exit code of #' + code + '\n' + stderr, 'ECMDERR', {
details: stderr,
exitCode: code
});

View File

@@ -52,7 +52,9 @@ function extractTar(archive, dst) {
fs.createReadStream(archive)
.on('error', deferred.reject)
.pipe(tar.extract(dst, {
ignore: isSymlink // Filter symlink files
ignore: isSymlink, // Filter symlink files
dmode: 0555, // Ensure dirs are readable
fmode: 0444 // Ensure files are readable
}))
.on('error', deferred.reject)
.on('finish', deferred.resolve.bind(deferred, dst));
@@ -68,7 +70,9 @@ function extractTarGz(archive, dst) {
.pipe(zlib.createGunzip())
.on('error', deferred.reject)
.pipe(tar.extract(dst, {
ignore: isSymlink // Filter symlink files
ignore: isSymlink, // Filter symlink files
dmode: 0555, // Ensure dirs are readable
fmode: 0444 // Ensure files are readable
}))
.on('error', deferred.reject)
.on('finish', deferred.resolve.bind(deferred, dst));

View File

@@ -2,7 +2,6 @@
'use strict';
var isRoot = require('is-root');
var createError = require('./createError');
var cli = require('./cli');
var renderer;
@@ -23,6 +22,7 @@ https://gist.github.com/isaacs/579814\n\n\
You can however run a command with sudo using --allow-root option';
if (isRoot()) {
var cli = require('./cli');
renderer = cli.getRenderer('', false, config);
renderer.error(createError('Cannot be run with sudo', 'ESUDO', { details : errorMsg }));
process.exit(1);

View File

@@ -1,6 +1,6 @@
{
"name": "bower",
"version": "1.3.10",
"version": "1.3.12",
"description": "The browser package manager",
"author": "Twitter",
"licenses": [
@@ -16,63 +16,65 @@
"node": ">=0.10.0"
},
"dependencies": {
"abbrev": "~1.0.4",
"archy": "0.0.2",
"bower-config": "~0.5.2",
"bower-endpoint-parser": "~0.2.2",
"bower-json": "~0.4.0",
"bower-logger": "~0.2.2",
"bower-registry-client": "~0.2.0",
"cardinal": "~0.4.0",
"chalk": "~0.5.0",
"chmodr": "~0.1.0",
"decompress-zip": "0.0.8",
"fstream": "~1.0.2",
"fstream-ignore": "~1.0.1",
"glob": "~4.0.2",
"graceful-fs": "~3.0.1",
"handlebars": "~2.0.0",
"inquirer": "~0.7.1",
"insight": "~0.4.3",
"is-root": "~1.0.0",
"junk": "~1.0.0",
"lockfile": "~1.0.0",
"lru-cache": "~2.5.0",
"mkdirp": "~0.5.0",
"mout": "~0.10.0",
"nopt": "~3.0.0",
"opn": "~1.0.0",
"osenv": "~0.1.0",
"p-throttler": "0.1.0",
"promptly": "~0.2.0",
"q": "~1.0.1",
"request": "~2.42.0",
"request-progress": "~0.3.0",
"retry": "~0.6.0",
"rimraf": "~2.2.0",
"semver": "~2.3.0",
"shell-quote": "~1.4.1",
"stringify-object": "~1.0.0",
"tar-fs": "~0.5.0",
"tmp": "0.0.23",
"update-notifier": "~0.2.0",
"which": "~1.0.5"
"abbrev": "^1.0.5",
"archy": "1.0.0",
"bower-config": "^0.5.2",
"bower-endpoint-parser": "^0.2.2",
"bower-json": "^0.4.0",
"bower-logger": "^0.2.2",
"bower-registry-client": "^0.2.1",
"cardinal": "0.4.4",
"chalk": "^1.0.0",
"chmodr": "0.1.0",
"decompress-zip": "^0.1.0",
"fstream": "^1.0.3",
"fstream-ignore": "^1.0.2",
"glob": "^4.3.2",
"graceful-fs": "^3.0.5",
"handlebars": "^2.0.0",
"inquirer": "0.8.0",
"insight": "^0.5.0",
"is-root": "^1.0.0",
"junk": "^1.0.0",
"lockfile": "^1.0.0",
"lru-cache": "^2.5.0",
"mkdirp": "0.5.0",
"mout": "^0.11.0",
"nopt": "^3.0.1",
"opn": "^1.0.1",
"p-throttler": "0.1.1",
"promptly": "0.2.0",
"q": "^1.1.2",
"request": "^2.51.0",
"request-progress": "0.3.1",
"retry": "0.6.1",
"rimraf": "^2.2.8",
"semver": "^2.3.0",
"shell-quote": "^1.4.2",
"stringify-object": "^1.0.0",
"tar-fs": "^1.4.1",
"tmp": "0.0.24",
"update-notifier": "^0.3.0",
"user-home": "^1.1.0",
"which": "^1.0.8"
},
"devDependencies": {
"coveralls": "~2.11.0",
"expect.js": "~0.3.1",
"grunt": "~0.4.4",
"chai": "^1.10.0",
"coveralls": "^2.11.2",
"expect.js": "^0.3.1",
"grunt": "^0.4.5",
"grunt-cli": "^0.1.13",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-exec": "~0.4.2",
"grunt-simple-mocha": "~0.4.0",
"istanbul": "~0.3.2",
"load-grunt-tasks": "~0.6.0",
"mocha": "~1.21.4",
"nock": "~0.46.0",
"node-uuid": "~1.4.1",
"proxyquire": "~1.0.1"
"grunt-contrib-jshint": "^0.10.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-exec": "^0.4.6",
"grunt-simple-mocha": "^0.4.0",
"istanbul": "^0.3.5",
"load-grunt-tasks": "^2.0.0",
"mocha": "^2.1.0",
"multiline": "^1.0.2",
"nock": "^0.56.0",
"node-uuid": "^1.4.2",
"proxyquire": "^1.3.0"
},
"scripts": {
"test": "grunt test"

View File

@@ -1,5 +1,5 @@
{
"command": "cache list",
"command": "cache clean",
"description": "Cleans cached packages.",
"usage": [
"cache clean [<options>]",

View File

@@ -1,5 +1,5 @@
{
"command": "cache clean",
"command": "cache list",
"description": "Lists cached packages.",
"usage": [
"cache list [<options>]",

View File

@@ -30,6 +30,11 @@
"shorthand": "-D",
"flag": "--save-dev",
"description": "Save installed packages into the project's bower.json devDependencies"
},
{
"shorthand": "-E",
"flag": "--save-exact",
"description": "Configure installed packages with an exact version rather than semver"
}
]
}

View File

@@ -62,6 +62,10 @@
{
"flag": "--version",
"description": "Output Bower version"
},
{
"flag": "--no-color",
"description": "Disable colors"
}
]
}

View File

@@ -1,9 +1,11 @@
{{#yellow}}Unable to find a suitable version for {{name}}, please choose one:{{/yellow}}
{{#condense}}
{{#each picks}}
{{#magenta}}{{sum @index 1}}){{/magenta}} {{#cyan}}{{endpoint.name}}#{{endpoint.target}}{{/cyan}}{{#if pkgMeta._release}} which resolved to {{#green}}{{pkgMeta._release}}{{/green}}{{/if}}{{#if dependants}} and is required by {{#green}}{{dependants}}{{/green}} {{/if}}
{{#magenta}}{{sum @index 1}}){{/magenta}} {{#cyan}}{{endpoint.name}}#{{endpoint.target}}{{/cyan}}{{#if pkgMeta._release}} which resolved to {{#green}}{{pkgMeta._release}}{{/green}}{{/if}}{{#if dependants}} and is required by {{#green}}{{dependants}}{{/green}}{{/if}}
{{/each}}
{{/condense}}
{{#unless saveResolutions}}
Prefix the choice with ! to persist it to bower.json
{{/unless}}

View File

@@ -14,3 +14,4 @@ Commands:
{{#rpad length="23"}}{{@key}}{{/rpad}} {{.}}
{{/each}}
{{/condense}}

View File

@@ -5,3 +5,4 @@
Package not found.
{{/if}}
{{/condense}}

View File

@@ -5,5 +5,6 @@
{{#cyan}}{{{name}}}{{/cyan}} {{{url}}}
{{/.}}
{{/condense}}
{{else}}No results.
{{/if}}
{{/if}}

31
test/commands/bower.js Normal file
View File

@@ -0,0 +1,31 @@
var expect = require('expect.js');
var helpers = require('../helpers');
describe('bower', function () {
var oldStdout;
var text;
before(function() {
oldStdout = process.stdout.write;
text = '';
process.stdout.write = function(args) {
text += args;
};
});
it('runs bower installation', function (done) {
helpers.require('bin/bower');
setTimeout(function() {
done();
}, 250);
});
after(function() {
process.stdout.write = oldStdout;
expect(text).to.contain('Usage:');
expect(text).to.contain('Commands:');
});
});

89
test/commands/cache/clean.js vendored Normal file
View File

@@ -0,0 +1,89 @@
var expect = require('expect.js');
var helpers = require('../../helpers');
var cacheClean = helpers.command('cache/clean');
var md5 = helpers.require('lib/util/md5');
var object = require('mout/object');
describe('bower cache clean', function () {
// Because directory names are required to be mp5 of _source
var cacheFilesFactory = function (spec) {
var files = {};
object.map(spec, function(bowerJson) {
bowerJson._source = bowerJson.name + '/' + bowerJson.version;
var path = md5(bowerJson._source) + '/' + bowerJson.version + '/.bower.json';
files[path] = bowerJson;
});
return files;
};
var cacheFiles = cacheFilesFactory([
{
name: 'angular',
version: '1.3.8'
},
{
name: 'angular',
version: '1.3.9'
},
{
name: 'jquery',
version: '1.0.0'
}
]);
var cacheDir = new helpers.TempDir(cacheFiles);
it('correctly reads arguments', function() {
expect(cacheClean.readOptions(['jquery', 'angular']))
.to.eql([['jquery', 'angular'], {}]);
});
it('removes all cache', function () {
cacheDir.prepare();
return helpers.run(cacheClean, [undefined, {}, {
storage: {
packages: cacheDir.path
}
}]).spread(function(result) {
object.map(cacheFiles, function (_, cacheFile) {
expect(cacheDir.exists(cacheFile)).to.be(false);
});
});
});
it('removes single package', function () {
cacheDir.prepare();
return helpers.run(cacheClean, [['angular'], {}, {
storage: {
packages: cacheDir.path
}
}]).spread(function(result) {
var paths = Object.keys(cacheFiles);
expect(cacheDir.exists(paths[0])).to.be(false);
expect(cacheDir.exists(paths[1])).to.be(false);
expect(cacheDir.exists(paths[2])).to.be(true);
});
});
it('removes single package package version', function () {
cacheDir.prepare();
return helpers.run(cacheClean, [['angular#1.3.8'], {}, {
storage: {
packages: cacheDir.path
}
}]).spread(function(result) {
var paths = Object.keys(cacheFiles);
expect(cacheDir.exists(paths[0])).to.be(false);
expect(cacheDir.exists(paths[1])).to.be(true);
expect(cacheDir.exists(paths[2])).to.be(true);
});
});
});

60
test/commands/cache/list.js vendored Normal file
View File

@@ -0,0 +1,60 @@
var expect = require('expect.js');
var helpers = require('../../helpers');
var cacheList = helpers.command('cache/list');
describe('bower cache list', function () {
var cacheDir = new helpers.TempDir({
'87323d6d4e48be291a9616a033d4cc6c/1.3.8/.bower.json': {
name: 'angular',
version: '1.3.8'
},
'87323d6d4e48be291a9616a033d4cc6c/1.3.9/.bower.json': {
name: 'angular',
version: '1.3.9'
},
'9eaed103d6a7e78d91f673cfad796850/1.0.0/.bower.json': {
name: 'jquery',
version: '1.0.0'
}
});
it('correctly reads arguments', function() {
expect(cacheList.readOptions(['jquery', 'angular']))
.to.eql([['jquery', 'angular'], {}]);
});
it('lists packages from cache', function () {
cacheDir.prepare();
return helpers.run(cacheList, [undefined, {}, {
storage: {
packages: cacheDir.path
}
}]).spread(function(result) {
expect(result[0].canonicalDir)
.to.be(cacheDir.getPath('87323d6d4e48be291a9616a033d4cc6c/1.3.8'));
expect(result[0].pkgMeta.version).to.be('1.3.8');
expect(result[1].pkgMeta.version).to.be('1.3.9');
expect(result[2].pkgMeta.version).to.be('1.0.0');
});
});
it('lists selected package names', function () {
cacheDir.prepare();
return helpers.run(cacheList, [['angular'], {}, {
storage: {
packages: cacheDir.path
}
}]).spread(function(result) {
expect(result[0].canonicalDir)
.to.be(cacheDir.getPath('87323d6d4e48be291a9616a033d4cc6c/1.3.8'));
expect(result[0].pkgMeta.version).to.be('1.3.8');
expect(result[1].pkgMeta.version).to.be('1.3.9');
});
});
});

43
test/commands/help.js Normal file
View File

@@ -0,0 +1,43 @@
var expect = require('expect.js');
var helpers = require('../helpers');
var help = helpers.command('help');
describe('bower help', function () {
it('correctly reads arguments', function() {
expect(help.readOptions(['foo'])).to.eql(['foo']);
});
it('shows general help', function () {
return helpers.run(help).spread(function(result) {
expect(result.usage[0]).to.be.a('string');
expect(result.commands).to.be.a('object');
expect(result.options).to.be.a('object');
});
});
var commands = [
'home', 'info', 'init', 'install',
'link', 'list', 'lookup', 'prune', 'register',
'search', 'update', 'uninstall', 'version',
'cache list', 'cache clean'
];
commands.forEach(function(command) {
it('shows help for ' + command + ' command', function() {
return helpers.run(help, [command]).spread(function(result) {
expect(result.command).to.be(command);
expect(result.description).to.be.a('string');
expect(result.usage[0]).to.be.a('string');
});
});
});
it('displays error for non-existing command', function() {
return helpers.run(help, ['fuu']).fail(function(e) {
expect(e.message).to.be('Unknown command: fuu');
expect(e.command).to.be('fuu');
expect(e.code).to.be('EUNKNOWNCMD');
});
});
});

59
test/commands/home.js Normal file
View File

@@ -0,0 +1,59 @@
var Q = require('q');
var expect = require('expect.js');
var helpers = require('../helpers');
var home = helpers.command('home');
describe('bower home', function () {
it('correctly reads arguments', function() {
expect(home.readOptions(['foo'])).to.eql(['foo']);
});
var package = new helpers.TempDir({
'bower.json': {
name: 'package',
homepage: 'http://bower.io'
}
});
var wrongPackage = new helpers.TempDir({
'bower.json': {
name: 'package'
}
});
it('opens repository home page in web browser', function () {
package.prepare();
return Q.Promise(function(resolve) {
var home = helpers.command('home', { opn: resolve });
helpers.run(home, [package.path]);
}).then(function(url) {
expect(url).to.be('http://bower.io');
});
});
it('opens home page of current repository', function () {
package.prepare();
return Q.Promise(function(resolve) {
var home = helpers.command('home', { opn: resolve });
helpers.run(home, [undefined, { cwd: package.path }]);
}).then(function(url) {
expect(url).to.be('http://bower.io');
});
});
it('errors if no homepage is set', function () {
wrongPackage.prepare();
return Q.Promise(function(resolve) {
var home = helpers.command('home', { opn: resolve });
helpers.run(home, [wrongPackage.path]).fail(resolve);
}).then(function(reason) {
expect(reason.message).to.be('No homepage set for package');
expect(reason.code).to.be('ENOHOME');
});
});
});

View File

@@ -1,5 +1,21 @@
describe('integration tests', function () {
require('./cache/list');
require('./cache/clean');
require('./help');
require('./home');
require('./info');
require('./init');
require('./install');
require('./list');
require('./link');
require('./lookup');
require('./prune');
require('./register');
require('./search');
require('./uninstall');
require('./update');
require('./version');
// run last because it changes defaults
require('./bower');
});

52
test/commands/info.js Normal file
View File

@@ -0,0 +1,52 @@
var expect = require('expect.js');
var helpers = require('../helpers');
var info = helpers.command('info');
describe('bower info', function () {
it('correctly reads arguments', function() {
expect(info.readOptions(['pkg', 'property']))
.to.eql(['pkg', 'property']);
});
var meta = {
name: 'package',
version: '0.1.2',
homepage: 'http://bower.io',
description: 'Hello world!'
};
var meta2 = {
name: 'package',
version: '0.1.3',
homepage: 'http://bower.io',
description: 'Hello world! Hello!'
};
var package = new helpers.TempDir({
'0.1.2': { 'bower.json': meta },
'0.1.3': { 'bower.json': meta2 }
});
it('just returns if not package is specified', function () {
return helpers.run(info).spread(function(results) {
expect(results).to.be(undefined);
});
});
it('shows info about given package', function () {
return package.prepareGit({}).then(function() {
return helpers.run(info, [package.path]).spread(function(results) {
expect(results).to.eql({
'latest': meta2,
'name': package.path,
'versions': [
'0.1.3',
'0.1.2'
]
});
});
});
});
});

View File

@@ -1,24 +1,24 @@
var path = require('path');
var expect = require('expect.js');
var fs = require('fs');
var helpers = require('../helpers');
var bower = helpers.require('lib/index');
var init = helpers.command('init');
describe('bower init', function () {
var tempDir = new helpers.TempDir();
var bowerJsonPath = path.join(tempDir.path, 'bower.json');
var package = new helpers.TempDir();
var config = {
cwd: tempDir.path,
interactive: true
};
it('correctly reads arguments', function() {
expect(init.readOptions([]))
.to.eql([]);
});
it('generates bower.json file', function () {
tempDir.prepare();
package.prepare();
var logger = bower.commands.init(config);
var logger = init({
cwd: package.path,
interactive: true
});
return helpers.expectEvent(logger, 'prompt')
.spread(function (prompt, answer) {
@@ -37,14 +37,49 @@ describe('bower init', function () {
return helpers.expectEvent(logger, 'prompt');
})
.spread(function (prompt, answer) {
answer({
prompt: true
});
answer({ prompt: true });
return helpers.expectEvent(logger, 'end');
})
.then(function () {
expect(fs.existsSync(bowerJsonPath)).to.be(true);
expect(package.readJson('bower.json')).to.eql({
name: 'test-name',
version: 'test-version',
homepage: 'test-homepage',
authors: [ 'test-author' ],
description: 'test-description',
moduleType: 'test-moduleType',
keywords: [ 'test-keyword' ],
license: 'test-license'
});
});
});
it('errors on non-interactive mode', function () {
package.prepare();
return helpers.run(init, { cwd: package.path }).then(
function () { throw 'should fail'; },
function (reason) {
expect(reason.message).to.be('Register requires an interactive shell');
expect(reason.code).to.be('ENOINT');
}
);
});
it('warns about existing bower.json', function () {
package.prepare({
'bower.json': {
name: 'foobar'
}
});
var logger = init({ cwd: package.path, interactive: true });
return helpers.expectEvent(logger, 'log').spread(function(event) {
expect(event.level).to.be('warn');
expect(event.message).to.be(
'The existing bower.json file will be used and filled in'
);
});
});
});

View File

@@ -1,13 +1,36 @@
var expect = require('expect.js');
var object = require('mout').object;
var helpers = require('../helpers');
var commands = helpers.require('lib/index').commands;
describe('bower install', function () {
var tempDir = new helpers.TempDir();
var install = helpers.command('install', { cwd: tempDir.path });
it('correctly reads arguments', function() {
expect(install.readOptions(['jquery', 'angular', '-F', '-p', '-S', '-D', '-E']))
.to.eql([['jquery', 'angular'], {
forceLatest: true,
production: true,
save: true,
saveDev: true,
saveExact: true
}]);
});
it('correctly reads long arguments', function() {
expect(install.readOptions([
'jquery', 'angular',
'--force-latest', '--production', '--save', '--save-dev', '--save-exact'
])).to.eql([['jquery', 'angular'], {
forceLatest: true,
production: true,
save: true,
saveDev: true,
saveExact: true
}]);
});
var package = new helpers.TempDir({
'bower.json': {
name: 'package'
@@ -16,20 +39,6 @@ describe('bower install', function () {
var gitPackage = new helpers.TempDir();
var installLogger = function(packages, options, config) {
config = object.merge(config || {}, {
cwd: tempDir.path
});
return commands.install(packages, options, config);
};
var install = function(packages, options, config) {
var logger = installLogger(packages, options, config);
return helpers.expectEvent(logger, 'end');
};
it('writes to bower.json if --save flag is used', function () {
package.prepare();
@@ -39,11 +48,73 @@ describe('bower install', function () {
}
});
return install([package.path], { save: true }).then(function() {
return helpers.run(install, [[package.path], { save: true }]).then(function() {
expect(tempDir.read('bower.json')).to.contain('dependencies');
});
});
it('writes an exact version number to dependencies in bower.json if --save --save-exact flags are used', function () {
package.prepare({
'bower.json': {
version: '1.2.3'
}
});
tempDir.prepare({
'bower.json': {
name: 'test'
}
});
return helpers.run(install, [
[package.path],
{ saveExact: true, save: true }
]).then(function() {
expect(tempDir.readJson('bower.json').dependencies.package).to.equal('1.2.3');
});
});
it('writes an exact version number to devDependencies in bower.json if --save-dev --save-exact flags are used', function () {
package.prepare({
'bower.json': {
version: '0.1.0'
}
});
tempDir.prepare({
'bower.json': {
name: 'test'
}
});
return helpers.run(install, [
[package.path],
{ saveExact: true, saveDev: true }
]).then(function() {
expect(tempDir.readJson('bower.json').devDependencies.package).to.equal('0.1.0');
});
});
it('does not write to bower.json if only --save-exact flag is used', function() {
package.prepare({
'bower.json': {
version: '1.2.3'
}
});
tempDir.prepare({
'bower.json': {
name: 'test'
}
});
return helpers.run(install, [[package.path], { saveExact: true }]).then(function() {
expect(tempDir.read('bower.json')).to.not.contain('dependencies');
expect(tempDir.read('bower.json')).to.not.contain('devDependencies');
});
});
it('reads .bowerrc from cwd', function () {
package.prepare({ foo: 'bar' });
@@ -57,7 +128,7 @@ describe('bower install', function () {
}
});
return install().then(function() {
return helpers.run(install).then(function() {
expect(tempDir.read('assets/package/foo')).to.be('bar');
});
});
@@ -74,12 +145,12 @@ describe('bower install', function () {
},
'.bowerrc': {
scripts: {
preinstall: 'bash -c "echo -n % > preinstall.txt"'
preinstall: 'node -e \'require("fs").writeFileSync("preinstall.txt", "%")\''
}
}
});
return install().then(function() {
return helpers.run(install).then(function() {
expect(tempDir.read('preinstall.txt')).to.be('package');
});
});
@@ -96,12 +167,12 @@ describe('bower install', function () {
},
'.bowerrc': {
scripts: {
postinstall: 'bash -c "echo -n % > postinstall.txt"'
postinstall: 'node -e \'require("fs").writeFileSync("postinstall.txt", "%")\''
}
}
});
return install().then(function() {
return helpers.run(install).then(function() {
expect(tempDir.read('postinstall.txt')).to.be('package');
});
});
@@ -114,13 +185,13 @@ describe('bower install', function () {
},
'.bowerrc': {
scripts: {
postinstall: 'bash -c "echo -n % > hooks.txt"',
preinstall: 'bash -c "echo -n % > hooks.txt"'
postinstall: 'node -e \'require("fs").writeFileSync("hooks.txt", "%")\'',
preinstall: 'node -e \'require("fs").writeFileSync("hooks.txt", "%")\''
}
}
});
return install().then(function() {
return helpers.run(install).then(function() {
expect(tempDir.exists('hooks.txt')).to.be(false);
});
});
@@ -134,12 +205,12 @@ describe('bower install', function () {
},
'.bowerrc': {
scripts: {
postinstall: 'bash -c "cat bower.json > hook.txt"',
postinstall: 'node -e \'var fs = require("fs"); fs.writeFileSync("hook.txt", fs.readFileSync("bower.json"));\''
}
}
});
return install([package.path], { save: true }).then(function() {
return helpers.run(install, [[package.path], { save: true }]).then(function() {
expect(tempDir.read('hook.txt')).to.contain('dependencies');
});
});
@@ -156,14 +227,14 @@ describe('bower install', function () {
},
'.bowerrc': {
scripts: {
postinstall: 'bash -c "echo foobar"'
postinstall: 'node -e \'process.stdout.write("foobar")\''
}
}
});
var lastAction = null;
installLogger().intercept(function (log) {
helpers.run(install).logger.intercept(function (log) {
if (log.level === 'action') {
lastAction = log;
}
@@ -197,7 +268,7 @@ describe('bower install', function () {
}
});
return install().then(function() {
return helpers.run(install).then(function() {
expect(tempDir.read('bower_components/package/version.txt')).to.contain('1.0.0');
});
});

110
test/commands/link.js Normal file
View File

@@ -0,0 +1,110 @@
var expect = require('expect.js');
var helpers = require('../helpers');
var link = helpers.command('link');
describe('bower link', function () {
var package = new helpers.TempDir({
'bower.json': {
name: 'package',
},
'index.js': 'Hello World!'
});
var otherPackage = new helpers.TempDir({
'bower.json': {
name: 'package2',
},
'index.js': 'Welcome World!'
});
var linksDir = new helpers.TempDir();
beforeEach(function() {
package.prepare();
otherPackage.prepare();
linksDir.prepare();
});
it('correctly reads arguments', function() {
expect(link.readOptions(['jquery', 'angular']))
.to.eql(['jquery', 'angular']);
});
it('creates self link', function () {
return helpers.run(link, [undefined, undefined,
{
cwd: package.path,
storage: {
links: linksDir.path
}
}
]).then(function() {
expect(linksDir.read('package/index.js'))
.to.be('Hello World!');
});
});
it('creates inter-link', function () {
return helpers.run(link, [undefined, undefined,
{
cwd: package.path,
storage: {
links: linksDir.path
}
}
]).then(function () {
return helpers.run(link, ['package', undefined,
{
cwd: otherPackage.path,
storage: {
links: linksDir.path
}
}
]);
}).then(function() {
expect(otherPackage.read('bower_components/package/index.js'))
.to.be('Hello World!');
});
});
it('creates inter-link with custom local name', function () {
return helpers.run(link, [undefined, undefined,
{
cwd: package.path,
storage: {
links: linksDir.path
}
}
]).then(function () {
return helpers.run(link, ['package', 'local',
{
cwd: otherPackage.path,
storage: {
links: linksDir.path
}
}
]);
}).then(function() {
expect(otherPackage.read('bower_components/local/index.js'))
.to.be('Hello World!');
});
});
it('errors on unexising package', function () {
return helpers.run(link, ['package', 'local',
{
cwd: otherPackage.path,
storage: {
links: linksDir.path
}
}
]).then(function() {
throw 'Should fail creating a link!';
}).fail(function(reason) {
expect(reason.code).to.be('ENOENT');
expect(reason.message).to.be('Failed to create link to package');
});
});
});

254
test/commands/list.js Normal file
View File

@@ -0,0 +1,254 @@
var expect = require('expect.js');
var object = require('mout').object;
var path = require('path');
var helpers = require('../helpers');
var commands = {
install: helpers.command('install'),
list: helpers.command('list')
};
describe('bower list', function () {
var tempDir = new helpers.TempDir();
var gitPackage = new helpers.TempDir();
var install = function(packages, options, config) {
config = object.merge(config || {}, {
cwd: tempDir.path
});
return helpers.run(commands.install, [packages, options, config]);
};
var list = function(options, config) {
config = object.merge(config || {}, {
cwd: tempDir.path
});
return helpers.run(commands.list, [options, config]);
};
it('correctly reads arguments', function() {
expect(commands.list.readOptions(['-p', '-r']))
.to.eql([{
paths: true,
relative: true
}]);
});
it('correctly reads long arguments', function() {
expect(commands.list.readOptions(['--paths', '--relative']))
.to.eql([{
paths: true,
relative: true
}]);
});
it('lists no packages when nothing installed', function () {
tempDir.prepare();
return list().spread(function(results) {
expect(results).to.be.an(Object);
expect(results.canonicalDir).to.equal(tempDir.path);
expect(results.pkgMeta.dependencies).to.eql({});
expect(results.pkgMeta.devDependencies).to.eql({});
expect(results.dependencies).to.eql({});
expect(results.nrDependants).to.eql(0);
expect(results.versions).to.eql([]);
});
});
it('lists 1 dependency when 1 local package installed', function () {
var package = new helpers.TempDir({
'bower.json': {
name: 'package',
main: 'test.txt'
}
}).prepare();
package.prepare();
return install([package.path]).then(function() {
return list().spread(function(results) {
expect(results).to.be.an(Object);
expect(results.canonicalDir).to.equal(tempDir.path);
expect(results.pkgMeta.dependencies).to.eql({
package: package.path + '#*'
});
expect(results.pkgMeta.devDependencies).to.eql({});
expect(results.dependencies.package).to.be.an(Object);
expect(results.dependencies.package.pkgMeta).to.be.an(Object);
expect(results.dependencies.package.pkgMeta.main).to.equal('test.txt');
expect(results.dependencies.package.canonicalDir).to.equal(
path.join(tempDir.path, 'bower_components/package')
);
expect(results.dependencies.package.dependencies).to.eql({});
expect(results.dependencies.package.nrDependants).to.equal(1);
expect(results.dependencies.package.versions).to.eql([]);
expect(results.nrDependants).to.equal(0);
expect(results.versions).to.eql([]);
});
});
});
it('lists 1 dependency with relative paths when 1 local package installed', function () {
var package = new helpers.TempDir({
'bower.json': {
name: 'package',
main: 'test.txt'
}
}).prepare();
package.prepare();
return install([package.path]).then(function() {
return list({relative: true}).spread(function(results) {
expect(results).to.be.an(Object);
expect(results.canonicalDir).to.equal(tempDir.path);
expect(results.dependencies).to.be.an(Object);
expect(results.dependencies.package).to.be.an(Object);
expect(results.dependencies.package.pkgMeta).to.be.an(Object);
expect(results.dependencies.package.pkgMeta.main).to.equal('test.txt');
expect(results.pkgMeta.dependencies).to.eql({
package: package.path + '#*'
});
expect(results.dependencies.package.canonicalDir).to.equal(
path.normalize('bower_components/package')
);
});
});
});
it('lists 1 dependency with 1 source relative source mapping when 1 local package installed', function () {
var package = new helpers.TempDir({
'bower.json': {
name: 'package',
main: 'test.txt'
}
}).prepare();
package.prepare();
return install([package.path]).then(function() {
return list({paths: true}).spread(function(results) {
expect(results).to.be.an(Object);
expect(results.package).to.equal(
'bower_components/package/test.txt'
);
});
});
});
it('lists 1 dependency with 2 source relative source mapping when 1 local package installed', function () {
var package = new helpers.TempDir({
'bower.json': {
name: 'package',
main: ['test.txt', 'test2.txt']
}
}).prepare();
package.prepare();
return install([package.path]).then(function() {
return list({paths: true}).spread(function(results) {
expect(results).to.be.an(Object);
expect(results.package).to.be.an(Object);
expect(results.package).to.eql([
'bower_components/package/test.txt',
'bower_components/package/test2.txt'
]);
});
});
});
it('lists 1 dependency when 1 git package installed', function () {
return gitPackage.prepareGit({
'1.0.0': {
'bower.json': {
name: 'package',
main: 'test.txt'
},
'version.txt': '1.0.0'
},
'1.0.1': {
'bower.json': {
name: 'package',
main: 'test2.txt'
},
'version.txt': '1.0.1'
}
}).then(function() {
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: gitPackage.path + '#1.0.0'
}
}
});
return install().then(function() {
return list().spread(function(results) {
expect(results).to.be.an(Object);
expect(results.canonicalDir).to.equal(tempDir.path);
expect(results.pkgMeta.dependencies).to.eql({
package: gitPackage.path + '#1.0.0'
});
expect(results.pkgMeta.devDependencies).to.eql({});
expect(results.dependencies.package).to.be.an(Object);
expect(results.dependencies.package.pkgMeta).to.be.an(Object);
expect(results.dependencies.package.pkgMeta.main).to.equal('test.txt');
expect(results.dependencies.package.canonicalDir).to.equal(
path.join(tempDir.path, 'bower_components/package')
);
expect(results.dependencies.package.dependencies).to.eql({});
expect(results.dependencies.package.nrDependants).to.equal(1);
expect(results.dependencies.package.versions).to.eql(['1.0.1', '1.0.0']);
expect(results.nrDependants).to.equal(0);
expect(results.versions).to.eql([]);
});
});
});
});
it('lists 1 dependency with relative paths when 1 git package installed', function () {
return gitPackage.prepareGit({
'1.0.0': {
'bower.json': {
name: 'package',
main: 'test.txt'
},
'version.txt': '1.0.0'
},
'1.0.1': {
'bower.json': {
name: 'package',
main: 'test2.txt'
},
'version.txt': '1.0.1'
}
}).then(function() {
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: gitPackage.path + '#1.0.0'
}
}
});
return install().then(function() {
return list({relative: true}).spread(function(results) {
expect(results.canonicalDir).to.equal(tempDir.path);
expect(results.pkgMeta.dependencies).to.eql({
package: gitPackage.path + '#1.0.0'
});
expect(results.dependencies.package.canonicalDir).to.equal(
path.normalize('bower_components/package')
);
});
});
});
});
});

55
test/commands/lookup.js Normal file
View File

@@ -0,0 +1,55 @@
var expect = require('expect.js');
var helpers = require('../helpers');
var lookup = helpers.command('lookup');
describe('bower lookup', function () {
var lookupWithResult = function (response) {
return helpers.command('lookup', {
'bower-registry-client': function() {
return {
lookup: function(query, callback) {
if (query in response) {
callback(null, response[query]);
} else {
callback();
}
}
};
}
});
};
it('correctly reads arguments', function() {
expect(lookup.readOptions(['jquery']))
.to.eql(['jquery']);
});
it('lookups package by name', function () {
var lookup = lookupWithResult({ jquery: { url: 'http://jquery.org' } });
return helpers.run(lookup, ['jquery']).spread(function(result) {
expect(result).to.eql({
name: 'jquery',
url: 'http://jquery.org'
});
});
});
it('returns null if no package is found', function () {
var lookup = lookupWithResult({ jquery: { url: 'http://jquery.org' } });
return helpers.run(lookup, ['foobar']).spread(function(result) {
expect(result).to.eql(null);
});
});
it('returns null if called without argument', function () {
var lookup = lookupWithResult({ jquery: { url: 'http://jquery.org' } });
return helpers.run(lookup, []).spread(function(result) {
expect(result).to.eql(null);
});
});
});

65
test/commands/prune.js Normal file
View File

@@ -0,0 +1,65 @@
var expect = require('expect.js');
var helpers = require('../helpers');
var prune = helpers.command('prune');
describe('bower home', function () {
var package = new helpers.TempDir({
'bower.json': {
name: 'package',
dependencies: {
jquery: '*'
}
},
'bower_components/jquery/jquery.js': 'jquery source'
});
it('correctly reads arguments', function() {
expect(prune.readOptions(['-p']))
.to.eql([{ production: true }]);
});
it('correctly reads long arguments', function() {
expect(prune.readOptions(['--production']))
.to.eql([{ production: true }]);
});
it('removes extraneous packages', function () {
package.prepare({
'bower_components/angular/angular.js': 'angular source',
'bower_components/angular/.bower.json': { name: 'angular' }
});
return helpers.run(prune, [{}, { cwd: package.path }]).then(function() {
expect(package.exists('bower_components/angular/angular.js'))
.to.be(false);
});
});
it('leaves non-bower packages', function () {
package.prepare({
'bower_components/angular/angular.js': 'angular source'
});
return helpers.run(prune, [{}, { cwd: package.path }]).then(function() {
expect(package.exists('bower_components/angular/angular.js'))
.to.be(true);
});
});
it('deals with custom directory', function () {
package.prepare({
'.bowerrc': { directory: 'components' },
'bower_components/angular/.bower.json': { name: 'angular' },
'bower_components/angular/angular.js': 'angular source',
'components/angular/.bower.json': { name: 'angular' },
'components/angular/angular.js': 'angular source'
});
return helpers.run(prune, [{}, { cwd: package.path }]).then(function() {
expect(package.exists('components/angular/angular.js')).to.be(false);
expect(package.exists('bower_components/angular/angular.js')).to.be(true);
});
});
});

125
test/commands/register.js Normal file
View File

@@ -0,0 +1,125 @@
var Q = require('q');
var expect = require('expect.js');
var helpers = require('../helpers');
var register = helpers.command('register');
var fakeRepositoryFactory = function (canonicalDir, pkgMeta) {
function FakeRepository() { }
FakeRepository.prototype.fetch = function() {
return Q.fcall(function () {
return [canonicalDir, pkgMeta];
});
};
FakeRepository.prototype.getRegistryClient = function() {
return {
register: function (name, url, cb) {
cb(null, { name: name, url: url });
}
};
};
return FakeRepository;
};
var register = helpers.command('register');
var registerFactory = function (canonicalDir, pkgMeta) {
return helpers.command('register', {
'../core/PackageRepository': fakeRepositoryFactory(
canonicalDir, pkgMeta
)
});
};
describe('bower register', function () {
var package = new helpers.TempDir({
'bower.json': {
name: 'package'
}
});
it('correctly reads arguments', function() {
expect(register.readOptions(['jquery', 'url']))
.to.eql(['jquery', 'url']);
});
it('errors if name is not provided', function () {
return helpers.run(register).fail(function(reason) {
expect(reason.message).to.be('Usage: bower register <name> <url>');
expect(reason.code).to.be('EINVFORMAT');
});
});
it('errors if url is not provided', function () {
return helpers.run(register, ['some-name'])
.fail(function(reason) {
expect(reason.message).to.be('Usage: bower register <name> <url>');
expect(reason.code).to.be('EINVFORMAT');
});
});
it('errors if url is not correct', function () {
return helpers.run(register, ['some-name', 'url'])
.fail(function(reason) {
expect(reason.message).to.be('The registry only accepts URLs starting with git://');
expect(reason.code).to.be('EINVFORMAT');
});
});
it('errors if trying to register private package', function () {
package.prepare({ 'bower.json': { private: true } });
var register = registerFactory(package.path, package.meta());
return helpers.run(register, ['some-name', 'git://fake-url.git'])
.fail(function(reason) {
expect(reason.message).to.be('The package you are trying to register is marked as private');
expect(reason.code).to.be('EPRIV');
});
});
it('should call registry client with name and url', function () {
package.prepare();
var register = registerFactory(package.path, package.meta());
return helpers.run(register, ['some-name', 'git://fake-url.git'])
.spread(function(result) {
expect(result).to.eql({
// Result from register action on stub
name: 'some-name', url: 'git://fake-url.git'
});
});
});
it('should confirm in interactive mode', function () {
package.prepare();
var register = registerFactory(package.path, package.meta());
var promise = helpers.run(register,
['some-name', 'git://fake-url.git', { interactive: true }]
);
return helpers.expectEvent(promise.logger, 'confirm')
.spread(function(e) {
expect(e.type).to.be('confirm');
expect(e.message).to.be('Registering a package will make it installable via the registry (https://bower.herokuapp.com), continue?');
expect(e.default).to.be(true);
});
});
it('should skip confirming when forcing', function () {
package.prepare();
var register = registerFactory(package.path, package.meta());
return helpers.run(register,
['some-name', 'git://fake-url.git',
{ interactive: true, force: true }
]
);
});
});

44
test/commands/search.js Normal file
View File

@@ -0,0 +1,44 @@
var Q = require('q');
var expect = require('expect.js');
var helpers = require('../helpers');
var search = helpers.command('search');
describe('bower search', function () {
it('correctly reads arguments', function() {
expect(search.readOptions(['jquery']))
.to.eql(['jquery']);
});
it('searches for single repository', function () {
return Q.Promise(function(resolve) {
var search = helpers.command('search', {
'bower-registry-client': function() {
return {
search: resolve
};
}
});
helpers.run(search, ['jquery'], {});
}).then(function(query) {
expect(query).to.be('jquery');
});
});
it('lists all repositories if no query given', function () {
return Q.Promise(function(resolve) {
var search = helpers.command('search', {
'bower-registry-client': function() {
return {
list: resolve
};
}
});
helpers.run(search, [], {});
});
});
});

View File

@@ -3,7 +3,7 @@ var expect = require('expect.js');
var fs = require('fs');
var helpers = require('../helpers');
var bower = helpers.require('lib/index');
var uninstall = helpers.command('uninstall');
describe('bower uninstall', function () {
@@ -31,20 +31,24 @@ describe('bower uninstall', function () {
interactive: true
};
it('does not remove anything from dependencies by default', function () {
var logger = bower.commands.uninstall(['underscore'], undefined, config);
it('correctly reads arguments', function() {
expect(uninstall.readOptions(['jquery', '-S', '-D']))
.to.eql([['jquery'], { save: true, saveDev: true }]);
});
return helpers.expectEvent(logger, 'end')
.then(function () {
it('correctly reads long arguments', function() {
expect(uninstall.readOptions(['jquery', '--save', '--save-dev']))
.to.eql([['jquery'], { save: true, saveDev: true }]);
});
it('does not remove anything from dependencies by default', function () {
return helpers.run(uninstall, [['underscore'], undefined, config]).then(function () {
expect(bowerJson().dependencies).to.eql({ 'underscore': '*' });
});
});
it('removes dependency from bower.json if --save flag is used', function () {
var logger = bower.commands.uninstall(['underscore'], {save: true}, config);
return helpers.expectEvent(logger, 'end')
.then(function () {
return helpers.run(uninstall, [['underscore'], {save: true}, config]).then(function () {
expect(bowerJson().dependencies).to.eql({});
});
});

246
test/commands/update.js Normal file
View File

@@ -0,0 +1,246 @@
var expect = require('expect.js');
var object = require('mout').object;
var helpers = require('../helpers');
var updateCmd = helpers.command('update');
var commands = helpers.require('lib/index').commands;
describe('bower update', function () {
var tempDir = new helpers.TempDir();
var gitPackage = new helpers.TempDir();
gitPackage.prepareGit({
'1.0.0': {
'bower.json': {
name: 'package'
},
'version.txt': '1.0.0'
},
'1.0.1': {
'bower.json': {
name: 'package'
},
'version.txt': '1.0.1'
}
});
var package = new helpers.TempDir({
'bower.json': {
name: 'package'
}
}).prepare();
var updateLogger = function(packages, options, config) {
config = object.merge(config || {}, {
cwd: tempDir.path
});
return commands.update(packages, options, config);
};
var update = function(packages, options, config) {
var logger = updateLogger(packages, options, config);
return helpers.expectEvent(logger, 'end');
};
var install = function(packages, options, config) {
config = object.merge(config || {}, {
cwd: tempDir.path
});
var logger = commands.install(
packages, options, config
);
return helpers.expectEvent(logger, 'end');
};
it('correctly reads arguments', function() {
expect(updateCmd.readOptions(['jquery', '-F', '-p']))
.to.eql([['jquery'], { forceLatest: true, production: true }]);
});
it('install missing packages', function () {
package.prepare();
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: package.path
}
}
});
return update().then(function() {
expect(tempDir.exists('bower_components/package/bower.json')).to.equal(true);
expect(tempDir.read('bower_components/package/bower.json')).to.contain('"name": "package"');
});
});
it('runs preinstall hook when installing missing package', function () {
package.prepare();
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: package.path
}
},
'.bowerrc': {
scripts: {
preinstall: 'node -e \'require("fs").writeFileSync("preinstall.txt", "%")\''
}
}
});
return update().then(function() {
expect(tempDir.read('preinstall.txt')).to.be('package');
});
});
it('runs postinstall hook when installing missing package', function () {
package.prepare();
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: package.path
}
},
'.bowerrc': {
scripts: {
postinstall: 'node -e \'require("fs").writeFileSync("postinstall.txt", "%")\''
}
}
});
return update().then(function() {
expect(tempDir.read('postinstall.txt')).to.be('package');
});
});
it('doesn\'t runs postinstall when no package is update', function () {
package.prepare();
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: package.path
}
},
'.bowerrc': {
scripts: {
postinstall: 'node -e \'require("fs").writeFileSync("postinstall.txt", "%")\''
}
}
});
return install().then(function() {
tempDir.prepare();
return update().then(function() {
expect(tempDir.exists('postinstall.txt')).to.be(false);
});
});
});
it('updates a package', function () {
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: gitPackage.path + '#1.0.0'
}
}
});
return install().then(function() {
expect(tempDir.read('bower_components/package/version.txt')).to.contain('1.0.0');
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: gitPackage.path + '#1.0.1'
}
}
});
return update().then(function() {
expect(tempDir.read('bower_components/package/version.txt')).to.contain('1.0.1');
});
});
});
it('runs preinstall hook when updating a package', function () {
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: gitPackage.path + '#1.0.0'
}
},
'.bowerrc': {
scripts: {
preinstall: 'node -e \'require("fs").writeFileSync("preinstall.txt", "%")\''
}
}
});
return install().then(function() {
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: gitPackage.path + '#1.0.1'
}
}
});
expect(tempDir.exists('preinstall.txt')).to.be(false);
return update().then(function() {
expect(tempDir.read('preinstall.txt')).to.be('package');
});
});
});
it('runs postinstall hook when updating a package', function () {
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: gitPackage.path + '#1.0.0'
}
},
'.bowerrc': {
scripts: {
preinstall: 'node -e \'require("fs").writeFileSync("preinstall.txt", "%")\'',
postinstall: 'node -e \'require("fs").writeFileSync("postinstall.txt", "%")\''
}
}
});
return install().then(function() {
tempDir.prepare({
'bower.json': {
name: 'test',
dependencies: {
package: gitPackage.path + '#1.0.1'
}
}
});
expect(tempDir.exists('postinstall.txt')).to.be(false);
return update().then(function() {
expect(tempDir.read('postinstall.txt')).to.be('package');
});
});
});
});

91
test/commands/version.js Normal file
View File

@@ -0,0 +1,91 @@
var expect = require('expect.js');
var helpers = require('../helpers');
var version = helpers.require('lib/commands').version;
describe('bower list', function () {
var package = new helpers.TempDir({
'bower.json': {
name: 'foobar',
version: '0.0.0'
}
});
var gitPackage = new helpers.TempDir({
'v0.0.0': {
'bower.json': {
name: 'foobar',
version: '0.0.0'
}
}
});
it('bumps patch version', function() {
package.prepare();
return helpers.run(version, ['patch', {}, { cwd: package.path }]).then(function() {
expect(package.readJson('bower.json').version).to.be('0.0.1');
});
});
it('bumps minor version', function() {
package.prepare();
return helpers.run(version, ['minor', {}, { cwd: package.path }]).then(function() {
expect(package.readJson('bower.json').version).to.be('0.1.0');
});
});
it('bumps major version', function() {
package.prepare();
return helpers.run(version, ['major', {}, { cwd: package.path }]).then(function() {
expect(package.readJson('bower.json').version).to.be('1.0.0');
});
});
it('changes version', function() {
package.prepare();
return helpers.run(version, ['1.2.3', {}, { cwd: package.path }]).then(function() {
expect(package.readJson('bower.json').version).to.be('1.2.3');
});
});
it('bumps patch version, create commit, and tag', function() {
return gitPackage.prepareGit().then(function() {
return helpers.run(version, ['patch', {}, { cwd: gitPackage.path }]).then(function() {
expect(gitPackage.readJson('bower.json').version).to.be('0.0.1');
return gitPackage.git('tag').spread(function(result) {
expect(result).to.be('v0.0.0\nv0.0.1\n');
return gitPackage.git('log', '--pretty=format:%s', '-n1').spread(function(result) {
expect(result).to.be('v0.0.1');
});
});
});
});
});
it('bumps with custom commit message', function() {
return gitPackage.prepareGit().then(function() {
return helpers.run(version, ['patch', { message: 'Bumping %s, because what'}, { cwd: gitPackage.path }]).then(function() {
expect(gitPackage.readJson('bower.json').version).to.be('0.0.1');
return gitPackage.git('tag').spread(function(result) {
expect(result).to.be('v0.0.0\nv0.0.1\n');
return gitPackage.git('log', '--pretty=format:%s', '-n1').spread(function(result) {
expect(result).to.be('Bumping 0.0.1, because what');
});
});
});
});
});
});

View File

@@ -11,6 +11,7 @@ var defaultConfig = require('../../lib/config');
var ResolveCache = require('../../lib/core/ResolveCache');
var resolvers = require('../../lib/core/resolvers');
var copy = require('../../lib/util/copy');
var helpers = require('../helpers');
describe('PackageRepository', function () {
var packageRepository;
@@ -21,7 +22,8 @@ describe('PackageRepository', function () {
var tempPackage = path.resolve(__dirname, '../tmp/temp-package');
var packagesCacheDir = path.join(__dirname, '../tmp/temp-resolve-cache');
var registryCacheDir = path.join(__dirname, '../tmp/temp-registry-cache');
var mockSource = 'file://' + testPackage;
var mockSource = helpers.localSource(testPackage);
var forceCaching = true;
after(function () {
@@ -65,7 +67,7 @@ describe('PackageRepository', function () {
return Q.resolve(resolver);
}
resolverFactory.getConstructor = function () {
return Q.resolve([resolvers.GitRemote, 'file://' + testPackage, false]);
return Q.resolve([resolvers.GitRemote, helpers.localSource(testPackage), false]);
};
resolverFactory.clearRuntimeCache = function () {
resolverFactoryClearHook();
@@ -182,7 +184,7 @@ describe('PackageRepository', function () {
return originalRetrieve.apply(this, arguments);
};
packageRepository.fetch({ name: '', source: testPackage, target: '~0.1.0' })
packageRepository.fetch({ name: '', source: helpers.localSource(testPackage), target: '~0.1.0' })
.spread(function (canonicalDir, pkgMeta) {
expect(called).to.be(false);
expect(fs.existsSync(canonicalDir)).to.be(true);

View File

@@ -908,7 +908,6 @@ describe('ResolveCache', function () {
expect(entries).to.be.an('array');
expectedJson = fs.readFileSync(path.join(__dirname, '../assets/resolve-cache/list-json-1.json'));
expectedJson = expectedJson.toString().trim();
mout.object.forOwn(entries, function (entry) {
// Trim absolute bower path from json
@@ -917,8 +916,7 @@ describe('ResolveCache', function () {
entry.canonicalDir = entry.canonicalDir.replace(/\\/g, '/');
});
json = JSON.stringify(entries, null, ' ');
expect(json).to.equal(expectedJson);
expect(entries).to.eql(JSON.parse(expectedJson));
next();
})

View File

@@ -10,6 +10,7 @@ var Logger = require('bower-logger');
var resolverFactory = require('../../lib/core/resolverFactory');
var resolvers = require('../../lib/core/resolvers');
var defaultConfig = require('../../lib/config');
var helpers = require('../helpers');
describe('resolverFactory', function () {
var tempSource;
@@ -30,7 +31,7 @@ describe('resolverFactory', function () {
});
after(function (next) {
rimraf('dejavu', next);
rimraf('pure', next);
});
function callFactory(decEndpoint, config) {
@@ -339,7 +340,9 @@ describe('resolverFactory', function () {
.done();
});
it('should recognize svn remote endpoints correctly', function (next) {
if (!helpers.hasSvn())
describe.skip('should recognize svn remote endpoints correctly', function() {});
else it('should recognize svn remote endpoints correctly', function (next) {
var promise = Q.resolve();
var endpoints;
@@ -524,31 +527,31 @@ describe('resolverFactory', function () {
});
it('should recognize registry endpoints correctly', function (next) {
// Create a 'dejavu' file at the root to prevent regressions of #666
fs.writeFileSync('dejavu', 'foo');
// Create a 'pure' file at the root to prevent regressions of #666
fs.writeFileSync('pure', 'foo');
callFactory({ source: 'dejavu' })
callFactory({ source: 'pure' })
.then(function (resolver) {
expect(resolver).to.be.a(resolvers.GitRemote);
expect(resolver.getSource()).to.equal('git://github.com/IndigoUnited/dejavu.git');
expect(resolver.getSource()).to.equal('git://github.com/yui/pure-release.git');
expect(resolver.getTarget()).to.equal('*');
})
.then(function () {
// Test with name
return callFactory({ source: 'dejavu', name: 'foo' })
return callFactory({ source: 'pure', name: 'foo' })
.then(function (resolver) {
expect(resolver).to.be.a(resolvers.GitRemote);
expect(resolver.getSource()).to.equal('git://github.com/IndigoUnited/dejavu.git');
expect(resolver.getSource()).to.equal('git://github.com/yui/pure-release.git');
expect(resolver.getName()).to.equal('foo');
expect(resolver.getTarget()).to.equal('*');
});
})
.then(function () {
// Test with target
return callFactory({ source: 'dejavu', target: '~2.0.0' })
return callFactory({ source: 'pure', target: '~0.4.0' })
.then(function (resolver) {
expect(resolver).to.be.a(resolvers.GitRemote);
expect(resolver.getTarget()).to.equal('~2.0.0');
expect(resolver.getTarget()).to.equal('~0.4.0');
next();
});
@@ -571,7 +574,7 @@ describe('resolverFactory', function () {
});
it('should set registry to true on the decomposed endpoint if fetched from the registry', function (next) {
var decEndpoint = { source: 'dejavu' };
var decEndpoint = { source: 'pure' };
callFactory(decEndpoint)
.then(function () {

View File

@@ -9,11 +9,13 @@ var mout = require('mout');
var Logger = require('bower-logger');
var SvnResolver = require('../../../lib/core/resolvers/SvnResolver');
var defaultConfig = require('../../../lib/config');
var helpers = require('../../helpers');
describe('SvnResolver', function () {
if (!helpers.hasSvn()) describe.skip('SvnResolver', function() {});
else describe('SvnResolver', function () {
var tempDir = path.resolve(__dirname, '../../tmp/tmp');
var testPackage = path.resolve(__dirname, '../../assets/package-svn/repo');
var testPackageAdmin = path.resolve(__dirname, '../../assets/package-svn/admin');
// var testPackageAdmin = path.resolve(__dirname, '../../assets/package-svn/admin');
var originaltags = SvnResolver.tags;
var logger;
@@ -1000,7 +1002,7 @@ describe('SvnResolver', function () {
it('should guess the name from the path', function () {
var resolver;
resolver = create('file://' + testPackage);
resolver = create(helpers.localSource(testPackage));
expect(resolver.getName()).to.equal('repo');
resolver = create('svn+http://yii.googlecode.com/svn');
@@ -1011,7 +1013,7 @@ describe('SvnResolver', function () {
describe('.resolve', function () {
it('should export correctly if resolution is a tag', function (next) {
var resolver = create({ source: 'file://' + testPackageAdmin, target: '0.0.1' });
var resolver = create({ source: testPackage, target: '0.0.1' });
resolver.resolve()
.then(function (dir) {
@@ -1027,7 +1029,7 @@ describe('SvnResolver', function () {
});
it('should export correctly if resolution is a commit', function (next) {
var resolver = create({ source: 'file://' + testPackageAdmin, target: 'r1' });
var resolver = create({ source: testPackage, target: 'r1' });
resolver.resolve()
.then(function (dir) {

View File

@@ -12,12 +12,22 @@ describe('scripts', function () {
var packageName = 'package-zip';
var packageDir = path.join(__dirname, '../assets/' + packageName + '.zip');
// We cannot use pure touch, because Windows
var touch = function (file) {
return 'node -e "var fs = require(\'fs\'); fs.closeSync(fs.openSync(\'' + file + '\', \'w\'));"';
};
// We cannot use pure touch, because Windows
var touchWithPid = function (file) {
return 'node -e "var fs = require(\'fs\'); fs.closeSync(fs.openSync(process.env.BOWER_PID + \'' + file + '\', \'w\'));"';
};
var config = {
cwd: tempDir,
scripts: {
preinstall: 'touch preinstall_%',
postinstall: 'touch postinstall_%',
preuninstall: 'touch preuninstall_%'
preinstall: touch('preinstall_%'),
postinstall: touch('postinstall_%'),
preuninstall: touch('preuninstall_%')
}
};
@@ -112,7 +122,7 @@ describe('scripts', function () {
it('should process scripts with quotes and vars in the cmd properly.', function (next) {
config.scripts.preinstall = 'touch "$BOWER_PID %"';
config.scripts.preinstall = touchWithPid(' %');
bower.commands
.install([packageDir], undefined, config)

View File

@@ -1,3 +1,5 @@
require('chalk').enabled = false;
var Q = require('q');
var path = require('path');
var mkdirp = require('mkdirp');
@@ -7,20 +9,26 @@ var object = require('mout/object');
var fs = require('fs');
var glob = require('glob');
var os = require('os');
var which = require('which');
var path = require('path');
var proxyquire = require('proxyquire').noCallThru().noPreserveCache();
var cmd = require('../lib/util/cmd');
var config = require('../lib/config');
// For better promise errors
Q.longStackSupport = true;
// Those are needed for Travis or not configured git environment
var env = {
'GIT_AUTHOR_DATE': 'Sun Apr 7 22:13:13 2013 +0000',
'GIT_AUTHOR_NAME': 'André Cruz',
'GIT_AUTHOR_EMAIL': 'amdfcruz@gmail.com',
'GIT_COMMITTER_DATE': 'Sun Apr 7 22:13:13 2013 +0000',
'GIT_COMMITTER_NAME': 'André Cruz',
'GIT_COMMITTER_EMAIL': 'amdfcruz@gmail.com'
'GIT_COMMITTER_EMAIL': 'amdfcruz@gmail.com',
};
// Preserve the original environment
object.mixIn(env, process.env);
object.mixIn(process.env, env);
var tmpLocation = path.join(
os.tmpdir ? os.tmpdir() : os.tmpDir(),
@@ -28,8 +36,12 @@ var tmpLocation = path.join(
uuid.v4().slice(0, 8)
);
exports.require = function (name) {
return require(path.join(__dirname, '../', name));
exports.require = function (name, stubs) {
if (stubs) {
return proxyquire(path.join(__dirname, '../', name), stubs);
} else {
return require(path.join(__dirname, '../', name));
}
};
// We need to reset cache because tests are reusing temp directories
@@ -47,10 +59,19 @@ exports.TempDir = (function() {
this.defaults = defaults;
}
TempDir.prototype.create = function (files) {
TempDir.prototype.create = function (files, defaults) {
var that = this;
files = object.merge(files || {}, this.defaults);
defaults = defaults || this.defaults || {};
files = object.merge(files || {}, defaults);
this.meta = function(tag) {
if (tag) {
return files[tag]['bower.json'];
} else {
return files['bower.json'];
}
};
if (files) {
object.forOwn(files, function (contents, filepath) {
@@ -97,7 +118,7 @@ exports.TempDir = (function() {
rimraf.sync(fullPath);
});
that.create(files);
that.create(files, {});
}).then(function () {
return that.git('add', '-A');
}).then(function () {
@@ -117,8 +138,16 @@ exports.TempDir = (function() {
});
};
TempDir.prototype.getPath = function (name) {
return path.join(this.path, name);
};
TempDir.prototype.read = function (name) {
return fs.readFileSync(path.join(this.path, name), 'utf8');
return fs.readFileSync(this.getPath(name), 'utf8');
};
TempDir.prototype.readJson = function (name) {
return JSON.parse(this.read(name));
};
TempDir.prototype.git = function () {
@@ -134,12 +163,139 @@ exports.TempDir = (function() {
return TempDir;
})();
exports.expectEvent = function (emitter, eventName) {
exports.expectEvent = function expectEvent(emitter, eventName) {
var deferred = Q.defer();
emitter.once(eventName, function () {
deferred.resolve(arguments);
});
emitter.once('error', function (reason) {
deferred.reject(reason);
});
return deferred.promise;
};
exports.command = function (command, stubs) {
var rawCommand;
var commandStubs = {};
stubs = stubs || {};
var cwd = stubs.cwd;
delete stubs.cwd;
rawCommand = exports.require(
'lib/commands/' + command, stubs
);
commandStubs['./' + command] = function () {
var args = [].slice.call(arguments);
args[rawCommand.length - 1] = object.merge({ cwd: cwd }, args[rawCommand.length - 1] || {});
return rawCommand.apply(null, args);
};
var instance = exports.require(
'lib/commands/index', commandStubs
);
var commandParts = command.split('/');
while (commandParts.length > 0) {
instance = instance[commandParts.shift()];
}
if (!instance) {
throw new Error('Unknown command: ' + command);
}
// TODO: refactor tests, so they can use readOptions directly
instance.readOptions = function (argv) {
argv = ['node', 'bower'].concat(argv);
argv = command.split('/').concat(argv);
return rawCommand.readOptions(argv);
};
return instance;
};
exports.run = function (command, args) {
var logger = command.apply(command, args || []);
// Hack so we can intercept prompring for data
logger.prompt = function(data) {
logger.emit('confirm', data);
};
var promise = exports.expectEvent(logger, 'end');
promise.logger = logger;
return promise;
};
// Captures all stdout and stderr
exports.capture = function(callback) {
var oldStdout = process.stdout.write;
var oldStderr = process.stderr.write;
var stdout = '';
var stderr = '';
process.stdout.write = function(text) {
stdout += text;
};
process.stderr.write = function(text) {
stderr += text;
};
return Q.fcall(callback).then(function() {
process.stdout.write = oldStdout;
process.stderr.write = oldStderr;
return [stdout, stderr];
}).fail(function(e) {
process.stdout.write = oldStdout;
process.stderr.write = oldStderr;
throw e;
});
};
exports.hasSvn = function() {
try {
which.sync('svn');
return true;
} catch (ex) {
return false;
}
};
exports.isWin = function() {
return process.platform === 'win32';
};
exports.localSource = function (localPath) {
localPath = path.normalize(localPath);
if (!exports.isWin()) {
localPath = 'file://' + localPath;
}
return localPath;
};
// Used for example by "svn checkout" and "svn export"
exports.localUrl = function (localPath) {
localPath = path.normalize(localPath);
if (!exports.isWin()) {
localPath = 'file://' + localPath;
} else {
localPath = 'file:///' + localPath;
}
return localPath;
};

View File

@@ -10,6 +10,23 @@ var cmd = require('../lib/util/cmd');
var packages = require('./packages-svn.json');
var nopt = require('nopt');
var isWin = function() {
return process.platform === 'win32';
};
var pathToUrl = function (localPath) {
localPath = path.normalize(localPath);
if (!isWin()) {
localPath = 'file://' + localPath;
} else {
localPath = 'file:///' + localPath;
}
return localPath;
};
var options = nopt({
'force': Boolean
}, {
@@ -22,15 +39,22 @@ var env = {};
mout.object.mixIn(env, process.env);
function ensurePackage(admin, dir) {
var promise;
var promise = new Q();
// If force is specified, delete folder
if (options.force) {
promise = Q.nfcall(rimraf, dir)
.then(function () {
promise = promise.then(function () {
return Q.nfcall(rimraf, admin);
});
promise = promise.then(function () {
return Q.nfcall(rimraf, dir);
});
promise = promise.then(function () {
throw new Error();
});
// Otherwise check if .svn is already created
// Otherwise check if .git is already created
} else {
promise = Q.nfcall(fs.stat, path.join(dir, '.svn'));
}
@@ -40,9 +64,9 @@ function ensurePackage(admin, dir) {
// Create dir
return Q.nfcall(mkdirp, dir)
// Init svn repo
.then(cmd.bind(null, 'svnadmin', ['create', admin]))
.then(cmd.bind(null, 'svnadmin', ['create', admin], {}))
// checkout the repo
.then(cmd.bind(null, 'svn', ['checkout', 'file://' + admin, dir]))
.then(cmd.bind(null, 'svn', ['checkout', pathToUrl(admin), dir], {}))
// create directory structure
.then(cmd.bind(null, 'svn', ['mkdir', 'trunk'], { cwd: dir }))
.then(cmd.bind(null, 'svn', ['mkdir', 'tags'], { cwd: dir }))
@@ -81,7 +105,7 @@ function checkRelease(dir, release) {
function createRelease(admin, dir, release, files) {
// checkout the repo
return cmd('svn', ['checkout', 'file://' + admin, dir])
return cmd('svn', ['checkout', pathToUrl(admin), dir])
// Attempt to delete branch, ignoring the error
.then(function () {
return cmd('svn', ['delete', dir + '/branches/' + release], { cwd: dir })

View File

@@ -0,0 +1,104 @@
var expect = require('chai').expect;
var helpers = require('../helpers');
var multiline = require('multiline').stripIndent;
var JsonRenderer = helpers.require('lib/renderers/JsonRenderer');
var jsonRendererWithPrompt = function (stubs) {
return helpers.require('lib/renderers/JsonRenderer', {
promptly: stubs
});
};
// When cloning on Windows it's possible carrets are used
var normalize = function (string) {
return string.replace(/\r\n|\r/g, '\n');
};
describe('JsonRenderer', function () {
it('logs simple message to stderr', function () {
return helpers.capture(function() {
var renderer = new JsonRenderer();
renderer.log({
id: 'foobar',
message: 'hello world'
});
renderer.end();
}).spread(function(stdout, stderr) {
expect(stderr).to.eq(normalize(multiline(function(){/*
[{
"id": "foobar",
"message": "hello world"
}]
*/})));
});
});
it('logs error message to stderr', function () {
return helpers.capture(function() {
var renderer = new JsonRenderer();
renderer.error({
id: 'foobar',
message: 'hello world',
data: {
foo: 'bar'
},
stacktrace: [
'./foo:23',
'./bar:23'
]
});
}).spread(function(stdout, stderr) {
expect(stderr).to.eq(normalize(multiline(function(){/*
[{
"id": "error",
"data": {
"foo": "bar"
},
"stacktrace": "N/A",
"level": "error",
"message": "hello world"
}]
*/})));
});
});
it('prompts for answer', function () {
var JsonRenderer = jsonRendererWithPrompt({
prompt: function(name, opts, callback) {
callback(null, 'something2');
}
});
var renderer = new JsonRenderer();
return helpers.capture(function() {
return renderer.prompt([
{
type: 'input',
name: 'field',
message: 'Please enter something',
default: 'something'
}
]).then(function(response) {
expect(response.field).to.eq('something2');
renderer.end();
});
}).spread(function(stdout, stderr) {
expect(stderr).to.eq(normalize(multiline(function(){/*
[{
"type": "input",
"name": "field",
"message": "Please enter something",
"default": "something",
"level": "prompt"
}]
*/})));
});
});
});

View File

@@ -0,0 +1,801 @@
// Simulate wide terminal
process.stdout.columns = 130;
var expect = require('chai').expect;
var helpers = require('../helpers');
var multiline = require('multiline').stripIndent;
var StandardRenderer = helpers.require('lib/renderers/StandardRenderer');
describe('StandardRenderer', function () {
it('logs generic simple message', function () {
return helpers.capture(function() {
var renderer = new StandardRenderer();
renderer.log({
id: 'foobar',
message: 'hello world'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.eq(multiline(function(){/*
bower foobar hello world
*/}));
});
});
it('logs simple error', function () {
return helpers.capture(function() {
var renderer = new StandardRenderer();
renderer.error({
code: 'EFOOBAR',
message: 'Hello error'
});
}).spread(function(stdout, stderr) {
expect(stderr).to.eq(multiline(function(){/*
bower EFOOBAR Hello error
*/}));
});
});
it('logs error with details', function () {
return helpers.capture(function() {
var renderer = new StandardRenderer();
renderer.error({
code: 'EFOOBAR',
message: 'Hello error',
details: ' Some awesome details\nMultiline! '
});
}).spread(function(stdout, stderr) {
expect(stderr).to.eq(multiline(function(){/*
bower EFOOBAR Hello error
Additional error details:
Some awesome details
Multiline!
*/}));
});
});
it('logs system details in verbose mode', function () {
return helpers.capture(function() {
var renderer = new StandardRenderer(undefined, { verbose: true });
renderer.error({
code: 'EFOOBAR',
message: 'Hello error',
details: ' Some awesome details\nMultiline! '
});
}).spread(function(stdout, stderr) {
expect(stderr).to.match(new RegExp(multiline(function(){/*
System info:
Bower version: [^\r\n]+
Node version: [^\r\n]+
OS: [^\r\n]+
*/})));
});
});
it('logs stack trace in verbose mode', function () {
return helpers.capture(function() {
var renderer = new StandardRenderer(undefined, { verbose: true });
renderer.error({
code: 'EFOOBAR',
message: 'Hello error',
details: ' Some awesome details\nMultiline! ',
stack: [
'./one.js:1',
'./two.js:2'
]
});
}).spread(function(stdout, stderr) {
expect(stderr).to.string(multiline(function(){/*
Stack trace:
./one.js:1
./two.js:2
*/}));
});
});
it('logs console trace in verbose mode', function () {
return helpers.capture(function() {
var renderer = new StandardRenderer(undefined, { verbose: true });
renderer.error({
code: 'EFOOBAR',
message: 'Hello error',
details: ' Some awesome details\nMultiline! '
});
}).spread(function(stdout, stderr) {
expect(stderr).to.match(new RegExp(multiline(function(){/*
Console trace:
Error
at StandardRenderer.error \(.+?\)
*/})));
});
});
it('outputs checkout command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer();
renderer.log({
id: 'checkout',
origin: 'jquery#master',
message: 'foobar'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
bower checkout jquery#foobar
*/}));
});
});
it('outputs full progress for wide command', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('install');
renderer.log({
id: 'progress',
origin: 'jquery#master',
message: 'foobar'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
bower jquery#master progress foobar
*/}));
});
});
it('outputs full progress for narrow command', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('help');
renderer.log({
id: 'progress',
origin: 'jquery#master',
message: 'foobar'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
bower progress jquery#master foobar
*/}));
});
});
it('outputs extract log just as progress log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('install');
renderer.log({
id: 'extract',
origin: 'jquery#master',
message: 'foobar'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
bower jquery#master extract foobar
*/}));
});
});
it('outputs incompatible log with suitable package', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer();
renderer.log({
id: 'incompatible',
data: {
resolution: '~0.1.1',
suitable: {
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'foobar'
}
},
picks: [
{
pkgMeta: {
_release: '0.0.0'
},
endpoint: {
name: 'fizfuz',
target: '~0.0.0'
},
dependants: [
{
pkgMeta: {
_release: 'release1'
},
endpoint: {
name: 'dependant1'
}
},
{
pkgMeta: {
_release: 'release2'
},
endpoint: {
name: 'dependant2'
}
}
]
},
{
endpoint: {
name: 'fizfuz2'
},
dependants: [
{
pkgMeta: {
// no release
},
endpoint: {
name: 'jquery2'
}
}
]
}
]
}
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
Please note that,
dependant1#release1, dependant2#release2 depends on fizfuz#~0.0.0 which resolved to fizfuz#0.0.0
jquery2 depends on fizfuz2#
Resort to using foobar#~0.1.1 which resolved to foobar#0.1.2
Code incompatibilities may occur.
*/}));
});
});
it('outputs solver log without suitable package', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer();
renderer.log({
id: 'solved',
data: {
resolution: '~0.1.1',
picks: [
{
pkgMeta: {
_release: '0.0.0'
},
endpoint: {
name: 'fizfuz',
target: '~0.0.0'
},
dependants: [
{
pkgMeta: {
_release: 'release1'
},
endpoint: {
name: 'dependant1'
}
},
{
pkgMeta: {
_release: 'release2'
},
endpoint: {
name: 'dependant2'
}
}
]
},
{
endpoint: {
name: 'fizfuz2'
},
dependants: [
{
pkgMeta: {
// no release
},
endpoint: {
name: 'jquery2'
}
}
]
}
]
}
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
Unable to find a suitable version for , please choose one:
1) fizfuz#~0.0.0 which resolved to 0.0.0 and is required by dependant1#release1, dependant2#release2
2) fizfuz2# and is required by jquery2
Prefix the choice with ! to persist it to bower.json
*/}));
});
});
it('outputs json log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer();
renderer.log({
id: 'json',
data: {
json: {
foo: 'bar',
fiz: {
fuz: 'faz'
}
}
}
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
{
foo: 'bar',
fiz: {
fuz: 'faz'
}
}
*/}));
});
});
it('outputs cached entry log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('install');
renderer.log({
id: 'cached-entry',
origin: 'origin',
message: 'message'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
bower origin cached message
*/}));
});
});
it('adjusts whitespace when package id too long', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('install', {});
renderer.log({
id: 'generic',
origin: 'short-origin',
message: 'message'
});
renderer.log({
id: 'generic',
origin: 'very-very-long-origin-string',
message: 'message'
});
renderer.log({
id: 'generic',
origin: 'short-origin',
message: 'message'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
bower short-origin generic message
bower very-very-long-origin-string generic message
bower short-origin generic message
*/}));
});
});
it('outputs install command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('install', {
cwd: '/tmp'
});
renderer.end([
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery'
}
},
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
version: '0.1.2'
},
endpoint: {
name: 'jquery'
}
},
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery'
},
missing: true
},
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery'
},
different: true
},
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery'
},
linked: true
},
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery',
target: '~0.1.2'
},
incompatible: true
},
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery',
target: '~0.1.2'
},
extraneous: true
},
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery',
target: '~0.1.2'
},
update: {
target: '0.1.5',
latest: '0.2.0'
}
},
{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery'
},
dependencies: {
angular: {
canonicalDir: '/tmp/components/angular',
pkgMeta: {
_release: '0.1.3'
},
endpoint: {
name: 'angular'
}
},
ember: {
canonicalDir: '/tmp/components/ember',
pkgMeta: {
_release: '0.2.3'
},
endpoint: {
name: 'ember'
},
dependencies: {
// Should be ingored (only one level)
react: {
canonicalDir: '/tmp/components/react',
pkgMeta: {
_release: '0.2.3'
},
endpoint: {
name: 'react'
}
}
}
}
}
}
]);
}).spread(function(stdout, stderr) {
if (helpers.isWin()) {
expect(stdout).to.equal(multiline(function(){/*
jquery#0.1.2 components\jquery
jquery#0.1.2 components\jquery
jquery components\jquery not installed
jquery#0.1.2 components\jquery different
jquery#0.1.2 components\jquery linked
jquery#0.1.2 components\jquery incompatible with ~0.1.2
jquery#0.1.2 components\jquery extraneous
jquery#0.1.2 components\jquery (0.1.5 available, latest is 0.2.0)
jquery#0.1.2 components\jquery
├── angular#0.1.3
└── ember#0.2.3
*/}));
} else {
expect(stdout).to.equal(multiline(function(){/*
jquery#0.1.2 components/jquery
jquery#0.1.2 components/jquery
jquery components/jquery not installed
jquery#0.1.2 components/jquery different
jquery#0.1.2 components/jquery linked
jquery#0.1.2 components/jquery incompatible with ~0.1.2
jquery#0.1.2 components/jquery extraneous
jquery#0.1.2 components/jquery (0.1.5 available, latest is 0.2.0)
jquery#0.1.2 components/jquery
├── angular#0.1.3
└── ember#0.2.3
*/}));
}
});
});
it('outputs short info command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('info', {});
renderer.end({
version: '1.2.3'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
{
version: '1.2.3'
}
*/}));
});
});
it('outputs full info command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('info', {});
renderer.end({
name: 'foo',
latest: {
version: '1.2.3'
},
versions: [
'1.2.0',
'1.2.1',
'1.2.2'
]
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
{
version: '1.2.3'
}
Available versions:
- 1.2.0
- 1.2.1
- 1.2.2
You can request info for a specific version with 'bower info foo#<version>'
*/}));
});
});
it('outputs lookup command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('lookup', {});
renderer.end({
name: 'bower',
url: 'http://bower.io'
});
renderer.end({
name: 'bower'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
bower http://bower.io
Package not found.
*/}));
});
});
it('outputs link command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('link', { cwd: '/tmp' });
renderer.end({
src: './foo',
dst: './bar',
installed: [{
canonicalDir: '/tmp/components/jquery',
pkgMeta: {
_release: '0.1.2'
},
endpoint: {
name: 'jquery'
}
}]
});
}).spread(function(stdout, stderr) {
if (helpers.isWin()) {
expect(stdout).to.equal(multiline(function(){/*
bower link ./bar > ./foo
jquery#0.1.2 components\jquery
*/}));
} else {
expect(stdout).to.equal(multiline(function(){/*
bower link ./bar > ./foo
jquery#0.1.2 components/jquery
*/}));
}
});
});
it('outputs search command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('search');
renderer.end([
{
name: 'jquery',
url: 'http://jquery.io'
},
{
name: 'bower',
url: 'http://bower.io'
}
]);
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
Search results:
jquery http://jquery.io
bower http://bower.io
*/}));
});
});
it('outputs register command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('register');
renderer.end({
name: 'jquery',
url: 'http://jquery.io'
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
Package jquery registered successfully!
All valid semver tags on http://jquery.io will be available as versions.
To publish a new version, just release a valid semver tag.
Run bower info jquery to list the available versions.
*/}));
});
});
it('outputs cache list command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('cache list');
renderer.end([
{
pkgMeta: {
name: 'awesome-jquery',
_target: '0.1.1',
_source: 'jquery'
}
}
]);
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
awesome-jquery=jquery#0.1.1
*/}));
});
});
it('outputs help command log', function() {
return helpers.capture(function() {
var renderer = new StandardRenderer('help');
renderer.end({
'command': 'uninstall',
'description': 'Uninstalls a package locally from your bower_components directory',
'usage': [
'uninstall <name> [<name> ..] [<options>]'
],
'options': [
{
'shorthand': '-h',
'flag': '--help',
'description': 'Show this help message'
},
{
'shorthand': '-S',
'flag': '--save',
'description': 'Remove uninstalled packages from the project\'s bower.json dependencies'
},
{
'shorthand': '-D',
'flag': '--save-dev',
'description': 'Remove uninstalled packages from the project\'s bower.json devDependencies'
}
]
});
}).spread(function(stdout, stderr) {
expect(stdout).to.equal(multiline(function(){/*
Usage:
bower uninstall <name> [<name> ..] [<options>]
Options:
-h, --help Show this help message
-S, --save Remove uninstalled packages from the project's bower.json dependencies
-D, --save-dev Remove uninstalled packages from the project's bower.json devDependencies
Additionally all global options listed in 'bower help' are available
Description:
Uninstalls a package locally from your bower_components directory
*/}));
});
});
});

View File

@@ -1,3 +1,11 @@
var helpers = require('./helpers');
if (!helpers.hasSvn()) {
console.warn('#######################################################');
console.warn('It is recommended you install svn for complete testing!');
console.warn('#######################################################');
}
// Cleanup the uncaughtException added by the tmp module
// It messes with the mocha uncaughtException event to caught errors
// Please note that is the Resolver that calls tmp.setGracefulCleanup()
@@ -18,5 +26,7 @@ require('./core/resolveCache');
require('./core/packageRepository');
require('./core/scripts');
require('./core/Manager');
require('./renderers/StandardRenderer.js');
require('./renderers/JsonRenderer.js');
require('./commands/index.js');
require('./util/index.js');

View File

@@ -12,65 +12,73 @@ describe('analytics', function () {
callback(undefined, promptResponse);
}
});
},
}
});
};
describe('#setup', function () {
it('leaves analytics enabled if provided', function () {
var config = { analytics: true };
return mockAnalytics().setup(config).then(function () {
expect(config.analytics).to.be(true);
});
return mockAnalytics()
.setup({ analytics: true })
.then(function (enabled) {
expect(enabled).to.be(true);
});
});
it('leaves analytics disabled if provided', function () {
var config = { analytics: false };
return mockAnalytics().setup(config).then(function () {
expect(config.analytics).to.be(false);
});
return mockAnalytics()
.setup({ analytics: false })
.then(function (enabled) {
expect(enabled).to.be(false);
});
});
it('defaults to false if insight.optOut is true', function () {
var config = { };
return mockAnalytics({ optOut: true }).setup(config).then(function () {
expect(config.analytics).to.be(false);
});
it('disables analytics for non-interactive mode', function () {
return mockAnalytics()
.setup({ interactive: false })
.then(function (enabled) {
expect(enabled).to.be(false);
});
});
it('defaults to true if insight.optOut is false', function () {
var config = { };
return mockAnalytics({ optOut: false }).setup(config).then(function () {
expect(config.analytics).to.be(true);
});
it('disables if insight.optOut is true and interactive', function () {
return mockAnalytics({ optOut: true })
.setup({ interactive: true })
.then(function (enabled) {
expect(enabled).to.be(false);
});
});
it('defaults to true if insight.optOut is undefined and noninteractive', function () {
var config = { };
return mockAnalytics({ optOut: undefined }).setup(config).then(function () {
expect(config.analytics).to.be(true);
});
it('enables if insight.optOut is false and interactive', function () {
return mockAnalytics({ optOut: false })
.setup({ interactive: true })
.then(function (enabled) {
expect(enabled).to.be(true);
});
});
it('defautls to true if interactive insights return true from prompt', function () {
var config = { interactive: true };
return mockAnalytics({ optOut: undefined }, true).setup(config).then(function () {
expect(config.analytics).to.be(true);
});
it('disables if insight.optOut is false and non-interactive', function () {
return mockAnalytics({ optOut: false })
.setup({ interactive: false })
.then(function (enabled) {
expect(enabled).to.be(false);
});
});
it('defautls to false if interactive insights return false from prompt', function () {
var config = { interactive: true };
it('enables if interactive insights return true from prompt', function () {
return mockAnalytics({ optOut: undefined }, true)
.setup({ interactive: true })
.then(function (enabled) {
expect(enabled).to.be(true);
});
});
return mockAnalytics({ optOut: undefined }, false).setup(config).then(function () {
expect(config.analytics).to.be(false);
});
it('disables if interactive insights return false from prompt', function () {
return mockAnalytics({ optOut: undefined }, false)
.setup({ interactive: true })
.then(function (enabled) {
expect(enabled).to.be(false);
});
});
});
@@ -83,9 +91,7 @@ describe('analytics', function () {
}
});
new analytics.Tracker({
analytics: true
}).track('foo');
new analytics.Tracker({ analytics: true }).track('foo');
});
it('does not track if analytics = false', function () {
@@ -96,10 +102,23 @@ describe('analytics', function () {
});
expect(function () {
new analytics.Tracker({
analytics: false
}).track('foo');
new analytics.Tracker({ analytics: false }).track('foo');
}).to.not.throwError();
});
it('tracks if analytics = undefined and setup returns true', function(next) {
var analytics = mockAnalytics({
track: function (arg) {
expect(arg).to.be('foo');
next();
}
});
analytics
.setup({ analytics: true })
.then(function () {
new analytics.Tracker({}).track('foo');
});
});
});
});