GithubHelp home page GithubHelp logo

bahmutov / dont-break Goto Github PK

View Code? Open in Web Editor NEW
206.0 5.0 18.0 148 KB

Checks if the current version of your package would break dependent projects

JavaScript 87.70% Shell 12.30%
npm ci dependency semantic-release plugin

dont-break's Introduction

dont-break

Checks if the node module in the current folder breaks unit tests for specified dependent projects.

Relevant discussion at npm, Do not break dependant modules.

Build status npm semantic-release next-update-travis badge

Install

npm install -g dont-break

Use

  • Create .dont-break.json file in the root of your package, list module names that you would like to test as an array.
  • Run dont-break any time to test latest version of each dependent module against the curent code

Example

2 projects.

  1. First project foo only exports single variable module.exports = 'foo';
  2. Second project foo-user depends on foo.

foo-user only works if it gets string foo from the module it depends on, like this:

var str = require('foo');
console.assert(str === 'foo', 'value of foo should be "foo", but is ' + str);

foo has only a single release 0.1.0 that works for foo-user project.

The author of foo changes code to be module.exports = 'bar'; and releases it as 0.2.0. foo-user wants to use the latest foo so it updates its dependency, not expecting anything bad - foo's minor version number has been upgraded. In semantic versioning it means no breaking API changes.

foo-user is now broken!

Instead, before publishing new version to NPM, project foo can create a file in its project folder .dont-break.json with names of dependent projects to test

echo '["foo-user"]' > .dont-break.json

You can check if the current code breaks listed dependent project by running

dont-break

This will install each dependent project from .dont-break.json file into /tmp/dont-break... folder, will run the dependent's unit tests using npm test to make sure they work initially, then will copy the current project into the temp folder, overwriting the previous working version. Then it will run the tests again, throwing an exception if they stopped working.

In the example case, it will report something like this

$ dont-break
dependents [ 'foo-user' ]
testing foo-user
  installing foo-user
installed into /tmp/[email protected]
  npm test
tests work in /tmp/[email protected]/lib/node_modules/foo-user
copied /Users/gleb/git/foo/* to /tmp/[email protected]/lib/node_modules/foo-user/node_modules/foo
  npm test
npm test returned 1
test errors:
AssertionError: value of foo should be "foo", but is bar
npm ERR! Test failed.  See above for more details.
npm ERR! not ok code 0
tests did not work in /tmp/[email protected]/lib/node_modules/foo-user
code 1
FAIL: Current version break dependents

The message clearly tells you that the dependent projects as they are right now cannot upgrade to the version you are about to release.

Dependencies

You can specify GitHub repos as dependencies, because they most likely will have tests. For example in .dont-break.json

// you can use JavaScript comments in this file .dont-break.json
[
  "https://github.com/bahmutov/dont-break-bar"
]

Picking projects to test manually is a judgement call. Dont-break can fetch top N most downloaded or most starred dependent modules and save the list.

  • run dont-break --top-downloads <N> to find top N most downloaded dependent modules, save to .dont-break.json and check.
  • run dont-break --top-starred <N> to find top N most starred dependent modules, save to .dont-break.json and check.

The above commands overwrite .dont-break.json file.

Configuration options

Global vs. project-level configuration

You can specify different configuration options on global level or on project level. Following configs are equivalent. Project level:

[
  {
    "name": "project-a",
    "test": "grunt test"
  },
  {
    "name": "https://github.com/bahmutov/dont-break-bar",
    "test": "grunt test"
  },
  {
    "name": "project-c",
    "test": "npm test:special"
  }
]

Global level:

{
  "test": "grunt test",
  "projects": [
    "project-a", 
    "https://github.com/bahmutov/dont-break-bar", 
    {
      "name": "project-c",
      "test": "npm test:special"
    }
  ]
}

Global level will simplify dont-break config if dependent projects share the same options. Also, options can be overriden on project level as in case of "project-c" here.

Execution flow overview

Dont-break performs folowing steps for each dependent project:

Sections below describe how you can customize these steps.

Name

Serves to identify the dependent module by either a NPM module name (possibly with scope and version range) or Github URL.

[
  {
    "name": "foo-module-name"
  }, {
    "name": "@my-scope/bar-module-name@^1.0.1-pre.1"
  }, {
    "name": "https://github.com/bahmutov/dont-break-bar"
  }
]

The above config is equivalent to its shorter version:

[
  "foo-module-name", "@my-scope/bar-module-name@^1.0.1-pre.1", "https://github.com/bahmutov/dont-break-bar"
]

Test command

You can specify a custom test command per dependent module. For example, to run grunt test for foo-module-name, but default command for module bar-name, list in .dont-break.json the following:

[
  {
    "name": "foo-module-name",
    "test": "grunt test"
  },
  "bar-name"
]

Install command

You can specify a custom install command per dependent module. By default it's npm install. For example, this will use yarn add for foo-module-name, but keep default npm install for module bar-name:

[
  {
    "name": "foo-module-name",
    "install": "yarn add"
  },
  "bar-name"
]

The name of dependent module will be added to given command, e.g. for above it will run yarn add foo-module-name.

Post-install command

Before testing the dependent package dont-break installs its dev dependencies via npm install command run from the dependency directory. If you need something more you can specify it via "postinstall" config parameter like this:

[
  {
    "name": "packageA",
    "postinstall": "npm run update"
  }, {
    "name": "packageB"
  }
]

If specified this command will run first before pretesting the old version of lib (if pretest isn't disabled), then after installing current version of lib to dependent package. You can use $CURRENT_MODULE_DIR variable here which will be replaced with a path to current module:

[
  {
    "name": "packageA",
    "postinstall": "$CURRENT_MODULE_DIR/install-all-deps.sh",
  }
]

Pre-testing with previous package version

By default dont-break first tests dependent module with its published version of current module, to make sure that it was working before the update. If this sounds excessive to you you can disable it with {"pretest": false} option:

[
  {
    "name": "foo-module-name",
    "test": "grunt test",
    "pretest": false
  }
]

Here "foo-module-name" module will be tested only once, and "bar-name" twise: first with its published version of current module, and then with the updated version.

The "pretest" property can also accept custom script to run for pretesting:

[
  {
    "name": "foo-module-name",
    "test": "grunt test",
    "pretest": "grunt test && ./ci/after-pretesting-by-dont-break"
  }
]

By default it equals to "test" command.

Current module installation method

To test dependent package dont-break installs current module inside the dependent package directory. By default it uses npm install $CURRENT_MODULE_DIR. You can enter your command there, e.g. yarn add $CURRENT_MODULE_DIR. There are also pre-configured options npm-link and yarn-link. They can be helpful in some cases, e.g. if you need to use npm install or yarn in postinstall command. To use npm link method specify {"currentModuleInstall": "npm-link"}:

{
  "currentModuleInstall": "npm-link",
  "projects": ["packageA", "packageB"]
}

Env vars exported to called scripts

Following env vars are available for use in scripts called by executed steps:

  • $CURRENT_MODULE_DIR - directory of current module
  • $CURRENT_MODULE_NAME - name of current module as stated in its package.json

Installation timeout

You can specify a longer installation time out, in seconds, using CLI option

dont-break --timeout 30

Related

dont-break is the opposite of next-update that one can use to safely upgrade dependencies.

Setting up second CI for dont-break

I prefer to use a separate CI service specifically to test the current code against the dependent projects using dont-break. For example, the project boggle is setup this way. The unit tests are run on TravisCI using pretty standard .travis.yml file

language: node_js
node_js:
  - "0.12"
  - "4"
branches:
  only:
    - master
before_script:
  - npm install -g grunt-cli

Then I setup a separate build service on CircleCi just to run the npm run dont-break command from the package.json

"scripts": {
    "dont-break": "dont-break --timeout 30"
}

We are assuming a global installation of dont-break, and the project lists the projects to check in the .dont-break file. At the present there is only a single dependent project boggle-connect.

To run dont-break on CircleCI, I created the circle.yml file. It should be clear what it does - installs dont-break, and runs the npm script command.

machine:
  node:
    version: "0.12"
dependencies:
  post:
    - npm install -g dont-break
test:
  override:
    - npm run dont-break

To make the status visible, I included the CircleCI badges in the README file.

[![Dont-break][circle-ci-image] ][circle-ci-url]
[circle-ci-image]: https://circleci.com/gh/bahmutov/boggle.svg?style=svg
[circle-ci-url]: https://circleci.com/gh/bahmutov/boggle

which produces the following:

Breaking dependencies? Dont-break using dont-break

Development and testing

This project is tested end to end using two small projects: boggle and its dependent boggle-connect.

To see open github issues, use command npm run issues

To see verbose log message, run with DEBUG=dont-break ... environment variable.

Small print

Author: Gleb Bahmutov © 2014

License: MIT - do anything with the code, but don't blame me if it does not work.

Spread the word: tweet, star on github, etc.

Support: if you find any problems with this module, email / tweet / open issue on Github

Implemented using npm-registry, lazy-ass and npm-utils.

MIT License

Copyright (c) 2014 Gleb Bahmutov

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 the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

dont-break's People

Contributors

amilajack avatar artemv avatar bahmutov avatar cristiingineru avatar denis-sokolov avatar hypercubed avatar searls avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

dont-break's Issues

Allow customization of script name.

I have a use case where I have a project that uses my module that runs basic unit tests for npm test and then a full suite for npm run test:all. I'd rather run the full suite of tests in my dont-break.

Problem when trying to test hoodie

console output with an error https://gist.github.com/anonymous/77eb308564e2bcdbeb2da3ee6ea22c02
seems something about copying - maybe @ sign?

installing dev dependencies /tmp/[email protected]/lib/node_modules/hoodie-app-tracker
  NPM install in current folder
npm WARN deprecated [email protected]: Jade has been renamed to pug, please install the latest version of pug instead of jade
npm WARN deprecated [email protected]: graceful-fs version 3 and before will fail on newer node releases. Please update to graceful-fs@^4.0.0 as soon as possible.
npm WARN deprecated [email protected]: this package has been reintegrated into npm and is now out of date with respect to npm
npm WARN deprecated @bahmutov/[email protected]: All features were merged back into original parse-github-repo-url
npm WARN deprecated [email protected]: Please update conventional-changelog to >1.0.0. If you are running the cli, use conventional-changelog-cli
npm ERR! Darwin 15.4.0
npm ERR! argv "/Users/gregor/.nvm/versions/node/v4.2.2/bin/node" "/Users/gregor/.nvm/versions/node/v4.2.2/bin/npm" "install"
npm ERR! node v4.2.2
npm ERR! npm  v3.8.6
npm ERR! path /private/tmp/[email protected]/lib/node_modules/hoodie-app-tracker/node_modules/.staging/hoodie-app-tracker-4790a197
npm ERR! code ENOENT
npm ERR! errno -2
npm ERR! syscall rename

npm ERR! enoent ENOENT: no such file or directory, rename '/private/tmp/[email protected]/lib/node_modules/hoodie-app-tracker/node_modules/.staging/hoodie-app-tracker-4790a197' -> '/private/tmp/[email protected]/lib/node_modules/hoodie-app-tracker'
npm ERR! enoent ENOENT: no such file or directory, rename '/private/tmp/[email protected]/lib/node_modules/hoodie-app-tracker/node_modules/.staging/hoodie-app-tracker-4790a197' -> '/private/tmp/[email protected]/lib/node_modules/hoodie-app-tracker'
npm ERR! enoent This is most likely not a problem with npm itself
npm ERR! enoent and is related to npm not being able to find a file.
npm ERR! enoent 

Trying to test https://github.com/hoodiehq/hoodie against https://github.com/hoodiehq/hoodie-app-tracker

Relevant tweet https://twitter.com/gr2m/status/721117553406435329

npm test seems to hang indefinitely

I was trying to see if this would work in react-bootstrap against our downstream dependent react-router-bootstrap. I added react-router-bootstrap to the .dont-break file in the root of the react-bootstrap repo and ran ./node_modules/.bin/dont-break I get the following output and it has been hanging for an hour:

➜  react-bootstrap git:(dont-break) ✗ ./node_modules/.bin/dont-break
[email protected] - Checks if the current version of your package would break dependent projects
in folder /Users/smithm/dev/react-bootstrap
testing dependents [ 'react-router-bootstrap' ]
testing react-router-bootstrap
  installing react-router-bootstrap
installed into /tmp/[email protected]
installing dev dependencies /tmp/[email protected]/lib/node_modules/react-router-bootstrap
  NPM install in current folder
restoring current directory /Users/smithm/dev/react-bootstrap
  npm test

Am I missing something?

Allow specifying the install timeout

pouchdb takes a long time to npm install due to a leveldown dependency. If any install takes more than 10 seconds, dont-break will throw an error.

I really want to use this module, because we have a huge problem in pouchdb with testing dependencies (lots of npm link and ln -s; it's ugly). But maybe there should be some way to increase the timeout?

Here's the log:

[email protected] - Checks if the current version of your package would break dependent projects
in folder /home/nolan/workspace/pouchdb-server
testing dependents
pouchdb: test-node
testing "pouchdb: test-node"
testing folder "/tmp/[email protected]"
  installing pouchdb
npm WARN peerDependencies The peer dependency bn.js@^0.15.0 included from miller-rabin will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency 
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
FAIL: Current version breaks dependents
REPORTED ERROR: install timed out for pouchdb
Error: install timed out for pouchdb
    at Promise_timeout_task [as _onTimeout] (/home/nolan/workspace/pouchdb-server/node_modules/dont-break/node_modules/q/q.js:1070:25)
    at Timer.listOnTimeout (timers.js:89:15)
restored folder /home/nolan/workspace/pouchdb-server
finishing with success? false

Empty changelog

Something is not working correctly, because the releases have empty notes (probably scopeless commits)

screen shot 2017-08-10 at 11 15 42 pm

Crashes if the module has no dependencies

Because assumes there is an object when fetching current version of dependency

var currentVersion = installedPackage.dependencies[pkg.name] ||
        installedPackage.devDependencies[pkg.name]

Dependants by Git URL

I need to add a dependant by Git URL, because the tests in it are added to .npmignore (see #15).

I have tried adding a dependant by Git URL using git+ssh syntax from package.json (git+ssh://[email protected]:example.git#master), but it tried to install git+ssh instead:

testing dependents [ 'git+ssh:' ]
testing git+ssh:
  installing git+ssh:
npm returned 1
errors:

I have tried adding a dependant by Git URL ([email protected]:example.git), but it prepended github.com:

testing dependents [ '[email protected]:example.git' ]
testing [email protected]:example.git
  installing [email protected]:example.git
npm returned 1
errors:
npm ERR! git clone [email protected]:example.com:example.git Cloning into bare repository '/home/<snip>'...

Is there any way to do it manually? Perhaps it should be considered to add one?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.