Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Beau Simensen @beausimensen +BeauSimensen beau.io

Slide 3

Slide 3 text

Dragonfly Development @dflydev dflydev.com

Slide 4

Slide 4 text

boogio.com @wearboogio reflxlabsinc.com @reflxlabs

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

{ “name”: “acme/my-project”, “description”: “Acme’s My Project”, “license”: “MIT”, “require”: { “silex/silex”: “1.1.*” }, “autoload”: { “psr-4”: { “Acme\\MyProject\\”: “src” } } }

Slide 7

Slide 7 text

$ 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 $

Slide 8

Slide 8 text

Semantic Versioning

Slide 9

Slide 9 text

semver.org

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

MAJOR.MINOR.PATCH When you break backwards compatibility

Slide 12

Slide 12 text

MAJOR.MINOR.PATCH When you add backwards compatible features

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Pre-Release Identifiers

Slide 15

Slide 15 text

1.0.0-alpha 1.0.0-beta.2 1.0.0-RC3

Slide 16

Slide 16 text

Stability Pre-Release Identifiers

Slide 17

Slide 17 text

Version Constraints

Slide 18

Slide 18 text

Exact Version 1.0.2

Slide 19

Slide 19 text

Ranges >=1.0,<2.0

Slide 20

Slide 20 text

Wildcards 1.0.*

Slide 21

Slide 21 text

Next Significant Release Tilde Operator

Slide 22

Slide 22 text

Next Significant Release ~1.2 Minimum allowed version and only the last number listed can increase.

Slide 23

Slide 23 text

Next Significant Release ~1.2 >=1.2,<2

Slide 24

Slide 24 text

Next Significant Release ~1.2.3 >=1.2.3,<1.3

Slide 25

Slide 25 text

Semantic Versioning lets you know what you are getting into

Slide 26

Slide 26 text

Safe 1.3.* Only get bug fixes

Slide 27

Slide 27 text

Reasonably Safe 1.* Get bug fixes and new features

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Version Constraint Considerations

Slide 30

Slide 30 text

–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).”

Slide 31

Slide 31 text

Libraries should generally have more permissive constraints

Slide 32

Slide 32 text

–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).”

Slide 33

Slide 33 text

End projects may want to have more restrictive constraints

Slide 34

Slide 34 text

Deep Dependency Resolution

Slide 35

Slide 35 text

{ “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

Slide 36

Slide 36 text

{ “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

Slide 37

Slide 37 text

{ “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

Slide 38

Slide 38 text

Conflicts

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

$ 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.

Slide 41

Slide 41 text

Versions from Tags

Slide 42

Slide 42 text

2.0.1 2.0.1 (2.0.*)

Slide 43

Slide 43 text

v2.0.1 2.0.1 (2.0.*)

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

3.4-cuddly-cat 3.4-cuddly-cat (3.4-cuddly-cat)

Slide 46

Slide 46 text

2.0.1g 2.0.1g (2.0.1g)

Slide 47

Slide 47 text

Versions from Branches

Slide 48

Slide 48 text

Branches are considered @dev stability

Slide 49

Slide 49 text

Numbered branches are easy

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

Named branches default to their name with a dev- prefix

Slide 52

Slide 52 text

master dev-master (dev-master)

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

Named branches can be aliased to be semver friendly

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

Create a branch alias as soon as you start a new Composer package

Slide 58

Slide 58 text

(future you and your users will thank you)

Slide 59

Slide 59 text

Requiring non-stable versions

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

requiring dev-master considered harmful

Slide 63

Slide 63 text

Pretend dev-master doesn't exist

Slide 64

Slide 64 text

Send pull requests when you find a package that offers dev-master without a branch alias

Slide 65

Slide 65 text

{ “name”: “acme/myapp” }

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

{ “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” } }

Slide 70

Slide 70 text

{ “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

Slide 71

Slide 71 text

{ “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!

Slide 72

Slide 72 text

dev-master is a virus

Slide 73

Slide 73 text

Once people start using dev-master for your package it can be hard to break them of that habit

Slide 74

Slide 74 text

Send pull requests when you find a package that requires dev-master when a branch alias exists

Slide 75

Slide 75 text

–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

Slide 76

Slide 76 text

Stability

Slide 77

Slide 77 text

Root package

Slide 78

Slide 78 text

The root package is the package defined in the working composer.json

Slide 79

Slide 79 text

A package is the root package while it is being developed

Slide 80

Slide 80 text

The root package gets to control all aspects of stability

Slide 81

Slide 81 text

Minimum stability

Slide 82

Slide 82 text

Controlled by the root package

Slide 83

Slide 83 text

Defaults to stable

Slide 84

Slide 84 text

{ “minimum-stability”: “alpha” }

Slide 85

Slide 85 text

Applied to all packages for which the root package doesn't specify a stability

Slide 86

Slide 86 text

Package-by-package stability

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

Stability solver errors are fun

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

$ 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

Slide 92

Slide 92 text

$ 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

Slide 93

Slide 93 text

{ "require": { "sculpin/sculpin": "2.0.*@dev" } }

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

Root package stability implications

Slide 96

Slide 96 text

Even if your package requires a dependency @dev, users of your package won't get it unless they explicitly ask for it.

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

{ “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

Slide 99

Slide 99 text

{ “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

Slide 100

Slide 100 text

[this page intentionally left blank]

Slide 101

Slide 101 text

Semantic Versioning lets you know what you're getting into

Slide 102

Slide 102 text

Libraries should generally have more permissive constraints

Slide 103

Slide 103 text

End projects may want to have more restrictive constraints

Slide 104

Slide 104 text

Create branch aliases

Slide 105

Slide 105 text

dev-master considered harmful

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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