Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Composer: Stability and Semantic Versioning Demystified (Lone Star PHP 2014)

Composer: Stability and Semantic Versioning Demystified (Lone Star PHP 2014)

Understanding stability and semantic versioning makes a huge impact on daily life with Composer. Learn how to decode Composer's solver errors, get a better understanding of semantic versioning, how dependencies interact with each other when it comes to stability, and how to use Composer features like branch aliases to make things run more smoothly.

23d971deeb3975a7d28246192fbbe7b7?s=128

Beau Simensen

April 26, 2014
Tweet

Transcript

  1. Stability and Semantic Versioning Demystified Lone Star PHP April 26th,

    2014
  2. Beau Simensen @beausimensen +BeauSimensen beau.io

  3. Dragonfly Development @dflydev dflydev.com

  4. boogio.com @wearboogio reflxlabsinc.com @reflxlabs

  5. None
  6. { “name”: “acme/my-project”, “description”: “Acme’s My Project”, “license”: “MIT”, “require”:

    { “silex/silex”: “1.1.*” }, “autoload”: { “psr-4”: { “Acme\\MyProject\\”: “src” } } }
  7. $ composer install Loading composer repositories with package information Installing

    dependencies (including require-dev) - Installing psr/log (1.0.0) - Installing symfony/routing (v2.3.7) - Installing symfony/debug (v2.3.7) - Installing symfony/http-foundation (v2.3.7) - Installing symfony/event-dispatcher (v2.3.7) - Installing symfony/http-kernel (v2.3.7) - Installing pimple/pimple (v1.1.0) - Installing silex/silex (v1.1.2) Writing lock file Generating autoload files $
  8. Semantic Versioning

  9. semver.org

  10. MAJOR.MINOR.PATCH Which number do you increment and why?

  11. MAJOR.MINOR.PATCH When you break backwards compatibility

  12. MAJOR.MINOR.PATCH When you add backwards compatible features

  13. MAJOR.MINOR.PATCH When you make backwards compatible bug fixes

  14. Pre-Release Identifiers

  15. 1.0.0-alpha 1.0.0-beta.2 1.0.0-RC3

  16. Stability Pre-Release Identifiers

  17. Version Constraints

  18. Exact Version 1.0.2

  19. Ranges >=1.0,<2.0

  20. Wildcards 1.0.*

  21. Next Significant Release Tilde Operator

  22. Next Significant Release ~1.2 Minimum allowed version and only the

    last number listed can increase.
  23. Next Significant Release ~1.2 >=1.2,<2

  24. Next Significant Release ~1.2.3 >=1.2.3,<1.3

  25. Semantic Versioning lets you know what you are getting into

  26. Safe 1.3.* Only get bug fixes

  27. Reasonably Safe 1.* Get bug fixes and new features

  28. Crazy Sauce * Composer allows this, but don't. Just don't.

  29. Version Constraint Considerations

  30. –Semantic Versioning “If the dependency specifications are too tight, you

    are in danger of version lock (the inability to upgrade a package without having to release new versions of every dependent package).”
  31. Libraries should generally have more permissive constraints

  32. –Semantic Versioning “If dependencies are specified too loosely, you will

    inevitably be bitten by version promiscuity (assuming compatibility with more future versions than is reasonable).”
  33. End projects may want to have more restrictive constraints

  34. Deep Dependency Resolution

  35. { “name”: “silex/silex”, “require”: { “pimple/pimple”: “1.*” } } 1.1.0

    1.1.0 1.1.1 1.0.2 1.0.1 1.0.0 2.0.0 Silex Pimple 0.0.1
  36. { “name”: “silex/silex”, “require”: { “pimple/pimple”: “1.*” } } {

    “name”: “dflydev/doctrine-orm-service-provider”, “require”: { “pimple/pimple”: “~1.1”, “doctrine/orm”: “~2.3” } } 1.1.0 1.1.0 1.1.1 1.0.2 1.0.1 1.0.0 2.0.0 Silex Pimple 0.0.1 2.3.2 2.4.0 2.3.1 2.3.0 2.2.1 2.5.0 ORM 2.2.0 1.0.0 dflydev
  37. { “name”: “acme/myapp”, “require”: { “dflydev/doctrine-orm-service-provider”: “1.0.*”, “silex/silex”: “1.1.*”, !

    “pimple/pimple”: “~1.1.1”, “doctrine/orm”: “2.4.*” } } { “name”: “silex/silex”, “require”: { “pimple/pimple”: “1.*” } } { “name”: “dflydev/doctrine-orm-service-provider”, “require”: { “pimple/pimple”: “~1.1”, “doctrine/orm”: “~2.3” } } 1.1.0 1.1.0 1.1.1 1.0.2 1.0.1 1.0.0 2.0.0 Silex Pimple 0.0.1 2.3.2 2.4.0 2.3.1 2.3.0 2.2.1 2.5.0 ORM 2.2.0 1.0.0 dflydev 1.0.0 myapp
  38. Conflicts

  39. { "require": { "silex/silex": "1.1.*", "pimple/pimple": "2.0.*@dev" } }

  40. $ composer install Loading composer repositories with package information Installing

    dependencies (including require-dev) Your requirements could not be resolved to an installable set of packages. ! Problem 1 - silex/silex v1.1.0 requires pimple/pimple 1.* -> satisfiable by pimple/pimple[1.0.0, 1.1.x-dev, v1.0.1, v1.0.2, v1.1.0]. - silex/silex v1.1.1 requires pimple/pimple 1.* -> satisfiable by pimple/pimple[1.0.0, 1.1.x-dev, v1.0.1, v1.0.2, v1.1.0]. - silex/silex v1.1.2 requires pimple/pimple ~1.0 -> satisfiable by pimple/pimple[1.0.0, 1.1.x-dev, v1.0.1, v1.0.2, v1.1.0]. - Can only install one of: pimple/pimple[2.0.x-dev, 1.0.0]. - Can only install one of: pimple/pimple[2.0.x-dev, 1.1.x-dev]. - Can only install one of: pimple/pimple[v1.0.1, 2.0.x-dev]. - Can only install one of: pimple/pimple[v1.0.2, 2.0.x-dev]. - Can only install one of: pimple/pimple[v1.1.0, 2.0.x-dev]. - Installation request for pimple/pimple 2.0.*@dev -> satisfiable by pimple/pimple[2.0.x-dev]. - Installation request for silex/silex 1.1.* -> satisfiable by silex/silex[v1.1.0, v1.1.1, v1.1.2]. ! Potential causes: - A typo in the package name - The package is not available in a stable-enough version according to your minimum-stability setting.
  41. Versions from Tags

  42. 2.0.1 2.0.1 (2.0.*)

  43. v2.0.1 2.0.1 (2.0.*)

  44. 2.0.1-RC1 2.0.1-RC1 (2.0.*@RC)

  45. 3.4-cuddly-cat 3.4-cuddly-cat (3.4-cuddly-cat)

  46. 2.0.1g 2.0.1g (2.0.1g)

  47. Versions from Branches

  48. Branches are considered @dev stability

  49. Numbered branches are easy

  50. 2.0 2.0.x-dev (2.0.*@dev)

  51. Named branches default to their name with a dev- prefix

  52. master dev-master (dev-master)

  53. 2.0-experimental dev-2.0-experimental (2.0.*@dev won't work!)

  54. Named branches can be aliased to be semver friendly

  55. { “extra”: { “branch-alias”: { “dev-master”: “2.0.x-dev” } } }

  56. master dev-master / 2.0.x-dev (dev-master or 2.0.*@dev)

  57. Create a branch alias as soon as you start a

    new Composer package
  58. (future you and your users will thank you)

  59. Requiring non-stable versions

  60. { “require”: { “symfony/yaml”: “3.5-cat”, “silex/silex”: “1.1@dev”, “pimple/pimple”: “dev-master”, “sculpin/core”:

    “2.0.*@beta” } }
  61. { “require”: { “symfony/yaml”: “3.5-cat”, “silex/silex”: “1.1@dev”, “pimple/pimple”: “dev-master”, “sculpin/core”:

    “2.0.*@beta” } }
  62. requiring dev-master considered harmful

  63. Pretend dev-master doesn't exist

  64. Send pull requests when you find a package that offers

    dev-master without a branch alias
  65. { “name”: “acme/myapp” }

  66. { “name”: “acme/myapp”, “require”: { “naughty/id-generator”: “1.0.*” } } !

    ! { “name”: “naughty/id-generator”, “require”: { “ircmaxell/random-lib”: “dev-master” } }
  67. { “name”: “acme/myapp”, “require”: { “naughty/id-generator”: “1.0.*”, ! “ircmaxell/random-lib”: “@dev”

    } } ! ! { “name”: “naughty/id-generator”, “require”: { “ircmaxell/random-lib”: “dev-master” } }
  68. { “name”: “acme/myapp”, “require”: { “naughty/id-generator”: “1.0.*”, ! “ircmaxell/random-lib”: “dev-master”

    } } ! ! { “name”: “naughty/id-generator”, “require”: { “ircmaxell/random-lib”: “dev-master” } }
  69. { “name”: “acme/myapp”, “require”: { “naughty/id-generator”: “1.0.*”, "dflydev/hawk": "1.0.*", !

    "ircmaxell/random-lib": "dev-master" } } ! ! { “name”: “naughty/id-generator”, “require”: { “ircmaxell/random-lib”: “dev-master” } } ! ! { “name”: “dflydev/hawk”, “require”: { “ircmaxell/random-lib”: “~1.0@dev” } }
  70. { “name”: “acme/myapp”, “require”: { “naughty/id-generator”: "1.0.*”, "dflydev/hawk": "1.0.*", !

    "ircmaxell/random-lib": "dev-master" } } ! ! { “name”: “naughty/id-generator”, “require”: { “ircmaxell/random-lib”: “dev-master” } } ! ! { “name”: “dflydev/hawk”, “require”: { “ircmaxell/random-lib”: “~1.0@dev” } } 1.0.x-dev != dev-master
  71. { “name”: “acme/myapp”, “require”: { “naughty/id-generator”: “1.0.*”, "dflydev/hawk": "1.0.*", !

    "ircmaxell/random-lib": "@dev" } } ! ! { “name”: “naughty/id-generator”, “require”: { “ircmaxell/random-lib”: “~1.0@dev” } } ! ! { “name”: “dflydev/hawk”, “require”: { “ircmaxell/random-lib”: “~1.0@dev” } } Time to send a pull request!
  72. dev-master is a virus

  73. Once people start using dev-master for your package it can

    be hard to break them of that habit
  74. Send pull requests when you find a package that requires

    dev-master when a branch alias exists
  75. –Michael Dowling “I'm working on a new version of Guzzle.

    If you're using composer: stop using dev-master. Use a tagged release. Especially in production.” https://twitter.com/mtdowling/status/440901351657054208
  76. Stability

  77. Root package

  78. The root package is the package defined in the working

    composer.json
  79. A package is the root package while it is being

    developed
  80. The root package gets to control all aspects of stability

  81. Minimum stability

  82. Controlled by the root package

  83. Defaults to stable

  84. { “minimum-stability”: “alpha” }

  85. Applied to all packages for which the root package doesn't

    specify a stability
  86. Package-by-package stability

  87. Stability can be controlled on a package-by-package basis

  88. { “require”: { “silex/silex”: “~1.1@dev”, “symfony/http-foundation”: “@beta” }, “minimum-stability”: “alpha”

    }
  89. Stability solver errors are fun

  90. { "require": { "sculpin/sculpin": "2.0.*" } }

  91. $ composer install Loading composer repositories with package information Installing

    dependencies (including require-dev) Your requirements could not be resolved to an installable set of packages. ! Problem 1 - The requested package sculpin/sculpin 2.0.* could not be found. ! Potential causes: - A typo in the package name - The package is not available in a stable-enough version according to your minimum-stability setting
  92. $ composer install Loading composer repositories with package information Installing

    dependencies (including require-dev) Your requirements could not be resolved to an installable set of packages. ! Problem 1 - The requested package sculpin/sculpin 2.0.* could not be found. ! Potential causes: - A typo in the package name - The package is not available in a stable-enough version according to your minimum-stability setting
  93. { "require": { "sculpin/sculpin": "2.0.*@dev" } }

  94. { "require": { "sculpin/sculpin": "2.0.*" }, "minimum-stability": "dev" }

  95. Root package stability implications

  96. Even if your package requires a dependency @dev, users of

    your package won't get it unless they explicitly ask for it.
  97. { “name”: “silex/silex”, “require”: { “pimple/pimple”: “1.*@dev” } } Root

    Package
  98. { “name”: “silex/silex”, “require”: { “pimple/pimple”: “1.*@dev” } } {

    “name”: “dflydev/doctrine-orm-service-provider”, “require”: { “pimple/pimple”: “1.*@beta”, “silex/silex”: “1.1.*”, “doctrine/orm”: “~2.3” } } Root Package
  99. { “require”: { “dflydev/doctrine-orm-service-provider”: “1.0.*”, ! “pimple/pimple”: “1.*@alpha” } }

    { “name”: “silex/silex”, “require”: { “pimple/pimple”: “1.*@dev” } } { “name”: “dflydev/doctrine-orm-service-provider”, “require”: { “pimple/pimple”: “1.*@beta”, “silex/silex”: “1.1.*”, “doctrine/orm”: “~2.3” } } Root Package
  100. [this page intentionally left blank]

  101. Semantic Versioning lets you know what you're getting into

  102. Libraries should generally have more permissive constraints

  103. End projects may want to have more restrictive constraints

  104. Create branch aliases

  105. dev-master considered harmful

  106. #composer look for simensen and say "hi" freenode IRC

  107. Questions? @beausimensen +BeauSimensen ddd.io/lsp14-semver joind.in