├── .gitignore ├── .jshintrc ├── .npmrc ├── .travis.yml ├── Gruntfile.js ├── History.md ├── README.md ├── bin └── set-auth-token-var-name.js ├── complexity.json ├── jshint.json ├── next-update-travis.sh ├── package.json ├── renovate.json └── src ├── form-auth-token.js ├── get-package.js ├── index.js ├── module-install-spec.js ├── module-install.js ├── npm-increment-version.js ├── npm-path.js ├── npm-prune-spec.js ├── npm-prune.js ├── npm-test.js ├── npm-version.js ├── pack.js ├── publish.js ├── repo-install.js ├── set-auth-token-spec.js ├── set-auth-token.js ├── test ├── form-auth-token.js ├── npm-pack.js ├── npm-path.js ├── npm-version.js ├── registry-url.js └── url.js └── url.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | cover/ 3 | test2.json 4 | test3.json 5 | npm-debug.log 6 | src/.DS_Store 7 | *.tgz 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "maxerr" : 50, 3 | 4 | "bitwise" : true, 5 | "camelcase" : false, 6 | "curly" : true, 7 | "eqeqeq" : true, 8 | "forin" : true, 9 | "immed" : false, 10 | "indent" : 2, 11 | "latedef" : false, 12 | "newcap" : true, 13 | "noarg" : true, 14 | "noempty" : true, 15 | "nonew" : false, 16 | "plusplus" : false, 17 | "quotmark" : "single", 18 | "undef" : true, 19 | "unused" : true, 20 | "strict" : false, 21 | "trailing" : false, 22 | "maxparams" : 4, 23 | "maxdepth" : 3, 24 | "maxstatements" : 30, 25 | "maxcomplexity" : 10, 26 | "maxlen" : 100, 27 | 28 | "asi" : false, 29 | "boss" : false, 30 | "debug" : false, 31 | "eqnull" : false, 32 | "es5" : false, 33 | "esnext" : false, 34 | "moz" : false, 35 | "evil" : false, 36 | "expr" : false, 37 | "funcscope" : false, 38 | "globalstrict" : false, 39 | "iterator" : false, 40 | "lastsemic" : false, 41 | "laxbreak" : false, 42 | "laxcomma" : false, 43 | "loopfunc" : false, 44 | "multistr" : false, 45 | "proto" : false, 46 | "scripturl" : false, 47 | "smarttabs" : false, 48 | "shadow" : false, 49 | "sub" : false, 50 | "supernew" : false, 51 | "validthis" : false, 52 | 53 | "browser" : false, 54 | "couch" : false, 55 | "devel" : true, 56 | "dojo" : false, 57 | "jquery" : false, 58 | "mootools" : false, 59 | "node" : true, 60 | "nonstandard" : false, 61 | "prototypejs" : false, 62 | "rhino" : false, 63 | "worker" : false, 64 | "wsh" : false, 65 | "yui" : false, 66 | 67 | "nomen" : false, 68 | "onevar" : false, 69 | "passfail" : false, 70 | "white" : true, 71 | 72 | "predef" : [] 73 | } 74 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=http://registry.npmjs.org/ 2 | save-exact=true 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | cache: 4 | directories: 5 | - node_modules 6 | notifications: 7 | email: true 8 | node_js: 9 | - '6' 10 | before_script: 11 | - npm prune 12 | script: 13 | - ./next-update-travis.sh 14 | - node . 15 | - npm test 16 | - node src/npm-test.js 17 | # a few "e2e" tests 18 | - node src/repo-install.js 19 | after_success: 20 | - npm run semantic-release 21 | - npm run coverage-codacy 22 | branches: 23 | except: 24 | - "/^v\\d+\\.\\d+\\.\\d+$/" 25 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function(grunt) { 3 | 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | 'nice-package': { 7 | all: { 8 | options: {} 9 | } 10 | }, 11 | filenames: { 12 | options: { 13 | valid: 'dashes' 14 | }, 15 | src: 'src/**/*.js' 16 | } 17 | }); 18 | 19 | var plugins = require('matchdep').filterDev('grunt-*'); 20 | plugins.forEach(grunt.loadNpmTasks); 21 | 22 | grunt.registerTask('default', ['nice-package', 'filenames']); 23 | }; 24 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.0.6 / 2013-10-31 3 | ================== 4 | 5 | * added method to get npm registry url 6 | * supporting check-types@1.1.0 7 | * bumped versions 8 | 9 | 0.0.5 / 2013-10-29 10 | ================== 11 | 12 | * upgraded all out of date dependencies 13 | 14 | 0.0.4 / 2013-10-29 15 | ================== 16 | 17 | * moved jshint settings from grunt to separate json file 18 | * using grunt-complexity, refactored gruntfile 19 | * added pre-git 20 | * added grunt 21 | * added repository url 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # npm-utils 2 | 3 | Async NPM shell commands: install, test, etc. 4 | 5 | [![NPM info][nodei.co]][npm-url] 6 | 7 | [![Build][npm-utils-ci-image]][npm-utils-ci-url] 8 | [![dependencies][dependencies-image]][dependencies-url] 9 | [![devDependencies][devDependencies-image]][devDependencies-url] 10 | 11 | [![Codacy Badge][codacy-image]][codacy-url] 12 | [![semantic-release][semantic-image] ][semantic-url] 13 | [![manpm](https://img.shields.io/badge/manpm-%E2%9C%93-3399ff.svg)](https://github.com/bahmutov/manpm) 14 | [![next-update-travis badge][badge]][readme] 15 | [![renovate-app badge][renovate-badge]][renovate-app] 16 | 17 | [renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg 18 | [renovate-app]: https://renovateapp.com/ 19 | 20 | ## Use 21 | 22 | ```js 23 | var npmUtils = require('npm-utils'); 24 | npmUtils.version() 25 | .then(function (semver) { 26 | console.log('NPM version %s', semver); 27 | }); 28 | ``` 29 | 30 | ## API 31 | 32 | ### NPM command path 33 | 34 | ```js 35 | path() // returns immediately path to npm command 36 | ``` 37 | 38 | ### Install 39 | 40 | ```js 41 | install({ 42 | name: string, 43 | version: string (optional), 44 | prefix: string (optional), // folder path prefix 45 | passThroughData: obj (optional), 46 | registry: string (optional) // registry url, 47 | flags: ['--save', '--verbose'] // list of command line flags to pass to NPM 48 | }) 49 | 50 | returns a promise 51 | ``` 52 | 53 | Note: the `name` could be another folder or a tar archive; passed 54 | to `npm install ` unchanged, that can be any match. 55 | See `npm help install`. 56 | 57 | Without `name` property, it just runs `npm install` in the current folder. 58 | 59 | ### repoInstall 60 | 61 | Clones Git repository for given NPM module and installs dependencies in the 62 | cloned folder. 63 | 64 | ```js 65 | repoInstall({ 66 | name: string, // NPM module name 67 | folder: string // destination new folder to create 68 | }) 69 | ``` 70 | 71 | Returns a promise 72 | 73 | ### Version 74 | 75 | ```js 76 | version() // returns a promise, resolved with NPM version string 77 | ``` 78 | 79 | ### Test 80 | 81 | ```js 82 | test() // spawns npm test command 83 | test('grunt test'); // spawns new command "grunt test" 84 | ``` 85 | 86 | The child test process will inherit output streams from the parent. 87 | 88 | ### registryUrl 89 | 90 | ```js 91 | registryUrl(); 92 | // returns a promise resolved with result of https://github.com/sindresorhus/registry-url 93 | // pass scope for specific registry 94 | registryUrl('@myCo') 95 | .then(url => ...) 96 | ``` 97 | 98 | ### publish 99 | 100 | ```js 101 | publish({ tag: '...'}); 102 | // the tag is optional 103 | ``` 104 | 105 | ### getPackage 106 | 107 | Loads `package.json` from a given folder 108 | 109 | ```js 110 | var pkg = npm.getPackage(folder); 111 | console.log('%s version %s', pkg.name, pkg.version); 112 | ``` 113 | 114 | ### pack 115 | 116 | Runs `npm pack ` command. Resolves with the name of the generated tarball file. 117 | 118 | ```js 119 | pack({ folder: 'path/to/folder' }) 120 | ``` 121 | 122 | If folder is not provided, uses the current one 123 | 124 | ### setAuthToken 125 | 126 | Please execute the `npm login` first! 127 | 128 | ```js 129 | setAuthToken() 130 | .then(canPublishNow, onError) 131 | ``` 132 | 133 | Updates local `.npmrc` (if found) or profile `~/.npmrc` file that can be used by CI 134 | servers to publish to NPM. 135 | The file will have the following line added (only the actual registry url will be used) 136 | 137 | //registry.npmjs.org/:_authToken=${NPM_TOKEN} 138 | 139 | Read the [Deploying with npm private modules][deploying post] for details, see 140 | project [ci-publish](https://github.com/bahmutov/ci-publish) for example how this could be 141 | used to release from CI after successful tests. 142 | 143 | [deploying post]: http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules 144 | 145 | Often the source of errors is that the environment does not have `NPM_TOKEN` set, 146 | or the `.npmrc` file already has the authToken entry for this registry. For example, 147 | when running locally 148 | 149 | $ NPM_TOKEN=foo node src/set-auth-token.js 150 | npmrc file already has auth token for registry 151 | //registry.npmjs.org/:_authToken= 152 | [Error: Auth token for registry exists //registry.npmjs.org/:_authToken=] 153 | 154 | ### increment or set package version 155 | 156 | Runs `npm version [major | minor | patch | version]` command. 157 | 158 | ```js 159 | incrementVersion({ 160 | increment: 'major|minor|patch|semver version', 161 | noGit: true // default false = Git commit happens 162 | }) 163 | // example 164 | incrementVersion({ 165 | increment: '2.0.1' 166 | }) 167 | ``` 168 | 169 | See `npm help version`. 170 | 171 | ### Prune dependencies 172 | 173 | ```js 174 | require('npm-utils').prune().catch(console.error); 175 | // same as "npm prune" 176 | ``` 177 | 178 | ## Bin commands 179 | 180 | ### Set auth token name 181 | 182 | Often the CI needs an auth token for a registry to be able to install private 183 | modules. The CI should have `NPM_TOKEN` environment variable set, and the 184 | next command adds the following to the `.npmrc` or `~/.npmrc` file 185 | 186 | ``` 187 | //registry.npmjs.org/:_authToken=${NPM_TOKEN} 188 | ``` 189 | 190 | You can use it like this. From the CI build file (`circle.yml`, `.travis.yml` 191 | etc) first install this package, then call the command, and then install 192 | all modules (including the private ones) 193 | 194 | ```sh 195 | npm i npm-utils 196 | $(npm bin)/set-auth-token-var-name 197 | npm i 198 | ``` 199 | 200 | ## Related 201 | 202 | * [ggit](https://github.com/bahmutov/ggit) - Git utils 203 | 204 | ## Troubleshooting 205 | 206 | Run the command with `DEBUG=npm-utils` environment variable set, this package 207 | uses [debug](https://www.npmjs.com/package/debug) 208 | 209 | ## Small print 210 | 211 | Author: Gleb Bahmutov @ 2013 @bahmutov 212 | 213 | License: MIT - do anything with the code, but don't blame me if it does not work. 214 | 215 | * [@bahmutov](https://twitter.com/bahmutov) 216 | * [glebbahmutov.com](http://glebbahmutov.com) 217 | * [blog](http://glebbahmutov.com/blog) 218 | 219 | [nodei.co]: https://nodei.co/npm/npm-utils.svg?downloads=true 220 | [npm-url]: https://npmjs.org/package/npm-utils 221 | [npm-utils-ci-image]: https://secure.travis-ci.org/bahmutov/npm-utils.svg?branch=master 222 | [npm-utils-ci-url]: https://travis-ci.org/bahmutov/npm-utils 223 | [dependencies-image]: https://david-dm.org/bahmutov/npm-utils.svg 224 | [dependencies-url]: https://david-dm.org/bahmutov/npm-utils 225 | [devDependencies-image]: https://david-dm.org/bahmutov/npm-utils/dev-status.svg 226 | [devDependencies-url]: https://david-dm.org/bahmutov/npm-utils#info=devDependencies 227 | [codacy-image]: https://api.codacy.com/project/badge/grade/80f4a9c1aad545fa8aeb090d66a3a7d2 228 | [codacy-url]: https://www.codacy.com/app/glebbahmutov_2600/npm-utils 229 | [semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg 230 | [semantic-url]: https://github.com/semantic-release/semantic-release 231 | [badge]: https://img.shields.io/badge/next--update--travis-%E2%9C%94%EF%B8%8F-green.svg 232 | [readme]: https://github.com/bahmutov/next-update-travis#readme 233 | -------------------------------------------------------------------------------- /bin/set-auth-token-var-name.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var envVarName = 'NPM_TOKEN'; 6 | if (!process.env[envVarName]) { 7 | console.error('Missing environment variable', envVarName); 8 | process.exit(-1); 9 | } 10 | 11 | var npmUtils = require('..'); 12 | npmUtils.setAuthToken() 13 | .then(function () { 14 | console.log('set .npmrc registry token to env variable', envVarName); 15 | }) 16 | .catch(function (err) { 17 | console.error(err); 18 | process.exit(-1); 19 | }); 20 | -------------------------------------------------------------------------------- /complexity.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": ["Gruntfile.js", "src/*.js"], 3 | "options": { 4 | "errorsOnly": false, 5 | "cyclomatic": 5, 6 | "halstead": 14, 7 | "maintainability": 100, 8 | "breakOnErrors": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /jshint.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "jshintrc": ".jshintrc" 4 | }, 5 | "default": { 6 | "src": [ "index.js", "src/*.js", "bin/*.js" ] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /next-update-travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then 6 | if [ "$GH_TOKEN" = "" ]; then 7 | echo "" 8 | echo "⛔️ Cannot find environment variable GH_TOKEN ⛔️" 9 | echo "Please set it up for this script to be able" 10 | echo "to push results to GitHub" 11 | echo "ℹ️ The best way is to use semantic-release to set it up" 12 | echo "" 13 | echo " https://github.com/semantic-release/semantic-release" 14 | echo "" 15 | echo "npm i -g semantic-release-cli" 16 | echo "semantic-release-cli setup" 17 | echo "" 18 | exit 1 19 | fi 20 | 21 | echo "Upgrading dependencies using next-update" 22 | npm i -g next-update 23 | 24 | # you can edit options to allow only some updates 25 | # --allow major | minor | patch 26 | # --latest true | false 27 | # see all options by installing next-update 28 | # and running next-update -h 29 | next-update --allow minor --latest false 30 | 31 | git status 32 | # if package.json is modified we have 33 | # new upgrades 34 | if git diff --name-only | grep package.json > /dev/null; then 35 | echo "There are new versions of dependencies 💪" 36 | git add package.json 37 | echo "----------- package.json diff -------------" 38 | git diff --staged 39 | echo "-------------------------------------------" 40 | git config --global user.email "next-update@ci.com" 41 | git config --global user.name "next-update" 42 | git commit -m "chore(deps): upgrade dependencies using next-update" 43 | # push back to GitHub using token 44 | git remote remove origin 45 | # TODO read origin from package.json 46 | # or use github api module github 47 | # like in https://github.com/semantic-release/semantic-release/blob/caribou/src/post.js 48 | git remote add origin https://next-update:$GH_TOKEN@github.com/bahmutov/npm-utils.git 49 | git push origin HEAD:master 50 | else 51 | echo "No new versions found ✋" 52 | fi 53 | else 54 | echo "Not a cron job, normal test" 55 | fi 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-utils", 3 | "description": "Async NPM shell commands", 4 | "version": "0.0.0-development", 5 | "author": "Gleb Bahmutov ", 6 | "bin": { 7 | "set-auth-token-var-name": "bin/set-auth-token-var-name.js" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/bahmutov/npm-utils/issues" 11 | }, 12 | "config": { 13 | "pre-git": { 14 | "commit-msg": "simple", 15 | "pre-commit": [ 16 | "npm run build", 17 | "npm test" 18 | ], 19 | "pre-push": [ 20 | "npm run size" 21 | ], 22 | "post-commit": [ 23 | "npm run exact-semver" 24 | ], 25 | "post-merge": [] 26 | } 27 | }, 28 | "contributors": [ 29 | "Jayson Harshbarger http://hypercubed.com/" 30 | ], 31 | "dependencies": { 32 | "chdir-promise": "0.6.2", 33 | "check-more-types": "2.24.0", 34 | "cross-spawn": "6.0.5", 35 | "debug": "3.2.7", 36 | "del": "3.0.0", 37 | "execa": "0.11.0", 38 | "ggit": "2.4.12", 39 | "lazy-ass": "1.6.0", 40 | "local-or-home-npmrc": "1.1.0", 41 | "q": "2.0.3", 42 | "registry-url": "3.1.0", 43 | "repo-url": "1.0.1", 44 | "verbal-expressions": "0.3.0" 45 | }, 46 | "devDependencies": { 47 | "codacy-coverage": "2.1.1", 48 | "exact-semver": "1.2.0", 49 | "git-issues": "1.3.1", 50 | "github-post-release": "1.13.1", 51 | "grunt": "0.4.5", 52 | "grunt-bump": "0.8.0", 53 | "grunt-cli": "1.4.3", 54 | "grunt-complexity": "0.4.0", 55 | "grunt-filenames": "0.4.0", 56 | "grunt-nice-package": "0.10.4", 57 | "gt": "0.10.0", 58 | "matchdep": "2.0.0", 59 | "mocha": "5.2.0", 60 | "next-update-travis": "1.7.1", 61 | "pkgfiles": "2.3.2", 62 | "pre-git": "3.17.1", 63 | "proxyquire": "2.1.3", 64 | "semantic-release": "6.3.6", 65 | "standard": "11.0.1", 66 | "temp": "0.9.4", 67 | "tmp-sync": "1.1.2" 68 | }, 69 | "engines": { 70 | "node": ">0.4.0" 71 | }, 72 | "files": [ 73 | "src/", 74 | "!src/test", 75 | "!src/*-spec.js", 76 | "bin" 77 | ], 78 | "homepage": "https://github.com/bahmutov/npm-utils", 79 | "keywords": [ 80 | "async", 81 | "command", 82 | "npm", 83 | "shell" 84 | ], 85 | "license": "MIT", 86 | "main": "src/index.js", 87 | "release": { 88 | "generateNotes": "github-post-release", 89 | "analyzeCommits": "simple-commit-message" 90 | }, 91 | "repository": { 92 | "type": "git", 93 | "url": "https://github.com/bahmutov/npm-utils.git" 94 | }, 95 | "scripts": { 96 | "build": "grunt", 97 | "commit": "git-issues && commit-wizard", 98 | "coverage-codacy": "cat cover/lcov.info | ./node_modules/.bin/codacy-coverage -v -d", 99 | "exact-semver": "exact-semver", 100 | "issues": "git-issues", 101 | "lint": "standard --verbose --fix src/*.js", 102 | "pkgfiles": "pkgfiles", 103 | "posttest": "npm run unit", 104 | "pretest": "npm run lint", 105 | "semantic-release": "semantic-release pre && npm publish && semantic-release post", 106 | "size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";", 107 | "test": "gt src/test/*.js --output", 108 | "unit": "mocha --timeout 30000 src/*-spec.js" 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["config:base"], 3 | "automerge": true, 4 | "major": { 5 | "automerge": false 6 | }, 7 | "excludePackageNames": ["grunt", "grunt-cli", "grunt-complexity"] 8 | } 9 | -------------------------------------------------------------------------------- /src/form-auth-token.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var la = require('lazy-ass') 4 | var is = require('check-more-types') 5 | var getNpmToken = 'https://www.npmjs.com/package/get-npm-token' 6 | 7 | // given registry url and token environment name returns 8 | // string to be placed into user's ~/.npmrc file 9 | // usually something like this //registry.npmjs.org/:_authToken=${NPM_TOKEN} 10 | function formAuthToken (registryUrl, tokenEnvName) { 11 | if (!tokenEnvName) { 12 | if (!process.env.NPM_TOKEN) { 13 | throw new Error('Cannot find NPM_TOKEN\nuse ' + getNpmToken + ' to get one') 14 | } 15 | tokenEnvName = 'NPM_TOKEN' 16 | } 17 | la(is.url(registryUrl), 'npm registry should be an url', registryUrl) 18 | 19 | // strip protocol http/https part 20 | registryUrl = registryUrl.replace('https:', '') 21 | registryUrl = registryUrl.replace('http:', '') 22 | 23 | var line = registryUrl + ':_authToken=' 24 | var fullLine = line + '${' + tokenEnvName + '}' 25 | 26 | return { 27 | test: line, 28 | token: fullLine 29 | } 30 | } 31 | 32 | module.exports = formAuthToken 33 | -------------------------------------------------------------------------------- /src/get-package.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var read = fs.readFileSync 3 | var join = require('path').join 4 | 5 | function getPackage (folder) { 6 | var filename = join(folder, 'package.json') 7 | if (!fs.existsSync(filename)) { 8 | throw new Error('Cannot find package file in folder ' + folder) 9 | } 10 | return JSON.parse(read(filename, 'utf-8')) 11 | } 12 | 13 | module.exports = getPackage 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var registryUrl = require('registry-url') 4 | 5 | function asyncRegistryUrl (scope) { 6 | /* global Promise */ 7 | return Promise.resolve(registryUrl(scope)) 8 | } 9 | 10 | module.exports = { 11 | install: require('./module-install'), 12 | repoInstall: require('./repo-install'), 13 | test: require('./npm-test'), 14 | path: require('./npm-path'), 15 | version: require('./npm-version'), 16 | isUrl: require('./url'), 17 | registryUrl: asyncRegistryUrl, 18 | publish: require('./publish'), 19 | pack: require('./pack'), 20 | getPackage: require('./get-package'), 21 | setAuthToken: require('./set-auth-token'), 22 | incrementVersion: require('./npm-increment-version'), 23 | prune: require('./npm-prune') 24 | } 25 | -------------------------------------------------------------------------------- /src/module-install-spec.js: -------------------------------------------------------------------------------- 1 | const la = require('lazy-ass') 2 | const is = require('check-more-types') 3 | 4 | /* global describe, it */ 5 | describe('module install', () => { 6 | const install = require('./module-install') 7 | // const path = require('path') 8 | 9 | it('is a function', () => { 10 | la(is.fn(install)) 11 | }) 12 | 13 | // it('install into tmp folder', function () { 14 | // gt.func(install, 'install is a function'); 15 | // var options = { 16 | // name: 'lodash', 17 | // prefix: '/tmp/lodash-prefix/', 18 | // registry: 'http://registry.npmjs.org/' 19 | // }; 20 | // install(options).then(function () { 21 | // return path.join(options.prefix, '/lib/node_modules/' + options.name); 22 | // }) 23 | // .finally(gt.start) 24 | // .done(); 25 | // }); 26 | 27 | // gt.async('passes command line flags', function () { 28 | // var options = { 29 | // name: 'lodash', 30 | // prefix: '/tmp/lodash-prefix/', 31 | // registry: 'http://registry.npmjs.org/', 32 | // flags: ['--verbose'] 33 | // }; 34 | // install(options).then(function () { 35 | // return path.join(options.prefix, '/lib/node_modules/' + options.name); 36 | // }) 37 | // .finally(gt.start) 38 | // .done(); 39 | // }); 40 | }) 41 | -------------------------------------------------------------------------------- /src/module-install.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var la = require('lazy-ass') 4 | var check = require('check-more-types') 5 | var spawn = require('child_process').spawn 6 | var q = require('q') 7 | var NPM_PATH = require('./npm-path') 8 | var debug = require('debug')('npm-utils') 9 | 10 | function promiseToRun (args, passThroughData) { 11 | check.verify.array(args, 'expected arguments') 12 | debug('module install with args:', args) 13 | 14 | var npm = spawn(NPM_PATH, args) 15 | var errors = '' 16 | 17 | npm.stdout.setEncoding('utf-8') 18 | npm.stderr.setEncoding('utf-8') 19 | 20 | npm.stdout.on('data', function (data) { 21 | process.stdout.write(data) 22 | }) 23 | 24 | npm.stderr.on('data', function (data) { 25 | errors += data 26 | process.stderr.write(data) 27 | }) 28 | 29 | npm.on('error', function (err) { 30 | console.error(err) 31 | errors += err.toString() 32 | }) 33 | 34 | var deferred = q.defer() 35 | npm.on('exit', function (code) { 36 | if (code) { 37 | console.error('npm returned', code) 38 | console.error('errors:\n' + errors) 39 | deferred.reject({ 40 | code: code, 41 | errors: errors 42 | }) 43 | } else { 44 | deferred.resolve(passThroughData) 45 | } 46 | }) 47 | return deferred.promise 48 | } 49 | 50 | function formArguments (opts, name, moduleVersion) { 51 | var args = ['install'] 52 | if (opts.prefix) { 53 | check.verify.string(name, 'expected module name string') 54 | check.verify.string(opts.prefix, 55 | 'install folder prefix should be a string, not ' + opts.prefix) 56 | args.push('-g') 57 | args.push('--prefix') 58 | args.push(opts.prefix) 59 | } 60 | if (opts.registry) { 61 | la(check.string(opts.registry), 'expected registry url string', opts) 62 | args.push('--registry') 63 | args.push(opts.registry) 64 | } 65 | if (moduleVersion) { 66 | args.push(moduleVersion) 67 | } 68 | if (check.array(opts.flags)) { 69 | args = args.concat(opts.flags) 70 | } 71 | return args 72 | } 73 | 74 | function promiseToInstall (opts) { 75 | opts = opts || {} 76 | var name = opts.name 77 | var moduleVersion = name 78 | if (name) { 79 | check.verify.string(name, 'expected module name string') 80 | if (opts.version) { 81 | check.verify.string(opts.version, 'expected version string') 82 | moduleVersion = moduleVersion + '@' + opts.version 83 | } 84 | console.log(' installing', moduleVersion) 85 | } else { 86 | console.log(' NPM install in current folder') 87 | } 88 | 89 | var args = formArguments(opts, name, moduleVersion) 90 | return promiseToRun(args, opts.passThroughData) 91 | } 92 | 93 | module.exports = promiseToInstall 94 | -------------------------------------------------------------------------------- /src/npm-increment-version.js: -------------------------------------------------------------------------------- 1 | var la = require('lazy-ass') 2 | var is = require('check-more-types') 3 | var run = require('./npm-test') 4 | var debug = require('debug')('npm-utils') 5 | 6 | var isIncrement = is.oneOf(['major', 'minor', 'patch']) 7 | 8 | function npmVersion (opts) { 9 | la(is.object(opts), 'missing options') 10 | la(isIncrement(opts.increment) || 11 | is.semver(opts.increment), 'invalid increment or version', opts) 12 | 13 | var cmd = 'npm version ' + opts.increment 14 | if (opts.noGit) { 15 | cmd += ' --no-git-tag-version' 16 | } 17 | debug('npm version command "%s"', cmd) 18 | return run(cmd) 19 | } 20 | 21 | module.exports = npmVersion 22 | 23 | if (!module.parent) { 24 | npmVersion({ increment: 'patch', noGit: true }) 25 | .catch(console.error.bind(console)) 26 | } 27 | -------------------------------------------------------------------------------- /src/npm-path.js: -------------------------------------------------------------------------------- 1 | // hack to find npm bin script reliably 2 | function findNpmPath () { 3 | var os = require('os') 4 | var type = os.type() 5 | return (/windows/gi).test(type) ? 'npm.cmd' : 'npm' 6 | } 7 | 8 | module.exports = findNpmPath() 9 | -------------------------------------------------------------------------------- /src/npm-prune-spec.js: -------------------------------------------------------------------------------- 1 | const la = require('lazy-ass') 2 | const is = require('check-more-types') 3 | const tmp = require('tmp-sync') 4 | const chdir = require('chdir-promise') 5 | const execa = require('execa') 6 | 7 | /* global describe, it */ 8 | describe('npm prune', () => { 9 | const prune = require('./npm-prune') 10 | 11 | it('is a function', () => { 12 | la(is.fn(install)) 13 | }) 14 | 15 | const hasExtraneous = text => { 16 | return text.indexOf('extraneous') !== -1 17 | } 18 | 19 | const expectExtraneous = () => { 20 | console.log('npm ls') 21 | return execa.shell('npm ls || true') 22 | .then(result => result.stdout) 23 | .then(stdout => { 24 | console.log(stdout) 25 | la(hasExtraneous(stdout), 'debug should be extraneous', stdout) 26 | }) 27 | } 28 | 29 | const expectNoExtraneous = () => { 30 | console.log('npm ls') 31 | return execa.shell('npm ls') 32 | .then(result => result.stdout) 33 | .then(stdout => { 34 | console.log(stdout) 35 | }) 36 | } 37 | 38 | const initPackage = () => { 39 | console.log('making new package') 40 | return execa.shell('npm init -y') 41 | } 42 | 43 | const install = name => { 44 | console.log('installing %s without saving', name) 45 | return execa.shell(`npm install ${name} --no-save`) 46 | } 47 | 48 | it('prunes in the temp folder', () => { 49 | const folder = tmp.in() 50 | console.log('prune test in folder', folder) 51 | return chdir.to(folder) 52 | .then(initPackage) 53 | .then(() => install('debug')) 54 | .then(expectExtraneous) 55 | .then(() => { 56 | console.log('npm prune') 57 | return prune() 58 | }) 59 | .then(expectNoExtraneous) 60 | .then(chdir.back) 61 | }) 62 | }) 63 | -------------------------------------------------------------------------------- /src/npm-prune.js: -------------------------------------------------------------------------------- 1 | var la = require('lazy-ass') 2 | var check = require('check-more-types') 3 | var spawn = require('child_process').spawn 4 | var q = require('q') 5 | var NPM_PATH = require('./npm-path') 6 | 7 | // returns a promise 8 | function prune () { 9 | console.log(' npm prune') 10 | la(check.string(NPM_PATH), 'missing npm path string') 11 | 12 | var npm = spawn(NPM_PATH, ['prune']) 13 | var output = '' 14 | var errors = '' 15 | 16 | npm.stdout.setEncoding('utf-8') 17 | npm.stderr.setEncoding('utf-8') 18 | 19 | npm.stdout.on('data', function (data) { 20 | output += data 21 | }) 22 | 23 | npm.stderr.on('data', function (data) { 24 | errors += data 25 | }) 26 | 27 | npm.on('error', function (err) { 28 | console.error(err) 29 | errors += err.toString() 30 | }) 31 | 32 | var deferred = q.defer() 33 | npm.on('exit', function (code) { 34 | if (code) { 35 | console.error('npm prune returned', code) 36 | console.error('errors:\n' + errors) 37 | deferred.reject({ 38 | code: code, 39 | errors: errors 40 | }) 41 | } 42 | deferred.resolve(output) 43 | }) 44 | return deferred.promise 45 | } 46 | 47 | module.exports = prune 48 | -------------------------------------------------------------------------------- /src/npm-test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var la = require('lazy-ass') 4 | var check = require('check-more-types') 5 | var spawn = require('cross-spawn') 6 | var q = require('q') 7 | var NPM_PATH = require('./npm-path') 8 | var debug = require('debug')('npm-utils') 9 | 10 | function testRunner (app, parts) { 11 | la(check.unemptyString(app), 'missing app to run', app) 12 | la(check.array(parts), 'missing arguments array', parts) 13 | var npm = spawn(app, parts, { stdio: 'inherit' }) 14 | var testErrors = '' 15 | 16 | npm.on('error', function (err) { 17 | console.error(err) 18 | testErrors += err.toString() 19 | }) 20 | 21 | var deferred = q.defer() 22 | npm.on('exit', function (code) { 23 | if (code) { 24 | var defaultMessage = 'Could not execute ' + app + ' ' + parts.join(' ') 25 | deferred.reject({ 26 | code: code, 27 | errors: testErrors || defaultMessage 28 | }) 29 | return 30 | } 31 | deferred.resolve() 32 | }) 33 | return deferred.promise 34 | } 35 | 36 | // returns a promise 37 | function test (cmd) { 38 | var app = NPM_PATH 39 | var parts = ['test'] 40 | la(check.string(NPM_PATH), 'missing npm path string') 41 | 42 | if (check.unemptyString(cmd)) { 43 | cmd = cmd.trim() 44 | parts = cmd.split(' ') 45 | app = parts.shift() 46 | } 47 | 48 | debug('spawning test process', app, parts) 49 | la(check.unemptyString(app), 'application name should be a string', app) 50 | la(check.arrayOfStrings(parts), 'arguments should be an array', parts) 51 | 52 | return testRunner(app, parts) 53 | } 54 | 55 | module.exports = test 56 | 57 | if (!module.parent) { 58 | test() 59 | .done() 60 | } 61 | -------------------------------------------------------------------------------- /src/npm-version.js: -------------------------------------------------------------------------------- 1 | var la = require('lazy-ass') 2 | var check = require('check-more-types') 3 | var spawn = require('child_process').spawn 4 | var q = require('q') 5 | var NPM_PATH = require('./npm-path') 6 | 7 | // returns a promise 8 | function version () { 9 | console.log(' npm version') 10 | la(check.string(NPM_PATH), 'missing npm path string') 11 | 12 | var npm = spawn(NPM_PATH, ['--version']) 13 | var output = '' 14 | var errors = '' 15 | 16 | npm.stdout.setEncoding('utf-8') 17 | npm.stderr.setEncoding('utf-8') 18 | 19 | npm.stdout.on('data', function (data) { 20 | output += data 21 | }) 22 | 23 | npm.stderr.on('data', function (data) { 24 | errors += data 25 | }) 26 | 27 | npm.on('error', function (err) { 28 | console.error(err) 29 | errors += err.toString() 30 | }) 31 | 32 | var deferred = q.defer() 33 | npm.on('exit', function (code) { 34 | if (code) { 35 | console.error('npm version returned', code) 36 | console.error('errors:\n' + errors) 37 | deferred.reject({ 38 | code: code, 39 | errors: errors 40 | }) 41 | } 42 | la(check.string(output), 'could not get npm version') 43 | deferred.resolve(output) 44 | }) 45 | return deferred.promise 46 | } 47 | 48 | module.exports = version 49 | -------------------------------------------------------------------------------- /src/pack.js: -------------------------------------------------------------------------------- 1 | var la = require('lazy-ass') 2 | var is = require('check-more-types') 3 | var fs = require('fs') 4 | var Q = require('q') 5 | var run = require('./npm-test') 6 | la(is.fn(run), 'expected run function') 7 | var getPackage = require('./get-package') 8 | 9 | // NPM pack generates file in the format 10 | // -.tgz 11 | function formTarballName (pkg) { 12 | return pkg.name + '-' + pkg.version + '.tgz' 13 | } 14 | 15 | function pack (options) { 16 | options = options || {} 17 | if (is.string(options)) { 18 | options = { folder: options } 19 | } 20 | la(is.object(options), 'expected options object for pack', options) 21 | 22 | var folder = options.folder ? options.folder : '.' 23 | var pkg = getPackage(folder) 24 | la(is.unemptyString(pkg.name) && 25 | is.unemptyString(pkg.version), 'invalid package in folder', folder) 26 | 27 | var command = 'npm pack ' + folder 28 | return run(command) 29 | .then(function () { 30 | // find the generated file in the current folder 31 | var filename = formTarballName(pkg) 32 | if (!fs.existsSync(filename)) { 33 | return Q.reject(new Error('Cannot find tar file ' + filename)) 34 | } 35 | return filename 36 | }) 37 | } 38 | 39 | module.exports = pack 40 | 41 | if (!module.parent) { 42 | console.log('running a test - packing current folder') 43 | pack() 44 | .then(function (filename) { 45 | console.log('packing produced file', filename) 46 | }) 47 | .catch(console.error.bind(console)) 48 | .done() 49 | } 50 | -------------------------------------------------------------------------------- /src/publish.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var la = require('lazy-ass') 4 | var is = require('check-more-types') 5 | var run = require('./npm-test') 6 | var debug = require('debug')('npm-utils') 7 | var q = require('q') 8 | 9 | la(is.fn(run), 'expected function') 10 | 11 | function publish (options) { 12 | options = options || {} 13 | var command = 'npm publish' 14 | if (is.unemptyString(options.tag)) { 15 | debug('publishing with a tag', options.tag) 16 | command += ' --tag ' + options.tag 17 | } 18 | 19 | if (is.unemptyString(options.access)) { 20 | debug('publishing with specific access', options.access) 21 | command += ' --access ' + options.access 22 | } 23 | 24 | return run(command) 25 | .catch(function (info) { 26 | debug('publishing hit an error') 27 | debug(info) 28 | la(is.string(info.testErrors), 'missing test errors string', info) 29 | return q.reject(new Error(info.testErrors)) 30 | }) 31 | } 32 | 33 | module.exports = publish 34 | 35 | if (!module.parent) { 36 | console.log('running a test - publishing under tag example') 37 | publish({ tag: 'example' }) 38 | .catch(console.error.bind(console)) 39 | .done() 40 | } 41 | -------------------------------------------------------------------------------- /src/repo-install.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const la = require('lazy-ass') 4 | const is = require('check-more-types') 5 | const repoUrl = require('repo-url') 6 | const npmInstall = require('./module-install') 7 | const ggit = require('ggit') 8 | const del = require('del') 9 | const chdir = require('chdir-promise') 10 | 11 | // to grab repo url for a package uses 12 | // https://github.com/juliangruber/repo-url 13 | function moduleRepo (name) { 14 | return new Promise(function (resolve, reject) { 15 | repoUrl(name, function (err, url) { 16 | if (err) { 17 | return reject(err) 18 | } 19 | resolve(url) 20 | }) 21 | }) 22 | } 23 | 24 | function cloneRepo (folder) { 25 | return function cloneUrl (url) { 26 | la(is.unemptyString(url), 'missing repo url', url) 27 | console.log('cloning url', url) 28 | console.log('into', folder) 29 | return ggit.cloneRepo({ 30 | url: url, 31 | folder: folder 32 | }) 33 | } 34 | } 35 | 36 | function repoInstall (opts) { 37 | la(opts && opts.name, 'missing NPM module name', opts) 38 | la(is.unemptyString(opts.folder), 'missing destination folder', opts) 39 | 40 | return moduleRepo(opts.name) 41 | .then(cloneRepo(opts.folder)) 42 | .then(chdir.to.bind(null, opts.folder)) 43 | .then(npmInstall) 44 | .then(chdir.back) 45 | } 46 | 47 | module.exports = repoInstall 48 | 49 | if (!module.parent) { 50 | const folder = '/tmp/test-repo-install' 51 | const options = { 52 | name: 'lazy-ass', 53 | folder: folder 54 | } 55 | del.sync(folder, {force: true}) 56 | repoInstall(options) 57 | .then(function () { 58 | console.log('install repo for module') 59 | }, function (err) { 60 | console.error('could not install repo') 61 | console.error(err) 62 | }) 63 | } 64 | -------------------------------------------------------------------------------- /src/set-auth-token-spec.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var proxyquire = require('proxyquire') 4 | var temp = require('temp') 5 | const chdir = require('chdir-promise') 6 | const la = require('lazy-ass') 7 | 8 | temp.track() 9 | 10 | var npmToken 11 | 12 | /* global describe, beforeEach, it, afterEach */ 13 | describe('set auth token', () => { 14 | let setAuthToken 15 | let dirPath 16 | 17 | beforeEach((done) => { 18 | temp.mkdir('npm-utils', function (err, tempFolder) { 19 | if (err) { 20 | throw err 21 | } 22 | dirPath = tempFolder 23 | console.log('temp folder', dirPath) 24 | 25 | setAuthToken = proxyquire('./set-auth-token', { 26 | 'user-home': dirPath 27 | }) 28 | console.log(setAuthToken) 29 | 30 | npmToken = process.env.NPM_TOKEN 31 | process.env.NPM_TOKEN = '1234' 32 | 33 | chdir.to(dirPath).then(() => { 34 | console.log('current folder', process.cwd()) 35 | done() 36 | }) 37 | }) 38 | }) 39 | 40 | afterEach((done) => { 41 | process.env.NPM_TOKEN = npmToken 42 | chdir.back().then(() => done()) 43 | }) 44 | 45 | it('sets the authentication token on default registry', function () { 46 | var customRegistry = 'https://npm.example.com/' 47 | var npmrcPath = path.join(dirPath, '.npmrc') 48 | var packagePath = path.join(dirPath, 'package.json') 49 | 50 | fs.writeFileSync(npmrcPath, '@myco:registry=' + customRegistry, { encoding: 'utf8' }) 51 | fs.writeFileSync(packagePath, '{ "name": "@myco/test-package" }', { encoding: 'utf8' }) 52 | 53 | return setAuthToken() 54 | .then(function () { 55 | var npmrcContents = fs.readFileSync(npmrcPath, 'utf8') 56 | console.log(npmrcContents) 57 | la(npmrcContents.includes('//npm.example.com/:_authToken=')) 58 | }) 59 | }) 60 | 61 | it('sets the authentication token based on publishConfig URL', function () { 62 | var customRegistry = 'https://npm.example.com/' 63 | var npmrcPath = path.join(dirPath, '.npmrc') 64 | var packagePath = path.join(dirPath, 'package.json') 65 | 66 | fs.writeFileSync(npmrcPath, '@myco:registry=' + customRegistry, { encoding: 'utf8' }) 67 | fs.writeFileSync(packagePath, '{ "name": "@myco/test-package", "publishConfig": { "registry": "https://private.example.com/" } }', { encoding: 'utf8' }) 68 | 69 | return setAuthToken() 70 | .then(function () { 71 | var npmrcContents = fs.readFileSync(npmrcPath, 'utf8') 72 | console.log(npmrcContents) 73 | la(npmrcContents.includes('//private.example.com/:_authToken=')) 74 | }) 75 | }) 76 | }) 77 | 78 | -------------------------------------------------------------------------------- /src/set-auth-token.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var registryUrl = require('registry-url') 4 | var fs = require('fs') 5 | var q = require('q') 6 | var formUrlToken = require('./form-auth-token') 7 | var getPackage = require('./get-package') 8 | var localOrHomeNpmrc = require('local-or-home-npmrc') 9 | var debug = require('debug')('npm-utils') 10 | 11 | function updateNpmrc (data) { 12 | var contents = '' 13 | 14 | var npmrcFile = localOrHomeNpmrc() 15 | if (fs.existsSync(npmrcFile)) { 16 | debug('using file:', npmrcFile) 17 | contents = fs.readFileSync(npmrcFile, 'utf-8') 18 | contents = contents.trim() + '\n' 19 | } 20 | if (contents.indexOf(data.token) !== -1) { 21 | console.log('npmrc file already has contents to add, skipping') 22 | return 23 | } 24 | if (contents.indexOf(data.test) !== -1) { 25 | console.error('npmrc file already has auth token for registry') 26 | console.error(data.test) 27 | throw new Error('Auth token for registry exists ' + data.test) 28 | } 29 | contents += data.token + '\n' 30 | fs.writeFileSync(npmrcFile, contents, 'utf-8') 31 | console.log('saved', npmrcFile) 32 | } 33 | 34 | function setAuthToken () { 35 | var deferred = q.defer() 36 | 37 | var cwd = process.cwd() 38 | var packageContents = getPackage(cwd) 39 | var packageName = packageContents.name 40 | debug('package %s in folder %s', packageName, cwd) 41 | 42 | // If set, prefer the value of the `packageConfig.registry` property over the value of the registry as set 43 | // in the user's `.npmrc` file. 44 | // In one scenario, a package may fetch its dependencies from a virtual registry that is an overlay of a private 45 | // registry over the public npm registry. Yet, that package is configured to publish directly to the private registry 46 | // URL. To account for this scenario we need to get the value of the private registry URL and configure it within 47 | // the `.npmrc` file. 48 | var registry 49 | if (packageContents.publishConfig && packageContents.publishConfig.registry) { 50 | registry = packageContents.publishConfig.registry 51 | } else { 52 | var scope = packageName.split('/')[0] 53 | registry = registryUrl(scope) 54 | } 55 | 56 | console.log('setting auth token for registry', registry) 57 | 58 | var data = formUrlToken(registry) 59 | updateNpmrc(data) 60 | 61 | deferred.resolve() 62 | return deferred.promise 63 | } 64 | 65 | module.exports = setAuthToken 66 | 67 | if (!module.parent) { 68 | setAuthToken() 69 | .catch(console.error.bind(console)) 70 | } 71 | -------------------------------------------------------------------------------- /src/test/form-auth-token.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var la = require('lazy-ass'); 4 | var is = require('check-more-types'); 5 | 6 | gt.module('form aut token'); 7 | 8 | var form = require('../form-auth-token'); 9 | 10 | gt.test('handles http url', function () { 11 | var registryUrl = 'http://registry.npmjs.org/'; 12 | var result = form(registryUrl, 'FOO'); 13 | la(is.object(result), result); 14 | la(is.unemptyString(result.token), result); 15 | var str = result.token; 16 | la(/FOO/.test(str), str); 17 | la(!/http:/.test(str), 'should not have http part', str); 18 | }); 19 | 20 | gt.test('handles https url', function () { 21 | var registryUrl = 'https://registry.npmjs.org/'; 22 | var result = form(registryUrl, 'FOO'); 23 | la(is.object(result), result); 24 | la(is.unemptyString(result.token), result); 25 | 26 | var str = result.token; 27 | la(/FOO/.test(str), str); 28 | la(!/https:/.test(str), 'should not have https part', str); 29 | }); 30 | 31 | gt.test('handles https url', function () { 32 | var registryUrl = 'https://registry.npmjs.org/'; 33 | var result = form(registryUrl, 'FOO'); 34 | la(is.object(result), result); 35 | la(is.unemptyString(result.token), result); 36 | 37 | var str = result.token; 38 | la(/FOO/.test(str), str); 39 | la(!/https:/.test(str), 'should not have https part', str); 40 | }); 41 | 42 | gt.test('starts with registry', function () { 43 | var registryUrl = 'https://registry.npmjs.org/'; 44 | var result = form(registryUrl, 'FOO'); 45 | var str = result.token; 46 | la(str.indexOf('//registry.npmjs') === 0, 47 | 'should start with registry', str); 48 | }); 49 | -------------------------------------------------------------------------------- /src/test/npm-pack.js: -------------------------------------------------------------------------------- 1 | gt.module('npm pack'); 2 | var pack = require('../pack'); 3 | var fs = require('fs'); 4 | 5 | gt.async('pack folder', function () { 6 | gt.func(pack, 'install is a function'); 7 | var folder = __dirname + '/../..'; 8 | pack(folder).then(function (filename) { 9 | gt.string(filename, 'expected tar filename'); 10 | gt.ok(fs.existsSync(filename), 'cannot find file ' + filename); 11 | fs.unlinkSync(filename); 12 | }) 13 | .finally(gt.start) 14 | .done(); 15 | }); 16 | -------------------------------------------------------------------------------- /src/test/npm-path.js: -------------------------------------------------------------------------------- 1 | gt.module('npm-path'); 2 | 3 | gt.test('npm path', function () { 4 | var npmPath = require('../npm-path'); 5 | console.log('npm path', npmPath); 6 | gt.string(npmPath, 'returns a string'); 7 | gt.ok(npmPath.length > 0, 'non empty string'); 8 | }); -------------------------------------------------------------------------------- /src/test/npm-version.js: -------------------------------------------------------------------------------- 1 | gt.module('npm version'); 2 | 3 | var version = require('../npm-version'); 4 | 5 | gt.asyncTest('getting npm version', 1, function () { 6 | var promise = version(); 7 | promise.then(function (ver) { 8 | gt.string(ver, 'got npm version'); 9 | console.log('npm version:', ver); 10 | }, function (err) { 11 | gt.ok(false, 'could not get npm version', err); 12 | }).done(gt.start); 13 | }); 14 | -------------------------------------------------------------------------------- /src/test/registry-url.js: -------------------------------------------------------------------------------- 1 | var check = require('check-more-types'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var registryUrl = require('registry-url'); 5 | var temp = require('temp'); 6 | 7 | temp.track(); 8 | 9 | gt.module('registry-url'); 10 | 11 | gt.async('registry-url returns a URL from .npmrc file', function () { 12 | temp.mkdir('npm-utils', function(err, dirPath) { 13 | var customRegistry = 'https://npm.example.com/'; 14 | 15 | var originalDir = process.cwd(); 16 | process.chdir(dirPath); 17 | 18 | var npmrcPath = path.join(dirPath, '.npmrc'); 19 | fs.writeFile(npmrcPath, 'registry=' + customRegistry, function () { 20 | var url = registryUrl(); 21 | 22 | gt.ok(check.webUrl(url), 'registry url is a url', url); 23 | gt.ok(check.same(url, customRegistry), 'registry url is same as .npmrc file', url); 24 | 25 | process.chdir(originalDir); 26 | gt.start(); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/test/url.js: -------------------------------------------------------------------------------- 1 | gt.module('isUrl'); 2 | 3 | var isUrl = require('../url'); 4 | 5 | gt.test('basics', function () { 6 | gt.arity(isUrl, 1); 7 | }); 8 | 9 | gt.test('isUrl positive', function () { 10 | var urls = [ 11 | 'https://github.com/bahmutov/qunit-promises.git#0.0.7', 12 | 'git://github.com/bahmutov/qunit-promises.git', 13 | 'http://github.com/bahmutov/qunit-promises.git#latest' 14 | ]; 15 | urls.forEach(function (url) { 16 | gt.ok(isUrl(url), url); 17 | }); 18 | }); 19 | 20 | gt.test('isUrl negative', function () { 21 | var notUrls = ['latest', '0.1.0', '*', '~0.2.1']; 22 | notUrls.forEach(function (notUrl) { 23 | gt.ok(!isUrl(notUrl), notUrl); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/url.js: -------------------------------------------------------------------------------- 1 | var la = require('lazy-ass') 2 | var VerEx = require('verbal-expressions') 3 | var check = require('check-more-types') 4 | 5 | var httpTester = new VerEx() 6 | .startOfLine() 7 | .then('http') 8 | .maybe('s') 9 | .then('://') 10 | .anythingBut(' ') 11 | .endOfLine() 12 | 13 | var gitTester = new VerEx() 14 | .startOfLine() 15 | .then('git') 16 | .then('://') 17 | .anythingBut(' ') 18 | .endOfLine() 19 | 20 | function isUrl (str) { 21 | la(check.string(str), 'expected a string') 22 | return httpTester.test(str) || gitTester.test(str) 23 | } 24 | 25 | module.exports = isUrl 26 | --------------------------------------------------------------------------------